diff --git a/g10/call-agent.c b/g10/call-agent.c index 01f59aca8..35fb615f0 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -974,8 +974,9 @@ agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, keypair_info_t *r_list) /* Send an APDU to the current card. On success the status word is - * stored at R_SW. With HEXAPDU being NULL only a RESET command is - * send to scd. HEXAPDU may also be one of these special strings: + * stored at R_SW unless R_SQ is NULL. With HEXAPDU being NULL only a + * RESET command is send to scd. HEXAPDU may also be one of theseo + * special strings: * * "undefined" :: Send the command "SCD SERIALNO undefined" * "lock" :: Send the command "SCD LOCK --wait" diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c index b56f40a1c..1f7008902 100644 --- a/tools/card-call-scd.c +++ b/tools/card-call-scd.c @@ -421,9 +421,16 @@ store_serialno (const char *line) /* Send an APDU to the current card. On success the status word is * stored at R_SW inless R_SW is NULL. With HEXAPDU being NULL only a - * RESET command is send to scd. With HEXAPDU being the string - * "undefined" the command "SERIALNO undefined" is send to scd. If - * R_DATA is not NULL the data without the status code is stored + * RESET command is send to scd. HEXAPDU may also be one of theseo + * special strings: + * + * "undefined" :: Send the command "SCD SERIALNO undefined" + * "lock" :: Send the command "SCD LOCK --wait" + * "trylock" :: Send the command "SCD LOCK" + * "unlock" :: Send the command "SCD UNLOCK" + * "reset-keep-lock" :: Send the command "SCD RESET --keep-lock" + * + * If R_DATA is not NULL the data without the status code is stored * there. Caller must release it. If OPTIONS is not NULL, this will * be passed verbatim to the SCDaemon's APDU command. */ gpg_error_t @@ -447,6 +454,26 @@ scd_apdu (const char *hexapdu, const char *options, unsigned int *r_sw, NULL, NULL, NULL, NULL, NULL, NULL); } + else if (!strcmp (hexapdu, "reset-keep-lock")) + { + err = assuan_transact (agent_ctx, "SCD RESET --keep-lock", + NULL, NULL, NULL, NULL, NULL, NULL); + } + else if (!strcmp (hexapdu, "lock")) + { + err = assuan_transact (agent_ctx, "SCD LOCK --wait", + NULL, NULL, NULL, NULL, NULL, NULL); + } + else if (!strcmp (hexapdu, "trylock")) + { + err = assuan_transact (agent_ctx, "SCD LOCK", + NULL, NULL, NULL, NULL, NULL, NULL); + } + else if (!strcmp (hexapdu, "unlock")) + { + err = assuan_transact (agent_ctx, "SCD UNLOCK", + NULL, NULL, NULL, NULL, NULL, NULL); + } else if (!strcmp (hexapdu, "undefined")) { err = assuan_transact (agent_ctx, "SCD SERIALNO undefined", diff --git a/tools/card-misc.c b/tools/card-misc.c index bbb2b4810..6466e98b2 100644 --- a/tools/card-misc.c +++ b/tools/card-misc.c @@ -92,8 +92,13 @@ send_apdu (const char *hexapdu, const char *desc, unsigned int ignore, if (err) log_error ("sending card command %s failed: %s\n", desc, gpg_strerror (err)); - else if (!hexapdu || !strcmp (hexapdu, "undefined")) - ; + else if (!hexapdu + || !strcmp (hexapdu, "undefined") + || !strcmp (hexapdu, "reset-keep-lock") + || !strcmp (hexapdu, "lock") + || !strcmp (hexapdu, "trylock") + || !strcmp (hexapdu, "unlock")) + ; /* Ignore pseudo APDUs. */ else if (ignore == 0xffff) ; /* Ignore all status words. */ else if (sw != 0x9000) diff --git a/tools/gpg-card.c b/tools/gpg-card.c index 7c30ad3aa..9898c5e31 100644 --- a/tools/gpg-card.c +++ b/tools/gpg-card.c @@ -2922,6 +2922,7 @@ cmd_factoryreset (card_info_t info) int termstate = 0; int any_apdu = 0; int is_yubikey = 0; + int locked = 0; int i; @@ -3026,7 +3027,7 @@ cmd_factoryreset (card_info_t info) if (is_yubikey) { - /* The PIV application si already selected, we only need to + /* If the PIV application is already selected, we only need to * send the special reset APDU after having blocked PIN and * PUK. Note that blocking the PUK is done using the * unblock PIN command. */ @@ -3044,9 +3045,15 @@ cmd_factoryreset (card_info_t info) else /* OpenPGP card. */ { any_apdu = 1; - /* We need to select a card application before we can send APDUs - * to the card without scdaemon doing anything on its own. */ - err = send_apdu (NULL, "RESET", 0, NULL, NULL); + /* We need to select a card application before we can send + * APDUs to the card without scdaemon doing anything on its + * own. We then lock the connection so that other tools + * (e.g. Kleopatra) don't try a new select. */ + err = send_apdu ("lock", "locking connection ", 0, NULL, NULL); + if (err) + goto leave; + locked = 1; + err = send_apdu ("reset-keep-lock", "reset", 0, NULL, NULL); if (err) goto leave; err = send_apdu ("undefined", "dummy select ", 0, NULL, NULL); @@ -3095,7 +3102,10 @@ cmd_factoryreset (card_info_t info) } /* Finally we reset the card reader once more. */ - err = send_apdu (NULL, "RESET", 0, NULL, NULL); + if (locked) + err = send_apdu ("reset-keep-lock", "reset", 0, NULL, NULL); + else + err = send_apdu (NULL, "RESET", 0, NULL, NULL); if (err) goto leave; @@ -3123,6 +3133,8 @@ cmd_factoryreset (card_info_t info) * scd serialno openpgp */ } + if (locked) + send_apdu ("unlock", "unlocking connection ", 0, NULL, NULL); xfree (answer); return err; }