~~Subkeys exported with `--export-secret-keys` will be imported successfully with `--import` but the subkeys will not actually work.~~ If GnuPG's input is provided via standard input then it fails to run versions of pinentry that require use of the terminal. I believThe error reported by GnuPG doesn't clearly indicate this is related to T3456at pinentry failed and instead it reports that the secret key is missing.
Below is a script demonstrates the issue using `--batch`, but I can reproduce it via regular, interactive GnuPG commands. The vital action needed to produce the bug, and why it's probably gone unnoticed for so long, is to fully delete the subkey from the keyring before attempting to import it. In my script I just use different homedirs. Also, I'm using Curve25519 so the example runs fasterFor pinentry-tty, but the bug isn't limited to this key type.the error message is:
Here's the scenario: Alice generates a primary key and an encryption subkey, then uses `--export-secret-keys` for safekeeping as backup. She also uses `--export` to output public keys, which she sends to Bob. Later, Bob uses the public key to encrypt a message for Alice. However, Alice has since gotten a new computer and hasn't set up GnuPG yet. To read the message, she imports the secret keys from her backups and attempts to decrypt the message. I've set up three homedirs to simulate this:```
gpg: public key decryption failed: Invalid IPC response
gpg: decryption failed: No secret key
```
1) Alice's first computerFor pinentry-curses, "keygen", where keys are generated.the error message is:
```
gpg: public key decryption failed: Inappropriate ioctl for device
2) Bob's computer, "friend", where the message is encrypted.gpg: decryption failed: No secret key
3) Alice's new computer,```
The latter is the more useful message because it reveals that pinentry-curses tried to use the input file as a terminal. Using strace shows this (ioctl on fd 0):
```
ioctl(0, TCGETS, 0x7ffc0fba08d0) = -1 ENOTTY (Inappropriate ioctl for device)
```
Below is a script demonstrates the issue using `--batch`, but I can reproduce it via regular, interactive GnuPG commands. In my script I just use different homedirs to simulate different hosts. Also, I'm using Curve25519 so the example runs faster, but the bug isn't limited to this key type.
A host named "keygen" generates a key and exports it. "import",Another host named "friend" encrypts a message. which willA third host named "import" imports the secret keys from backup and decrypts the message.
```
#!/bin/sh
set -e
gpg="gpg --quiet --homedir . --batch"
keygen="$(mktemp -d "keygen-XXXXXX")"
friend="$(mktemp -d "friend-XXXXXX")"
import="$(mktemp -d "import-XXXXXX")"
chmod 700 "$keygen" "$friend" "$import"
cleanup() {
rm -rf -- "$keygen" "$friend" "$import"
}
trap cleanup INT TERM EXIT
pass="$1"
(
cd "$keygen"
$gpg --passphrase '' --quick-generate-key x ed25519 default none
fpr="$($gpg --list-keys --with-colons | awk -F: '/^fpr/{print $10; exit}')"
$gpg --passphrase "$pass" --quick-add-key "$fpr" cv25519 default none
$gpg --list-secret-keys
$gpg --export >../public.gpg
echo $pass | $gpg --passphrase-fd 0 --pinentry-mode loopback \
--export-secret-keys >../secret.gpg
)
(
cd "$friend"
$gpg --import ../public.gpg
echo "Let's meet at midnight" \
| $gpg --trust-model always --encrypt --recipient x >../msg.gpg
)
(
cd "$import"
echo $pass | $gpg --passphrase-fd 0 --pinentry-mode loopback \
--import ../secret.gpg
$gpg --list-secret-keys
$gpg --decrypt <../msg.gpg
)
```
When the script is run without arguments, the subkey is unprotected. In this case everything works fine:
```
$ sh example.sh
keygen-UBWzBs/pubring.kbx
--------------------------------------------------------------------------------
sec ed25519 2019-08-12 [SC]
6DFDBB761EE6AED9F1303E1139FC599588A3C825
uid [ultimate] x
ssb cv25519 2019-08-12 [E]
import-hKIkzV/pubring.kbx
--------------------------------------------------------------------------------
sec ed25519 2019-08-12 [SC]
6DFDBB761EE6AED9F1303E1139FC599588A3C825
uid [ unknown] x
ssb cv25519 2019-08-12 [E]
Let's meet at midnight
```
The key listings show the generated keys, then what was later imported. But, if Alice tries to protect the subkey with a passphrase ("foo"), then the key becomes unusableWhen a passphrase is set and pinentry is configured as pinentry-tty or pinentry-curses:
```
$ sh example.sh foo
keygen-UBWzBs/pubring.kbx
--------------------------------------------------------------------------------
sec ed25519 2019-08-12 [SC]
422C5F8B9CBDF139C765B60774C46E98E616C620
uid [ultimate] x
ssb cv25519 2019-08-12 [E]
import-hKIkzV/pubring.kbx
--------------------------------------------------------------------------------
sec ed25519 2019-08-12 [SC]
422C5F8B9CBDF139C765B60774C46E98E616C620
uid [ unknown] x
ssb cv25519 2019-08-12 [E]
gpg: decryption failed: No secret key
```
If you manually import `secret.gpg` you will be prompted for the passphrase, meaning GnuPG *knows* it's there, that it's protected, and it's even decrypting it. But it's ultimately unusablet tries to prompt for the protection passphrase on the `--decrypt` line but fails.