Using gpgme_op_encrypt() with GPGME_ENCRYPT_CHG_RECP or GPGME_ENCRYPT_ADD_RECP, no error code is returned, in case no suitable secret key is available.
This diff demonstrates the problem based on tests/gpg/t-encrypt (to be split into a separate testcase, but the diff is smaller like this):
diff --git a/tests/gpg/t-encrypt.c b/tests/gpg/t-encrypt.c index 76d9e397..69610335 100644 --- a/tests/gpg/t-encrypt.c +++ b/tests/gpg/t-encrypt.c @@ -76,10 +76,43 @@ main (int argc, char *argv[]) } print_data (out); + // Reencrypt, swapping out the first key for a different one + gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK); + gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL); + gpgme_key_unref (key[0]); + err = gpgme_get_key (ctx, "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", + &key[0], 0); + fail_if_err (err); + gpgme_data_t out2; + err = gpgme_data_new (&out2); + fail_if_err (err); + gpgme_data_seek (out, 0, SEEK_SET); + err = gpgme_op_encrypt (ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST | GPGME_ENCRYPT_CHG_RECP, out, out2); + fail_if_err (err); + fprintf (stderr, "\nReencrypted:\n"); + print_data (out2); + + // Try to reencrypt once more. We no longer have a secret key, so this should fail: + gpgme_key_unref (key[0]); + err = gpgme_get_key (ctx, "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", + &key[0], 0); + gpgme_data_t out3; + err = gpgme_data_new (&out3); + fail_if_err (err); + gpgme_data_seek (out2, 0, SEEK_SET); + err = gpgme_op_encrypt (ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST | GPGME_ENCRYPT_CHG_RECP, out2, out3); + if (!err) { + fprintf (stderr, "\nThis should have failed but did not. (Empty) result data below:\n"); + print_data (out3); + exit (1); + } + gpgme_key_unref (key[0]); gpgme_key_unref (key[1]); gpgme_data_release (in); gpgme_data_release (out); + gpgme_data_release (out2); + gpgme_data_release (out3); gpgme_release (ctx); return 0; }