From 5a369a8f31bb4b3bb05b38149fb349a1cda99e5c Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Wed, 19 Aug 2020 03:06:06 +0000 Subject: [PATCH] epass2003: Fix erase sequence. The previous erase sequence did not always work. For example: % pkcs15-init -C Using reader with a card: Feitian ePass2003 00 00 New User PIN. Please enter User PIN: 1234 Please type again to verify: 1234 Unblock Code for New User PIN (Optional - press return for no PIN). Please enter User unblocking PIN (PUK): Failed to create PKCS #15 meta structure: Security status not satisfied % pkcs15-init -E Using reader with a card: Feitian ePass2003 00 00 Failed to erase card: Security status not satisfied This apparently bricked many people's ePass2003 devices: https://github.com/OpenSC/OpenSC/issues/767 https://sourceforge.net/p/opensc/mailman/message/33621883/ https://github.com/OpenSC/OpenSC/wiki/Feitian-ePass2003 Feitian provided a proprietary binary blob called `FIX_TOOL' to recover devices from this state, but declined to offer source code when asked: https://download.ftsafe.com/files/ePass/Fix_Tool.tar.gz https://download.ftsafe.com/files/reader/SDK/Fix_Tool_20200604.zip With reverse-engineering help by Saleem Rashid (@saleemrashid on Github), I was able to find the sequence of three APDUs that the tool submits to the device to erase it. The mechanism seems to be: 1. Install a magic PIN. This is like install_secret_key, as used by internal_install_pin, but with a few different magic constants. 2. Verify the magic PIN. 3. Delete the MF file, without selecting anything first. With this patch, `pkcs15-init -E' successfully erases my ePass2003, and I am able to initialize it with `pkcs15-init -C -p pkcs15+onepin' if I set both a user pin and a PUK. (This patch does not prevent the ePass2003 from getting into the state which could not be erased by the old erase sequence.) --- src/libopensc/card-epass2003.c | 38 +++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/libopensc/card-epass2003.c b/src/libopensc/card-epass2003.c index 74c557ef..42d9df2f 100644 --- a/src/libopensc/card-epass2003.c +++ b/src/libopensc/card-epass2003.c @@ -2518,12 +2518,48 @@ epass2003_gen_key(struct sc_card *card, sc_epass2003_gen_key_data * data) static int epass2003_erase_card(struct sc_card *card) { + static const unsigned char install_magic_pin[26] = { + /* compare install_secret_key */ + 0x06,0x01,0x10,0x16, 0x16,0x16,0x00,0x0f, 0xff,0x66, + 0x31,0x32,0x33,0x34, 0x35,0x36,0x37,0x38, + 0x31,0x32,0x33,0x34, 0x35,0x36,0x37,0x38, + }; + static const unsigned char magic_pin[16] = "1234567812345678"; + static const unsigned char mf_path[2] = { 0x3f, 0x00 }; + sc_apdu_t apdu; int r; LOG_FUNC_CALLED(card->ctx); sc_invalidate_cache(card); - r = sc_delete_file(card, sc_get_mf_path()); + /* install magic pin */ + sc_format_apdu(card, &apdu, 0x03, 0xe3, 0x00, 0x00); + apdu.cla = 0x80; + apdu.data = install_magic_pin; + apdu.datalen = apdu.lc = sizeof(install_magic_pin); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU install magic pin failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "install magic pin failed"); + + /* verify magic pin */ + sc_format_apdu(card, &apdu, 0x03, 0x20, 0x00, 0x01); + apdu.cla = 0; + apdu.data = magic_pin; + apdu.datalen = apdu.lc = sizeof(magic_pin); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU verify magic pin failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(card->ctx, r, "verify magic pin failed"); + + /* delete MF */ + sc_format_apdu(card, &apdu, 0x03, 0xe4, 0x00, 0x00); + apdu.cla = 0; + apdu.data = mf_path; + apdu.datalen = apdu.lc = sizeof(mf_path); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU delete MF failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "delete MF failed"); LOG_FUNC_RETURN(card->ctx, r);