## Summary
When testing smartcard-based key generation with gpg --card-edit, I observed that after generating a key directly on a YubiKey (OpenPGP applet), gpgme_get_key() fails to correctly reflect the presence of the secret encryption subkey — if the same gpgme_ctx_t context is reused.
Specifically, the secret flag for the encryption subkey is false, even though the key was just generated and is present on the card.
However, if the gpgme_ctx_t context is destroyed and re-created, the encryption subkey is detected correctly as secret.
This issue is reproducible and occurred in 4 out of 5 tests.
## Environment
1. GPGME version: 1.24.2
2. GnuPG version: 2.4.7
## Reproduction Process
1. Start smartcard editing:
2. Use the generate command to create a key directly on the smartcard:
3. After successful key creation, use the following C program to query the key using `gpgme_get_key()` **without recreating the gpgme context**.
4. Observe that the encryption subkey is returned with `secret == false`.
5. Now, destroy and recreate the context, query again, and the encryption key is correctly shown as secret == true.
### Test Code
```
#include <gpgme.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void check_error(gpgme_error_t err) {
if (err) {
fprintf(stderr, "GPGME Error: %s\n", gpgme_strerror(err));
exit(1);
}
}
void print_subkey_status(gpgme_subkey_t subkey) {
printf(" Subkey: %s\n", subkey->keyid);
printf(" Expiration: %s\n", subkey->expires ? ctime(&subkey->expires) : "No expiration");
printf(" Public Key Algorithm: %d\n", subkey->pubkey_algo);
printf(" Key Length: %u\n", subkey->length);
printf(" Can Encrypt: %s\n", subkey->can_encrypt ? "Yes" : "No");
printf(" Can Sign: %s\n", subkey->can_sign ? "Yes" : "No");
printf(" Can Authenticate: %s\n", subkey->can_authenticate ? "Yes" : "No");
printf(" Expired: %s\n", subkey->expired ? "Yes" : "No");
printf(" Revoked: %s\n", subkey->revoked ? "Yes" : "No");
printf(" Disabled: %s\n", subkey->disabled ? "Yes" : "No");
printf(" Secret Key Present: %s\n", subkey->secret ? "Yes" : "No");
printf("\n");
}
int main() {
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_ctx_t ctx;
gpgme_error_t err;
// Initialize context once
err = gpgme_new(&ctx);
check_error(err);
gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
char input[256];
while (1) {
printf("Enter Key ID or Fingerprint (or 'exit' to quit): ");
if (!fgets(input, sizeof(input), stdin)) {
break;
}
input[strcspn(input, "\n")] = 0;
if (strcmp(input, "exit") == 0) {
break;
}
gpgme_key_t key;
err = gpgme_get_key(ctx, input, &key, 1);
if (err) {
fprintf(stderr, "Failed to get key: %s\n", gpgme_strerror(err));
continue;
}
printf("Primary Key: %s\n", key->subkeys->keyid);
printf("Fingerprint: %s\n", key->subkeys->fpr);
printf("Subkey List:\n");
gpgme_subkey_t subkey = key->subkeys;
while (subkey) {
print_subkey_status(subkey);
subkey = subkey->next;
}
gpgme_key_release(key);
}
gpgme_release(ctx);
printf("Exiting.\n");
return 0;
}
```
### Test Procedure
``` shell
gpg/card> list
XXXXXX
XXXXXX
XXXXXX
gpg/card> generate
Sicherung des Verschlüsselungsschlüssel außerhalb der Karte erstellen? (J/n) J
gpg: Hinweis: Auf der Karte sind bereits Schlüssel gespeichert!
Vorhandene Schlüssel ersetzen? (j/N) j
Bitte wählen Sie, wie lange der Schlüssel gültig bleiben soll.
0 = Schlüssel verfällt nie
<n> = Schlüssel verfällt nach n Tagen
<n>w = Schlüssel verfällt nach n Wochen
<n>m = Schlüssel verfällt nach n Monaten
<n>y = Schlüssel verfällt nach n Jahren
Wie lange bleibt der Schlüssel gültig? (0) 0
Schlüssel verfällt nie
Ist dies richtig? (j/N) j
GnuPG erstellt eine User-ID, um Ihren Schlüssel identifizierbar zu machen.
Ihr Name ("Vorname Nachname"): eric
Email-Adresse: eric@bktus.com
Kommentar:
Sie haben diese User-ID gewählt:
"eric <eric@bktus.com>"
Ändern: (N)ame, (K)ommentar, (E)-Mail oder (F)ertig/(A)bbrechen? F
Wir müssen eine ganze Menge Zufallswerte erzeugen. Sie können dies
unterstützen, indem Sie z.B. in einem anderen Fenster/Konsole irgendetwas
tippen, die Maus verwenden oder irgendwelche anderen Programme benutzen.
gpg: Hinweis: Sicherung des Kartenschlüssels wurde auf `/Users/erich/.gnupg/sk_46XXXXXXXXX6FC.gpg' gespeichert
gpg: Widerrufzertifikat wurde als '/Users/erich/.gnupg/openpgp-revocs.d/124527XXXXXXXXXXX571F9B8D.rev' gespeichert.
Öffentlichen und geheimen Schlüssel erzeugt und signiert.
pub brainpoolP256r1 2025-04-21 [SC]
12452724D065162457908D7CF17AE2C5571F9B8D
uid eric <eric@bktus.com>
sub brainpoolP256r1 2025-04-21 [A]
sub brainpoolP256r1 2025-04-21 [E]
gpg/card>
``
### GPGME Output (reused context)
```shell
Enter Key ID or Fingerprint (or 'exit' to quit): 12452724D065162457908D7CF17AE2C5571F9B8D
Primary Key: F17AE2C5571F9B8D
Fingerprint: 12452724D065162457908D7CF17AE2C5571F9B8D
Subkey List:
Subkey: F17AE2C5571F9B8D
Expiration: No expiration
Public Key Algorithm: 301
Key Length: 256
Can Encrypt: No
Can Sign: Yes
Can Authenticate: No
Expired: No
Revoked: No
Disabled: No
Secret Key Present: Yes
Subkey: 53A764C774EAE8C4
Expiration: No expiration
Public Key Algorithm: 301
Key Length: 256
Can Encrypt: No
Can Sign: No
Can Authenticate: Yes
Expired: No
Revoked: No
Disabled: No
Secret Key Present: Yes
Subkey: 46643F012EAA06FC
Expiration: No expiration
Public Key Algorithm: 302
Key Length: 256
Can Encrypt: Yes
Can Sign: No
Can Authenticate: No
Expired: No
Revoked: No
Disabled: No
->**Secret Key Present: No** <-
```
## Expected Behavior
All three subkeys should report `secret == true` after generation, regardless of whether the context is reused.