Consider the following program:
#include <gpgme.h> int main (int argc, char *argv[]) { gpgme_ctx_t ctx; gpgme_error_t err; const char *version = gpgme_check_version (NULL); printf("gpgme version: %s\n", version); err = gpgme_new (&ctx); if (err) { printf ("gpgme_new: %s (%d)\n", gpgme_strerror (err), err); return 1; } const char *fpr = "CD25ED96421EC550CBC581CD6572DDCA38F80155"; gpgme_key_t key; err = gpgme_get_key (ctx, fpr, &key, 0); if (err) { printf ("gpgme_get_key (%s): %s (%d)\n", fpr, gpgme_strerror (err), err); return 1; } gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK); err = gpgme_op_delete (ctx, key, 1); if (err) { printf ("gpgme_op_delete: %s (%d)\n", gpgme_strerror (err), err); return 1; } gpgme_key_unref (key); return 0; }
This tries to delete a secret key while loopback mode is enabled. Unfortunately, this program returns success, but it does not actually delete the key in question:
/tmp/tmp.QASe7zmW0e$ gpg -K /tmp/tmp.QASe7zmW0e/pubring.kbx ------------------------------- sec rsa2048 2017-09-19 [SC] [expires: 2019-09-19] CD25ED96421EC550CBC581CD6572DDCA38F80155 uid [ultimate] test@example.com ssb rsa2048 2017-09-19 [E] us@grit:/tmp/tmp.QASe7zmW0e$ ../gpgme/gpgme-test gpgme version: 1.8.0 us@grit:/tmp/tmp.QASe7zmW0e$ echo $? 0 /tmp/tmp.QASe7zmW0e$ gpg -K /tmp/tmp.QASe7zmW0e/pubring.kbx ------------------------------- sec rsa2048 2017-09-19 [SC] [expires: 2019-09-19] CD25ED96421EC550CBC581CD6572DDCA38F80155 uid [ultimate] test@example.com ssb rsa2048 2017-09-19 [E] /tmp/tmp.QASe7zmW0e$
Disabling loopback mode causes a pinentry prompt to appear and if the user presses ok, then the key is deleted.
Also, running the equivalent (?) from the command line appears to correctly fail:
$ gpg --batch --pinentry-mode=loopback --delete-secret-keys CD25ED96421EC550CBC581CD6572DDCA38F80155 gpg: deleting secret key failed: No pinentry gpg: deleting secret subkey failed: No pinentry gpg: CD25ED96421EC550CBC581CD6572DDCA38F80155: delete key failed: No pinentry /tmp/tmp.QASe7zmW0e$ echo $? 2