Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gpg --armor --export-secret-key username@email still outputs a private key #415

Closed
CocolinoFan opened this issue Jan 31, 2024 · 5 comments
Closed

Comments

@CocolinoFan
Copy link

Hello,
I have followed the guide to the letter.
gpg -K outputs:

/home/purism/.gnupg/pubring.kbx
---------------------------------------------
sec# rsa4096/0x8CCAF633B6859E80 2024-01-26 [C]
   Key fingerprint = D8E7 0DAC 2CB9 F4DE 2728 00D5 8CCA F633 B685 9E80
uid                [ultimate] Mircea Arva <arvamircea@gmail.com>
uid                [ultimate] CocolinoFan
ssb> rsa4096/0xC1B1AA5434C755A0 2024-01-26 [S] [expires: 2026-01-25]
ssb> rsa4096/0xBB39FA2D78C58B67 2024-01-26 [E] [expires: 2026-01-25]
ssb> rsa4096/0x5EF04E406E0C0E1D 2024-01-26 [A] [expires: 2026-01-25]

We can see that the main key is a sec# meaning there is only a public key and no private key.
We can also see that the subkeys are ssb> meaning that the private keys have been moved to the card.

Just to be 100% sure:

gpg --delete-secret-key 0x8CCAF633B6859E80
gpg: key "0x8CCAF633B6859E80" not found
gpg: 0x8CCAF633B6859E80: delete key failed: Not found

From an excess of caution I have tried running gpg --armor --export-secret-key arvamircea@gmail.com and well... It worked. The command outputted a private key, it did not ask me for a password or the card PIN.
How is this possible?

Inside the private-keys-v1.d directory I have three files corresponding to my 3 subkeys.
Inside those files I have: Key: (shadowed-private-key (rsa (n #00DA etc etc

Why is gpg --armor --export-secret-key 0x8CCAF633B6859E80 outputting a private key? o.O

@CocolinoFan
Copy link
Author

CocolinoFan commented Jan 31, 2024

I found issue #410 that looks very similar, but the replys wore not very satisfying.
"It exports a stub pointing to a particular Yubikey"

If it's a stub, and not the actual private key, then why is the output:

-----BEGIN PGP PRIVATE KEY BLOCK-----
very log string that looks like a private key
-----END PGP PRIVATE KEY BLOCK-----

And not, I don't know -----BEGIN PGP STUB-----

@leohidalgo
Copy link

I think a good test is:

  • export the stub/secret key
  • delete all keys
  • import
  • validate if you can create a new subkey

@CocolinoFan
Copy link
Author

I hope the "stub"s are three files in the private-keys-v1.d directory?
There is no secret keys to export, I hope. There should all be on the card.
My master private key is safe offline, it would be really cumbersome to make more subkeys at this point.

I can:

  1. Backup the private-keys-v1.d directory with the 3 files inside
  2. Delete the whole .gnupg directory
  3. Move the private-keys-v1.d directory back into a new .gnupg
  4. Import the public key from an online keyserver
  5. See if gpg --armor --export-secret-key username@email still outputs a private key

But, I have a feeling it will still output a private key.
I just want someone that knows GPG well to confirm that what ever gpg --armor --export-secret-key username@email outputs is not my private key; and to explain why is outputting says "-----BEGIN PGP PRIVATE KEY BLOCK-----", why not give an error or why not say something like "-----BEGIN PGP STUB-----".

@Paraphraser
Copy link
Contributor

I'm no security guru so please take this with several kilograms of salt.

I think of it like this.

Ignore the YubiKey for the moment. Assume you've generated a GnuPG key-pair on system A and you want to migrate everything to system B. You're going to do something like this:

  1. On system A:

    $ TARGET=mykeyidhere
    $ gpg --armor --export $TARGET >$TARGET-public.asc
    $ gpg --armor --export-secret-key $TARGET >$TARGET-secret.asc
    
  2. Copy the two files to system B.

  3. On system B:

    $ TARGET=mykeyidhere
    $ gpg --import $TARGET-public.asc
    $ gpg --import $TARGET-secret.asc
    

Assuming you set a passphrase when you generated the key-pair, you'll be prompted to enter it in the third command on each system.

Because the secret.asc contains the public key, you can actually reduce this to just the secret.asc file but I tend to think of migration as a two-file problem so I can decide, case by case, whether a system needs both the public and private keys, or only needs the public half.

If you repeat this same sequence when the private keys are stored on your YubiKey, you won't get prompted for the passphrase.

Well, perhaps I should be more precise and say that I don't get passphrase prompts on my system.

I take that to mean GnuPG's authors thought there was nothing being written to the secret.asc file that was worth protecting.

More to the point, when the private keys are stored on the YubiKey, the third command on system B produces this:

gpg: key 922198D722A7431A: 5 signatures not checked due to missing keys
gpg: key 922198D722A7431A: "Moi Nom (Paraphraser) <nobody@github.com>" not changed
gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status
gpg: key 922198D722A7431A: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1

That's a sort of "you can't get there from here" message which I take to mean that, whatever is in that secret.asc file, it isn't the private keys. Running gpg -K produces silence which seems to confirm there was nothing to import.

If I follow the instructions:

  1. Connect the YubiKey.

  2. Run:

    $ gpg --card-status
    $ gpg -K
    

then the expected ssb> pattern comes back. I still have to fix the trust but that's about it. If I try something that needs the YubiKey (eg sign a file) then I'm prompted for the PIN and have to touch the key. The overall behaviour suggests that everything came from the YubiKey rather than the secret.asc file.

Going back a step, if I do this:

$ gpg --list-packets $TARGET-secret.asc | grep -c "gnu-divert-to-card"
3

I interpret the "3" as marrying-up with the three ssb> keys.

If you run --list-packets on your own secret.asc file (without the pipe-to-grep) and nose around the output, and then compare it with what you get when a key-pair doesn't involve a YubiKey, the pattern is quite different. While I can't say for absolute certainty that there's nothing in the secret.asc to give the game away, it'd require more tools and knowledge than I have to prove it one way or the other.

Thinking about what might have been in the minds of GnuPG's authors, if I assume that the local keychain only contains stubs then what should --export-secret-key do? The options would seem to be to either produce nothing, or produce something which at least documents the fact that the private keys can't be found in the secret.asc but must be imported from the card.

All things considered, I think I'd rather get the "run --card-status" prompt telling me what to do, than silence where I have to figure it out for myself.

Does that help at all?

@CocolinoFan
Copy link
Author

It helps a lot actually, thank you sir. 🙏

Before I posted this I made some tests myself. I copied the .gnupg directory from computer A (with the PGP card) to computer B.
When trying to decrypt a file on computer B it tells me that it needs the card, good.
Is just that, on both computer A and computer B gpg --armor --export-secret-key $KEYID produced a file

-----BEGIN PGP PRIVATE KEY BLOCK-----
very log string that looks like a private key
-----END PGP PRIVATE KEY BLOCK-----

Seeing a file that claims it has a private key really scared me as I went to great lengths to make everything safe.

If you repeat this same sequence when the private keys are stored on your YubiKey, you won't get prompted for the passphrase.

Oh yes, that should have been a dead giveaway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants