From bbbedd3b358f80a7f98df2b22cf541cb007dd62e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?= Date: Mon, 4 Mar 2013 18:13:03 +0700 Subject: [PATCH 06/18] openpgp-tool: Support deleting key in Gnuk. --- src/tools/openpgp-tool.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/src/tools/openpgp-tool.c b/src/tools/openpgp-tool.c index 0d360a3..239c86b 100644 --- a/src/tools/openpgp-tool.c +++ b/src/tools/openpgp-tool.c @@ -39,6 +39,7 @@ #define OPT_PRETTY 257 #define OPT_VERIFY 258 #define OPT_PIN 259 +#define OPT_DELKEY 260 /* define structures */ struct ef_name_map { @@ -77,6 +78,7 @@ static char *verifytype = NULL; static int opt_pin = 0; static char *pin = NULL; static int opt_erase = 0; +static int opt_delkey = 0; static const char *app_name = "openpgp-tool"; @@ -96,6 +98,7 @@ static const struct option options[] = { { "erase", no_argument, NULL, 'E' }, { "verify", required_argument, NULL, OPT_VERIFY }, { "pin", required_argument, NULL, OPT_PIN }, + { "del-key", required_argument, NULL, OPT_DELKEY }, { NULL, 0, NULL, 0 } }; @@ -114,7 +117,8 @@ static const char *option_help[] = { /* V */ "Show version number", /* E */ "Erase (reset) the card", "Verify PIN (CHV1, CHV2, CHV3...)", - "PIN string" + "PIN string", + "Delete key (1, 2, 3 or all)" }; static const struct ef_name_map openpgp_data[] = { @@ -294,6 +298,14 @@ static int decode_options(int argc, char **argv) case 'E': opt_erase++; break; + case OPT_DELKEY: + opt_delkey++; + if (strcmp(optarg, "all") != 0) /* Arg string is not 'all' */ + key_id = optarg[0] - '0'; + else /* Arg string is 'all' */ + key_id = 'a'; + actions++; + break; default: util_print_usage_and_die(app_name, options, option_help, NULL); } @@ -452,6 +464,133 @@ int do_verify(sc_card_t *card, u8 *type, u8* pin) return r; } +/** + * Delete key, for Gnuk. + **/ +int delete_key_gnuk(sc_card_t *card, u8 key_id) +{ + sc_context_t *ctx = card->ctx; + int r = SC_SUCCESS; + u8 *data = NULL; + + /* Delete fingerprint */ + sc_log(ctx, "Delete fingerprints"); + r |= sc_put_data(card, 0xC6 + key_id, NULL, 0); + /* Delete creation time */ + sc_log(ctx, "Delete creation time"); + r |= sc_put_data(card, 0xCD + key_id, NULL, 0); + + /* Rewrite Extended Header List */ + sc_log(ctx, "Rewrite Extended Header List"); + + if (key_id == 1) + data = "\x4D\x02\xB6"; + else if (key_id == 2) + data = "\x4D\x02\xB8"; + else if (key_id == 3) + data = "\x4D\x02\xA4"; + else + return SC_ERROR_INVALID_ARGUMENTS; + + r |= sc_put_data(card, 0x4D, data, strlen(data) + 1); + return r; +} + +/** + * Delete key, for OpenPGP card. + * This function is not complete and is reserved for future version (> 2) of OpenPGP card. + **/ +int delete_key_openpgp(sc_card_t *card, u8 key_id) +{ + sc_context_t *ctx = card->ctx; + char *del_fingerprint = "00:DA:00:C6:14:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"; + char *del_creationtime = "00:DA:00:CD:04:00:00:00:00"; + /* We need to replace the 4th byte later */ + char *apdustring = NULL; + u8 buf[SC_MAX_APDU_BUFFER_SIZE]; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + sc_apdu_t apdu; + size_t len0; + int i; + int r = SC_SUCCESS; + + for (i = 0; i < 2; i++) { + if (i == 0) /* Reset fingerprint */ + apdustring = del_fingerprint; + else /* Reset creation time */ + apdustring = del_creationtime; + /* Convert the string to binary array */ + len0 = sizeof(buf); + sc_hex_to_bin(apdustring, buf, &len0); + + /* Replace DO tag, subject to key ID */ + buf[3] = buf[3] + key_id; + + /* Build APDU from binary array */ + r = sc_bytes2apdu(card->ctx, buf, len0, &apdu); + if (r) { + sc_log(ctx, "Failed to build APDU"); + LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL); + } + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); + + /* Send APDU to card */ + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(ctx, r, "Transmiting APDU failed"); + } + /* TODO: Rewrite Extended Header List. + * Not support by OpenGPG v2 yet */ + LOG_FUNC_RETURN(ctx, r); +} + +int delete_key(sc_card_t *card, u8 key_id) +{ + sc_context_t *ctx = card->ctx; + int r; + + LOG_FUNC_CALLED(ctx); + /* Check key ID */ + if (key_id < 1 || key_id > 3) { + sc_log(ctx, "Invalid key ID %d", key_id); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + } + + if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) + r = delete_key_gnuk(card, key_id); + else + r = delete_key_openpgp(card, key_id); + + LOG_FUNC_RETURN(ctx, r); +} + +int do_delete_key(sc_card_t *card, u8 key_id) +{ + sc_context_t *ctx = card->ctx; + int r = SC_SUCCESS; + + /* Currently, only Gnuk supports deleting keys */ + if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) { + printf("Only Gnuk supports deleting keys. General OpenPGP doesn't."); + return SC_ERROR_NOT_SUPPORTED; + } + + if (key_id < 1 || (key_id > 3 && key_id != 'a')) { + printf("Error: Invalid key id %d", key_id); + return SC_ERROR_INVALID_ARGUMENTS; + } + if (key_id == 1 || key_id == 'a') { + r |= delete_key(card, 1); + } + if (key_id == 2 || key_id == 'a') { + r |= delete_key(card, 2); + } + if (key_id == 3 || key_id == 'a') { + r |= delete_key(card, 3); + } + return r; +} + int do_erase(sc_card_t *card) { int r; @@ -539,6 +678,9 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (opt_delkey) + exit_status != do_delete_key(card, key_id); + if (opt_erase) exit_status != do_erase(card); -- 1.9.3