Skip to main content

GPG::SSH; notes for current best practices

When I start at a new company, I always do a refresher on my key security.

One thing I always hate about SSH is that the encryption scheme is pretty basic actually, and once your ssh-agent is loaded- anything can just request a sign/authorize.

So, in tried and true “over engineering” fashion, I’ve taken to using my GPG key as my ssh key instead, and using gpg-agent instead of ssh-agent.

Another thing is to use elliptic curves instead of RSA, RSA is still secure, but ECC (ECDSA) is faster and theoretically more resistant, and everything from 2016 onwards supports it, so it’s fair to assume it is supported in my SSH programs of choice. :)

First, to create a ECDSA key we have to use expert mode with the --full-gen-key:

jan.harasym@sm-mbp-jmh ~ % gpg2 --full-gen-key --expert
gpg (GnuPG/MacGPG2) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card

We want to use ECC and ECC here, or “ECC (set your own capabilities)” and skip to the addkey section.

Your selection? 9

Next we choose our ciphers:

Please select which elliptic curve you want:
   (1) Curve 25519
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1

NIST P-521 is the strongest, but NIST P-256 will be more compatible.

Your selection? 5

And finally expiry and user-info.

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0

Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Jan Martin Harasym
Email address: jmh@xxx.com
Comment: Expert Online Infrastructure Engineer :: Live Operations
You selected this USER-ID:
    "Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
<...>

pub   nistp521 2020-08-16 [SC]
      6F1AA563C75BA41387FDDAD7DE3F72240989604A
uid                      Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>
sub   nistp521 2020-08-16 [E]

Now we need to add a key which can be used for authorization, for this we can create a subkey, remove the encryption capability and enable the authorization one. (Failing this, we can ask for setting our own capabilities during the initial key creation above)

Make sure it’s ECC (set your own capabilities) when selecting a key type.

jan.harasym@sm-mbp-jmh ~ % gpg2 --expert --edit-key 6F1AA563C75BA41387FDDAD7DE3F72240989604A

Secret key is available.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
sec  nistp521/DE3F72240989604A
     created: 2020-08-16  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  nistp521/697423BAAFF6B653
     created: 2020-08-16  expires: never       usage: E   
[ultimate] (1). Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>

gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 11

Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
Current allowed actions: Sign 

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
Current allowed actions: 

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A

Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
Current allowed actions: Authenticate 

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? q
Please select which elliptic curve you want:
   (1) Curve 25519
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
Your selection? 5
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  nistp521/DE3F72240989604A
     created: 2020-08-16  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  nistp521/697423BAAFF6B653
     created: 2020-08-16  expires: never       usage: E   
ssb  nistp521/5A4C21BF1FC787DB
     created: 2020-08-16  expires: never       usage: A   
[ultimate] (1). Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>

gpg> Save changes? (y/N) y

Tell gpg-agent to enable ssh support:

echo > ~/.gnupg/gpg-agent <<EOF
default-cache-ttl 600
max-cache-ttl 7200
enable-ssh-support
write-env-file ~/.gpg-agent-info
EOF

And finally we need to tell the gpg-agent which key we want to load, however this is done by using the ‘keygrip’, not the ‘keyID’, you can get the keygrip with the following:

jan.harasym@sm-mbp-jmh ~ % gpg -K --with-keygrip
/Users/jan.harasym/.gnupg/pubring.kbx
-------------------------------------
sec   nistp521 2020-08-16 [SC]
      6F1AA563C75BA41387FDDAD7DE3F72240989604A
      Keygrip = 1114A87C954A99D1BE2BBBCEFD2FEF4A8F81A17B
uid           [ultimate] Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>
uid           [ultimate] [jpeg image of size 8037]
ssb   nistp521 2020-08-16 [E]
      Keygrip = 8E504AC5A41C7C71905604E83B2F150B562ADFAE
ssb   nistp521 2020-08-16 [A]
      Keygrip = 1DB1E97B20FD54DF2BAB906EA64C30081DEA8C32

Look for the keygrip which is associated with the [A] capability in my case:

ssb   nistp521 2020-08-16 [A]
      Keygrip = 1DB1E97B20FD54DF2BAB906EA64C30081DEA8C32

And enable the “A” key by adding it to the bottom of the sshcontrol file:

echo '1DB1E97B20FD54DF2BAB906EA64C30081DEA8C32' > ~/.gnupg/sshcontrol

EDIT:

AWS does not like strong keys, so for AWS I did the same as above but when I added a key for authorization I chose RSA:4096 instead.

jan.harasym@sm-mbp-jmh / % gpg2 --expert --edit-key 6F1AA563C75BA41387FDDAD7DE3F72240989604A
gpg (GnuPG/MacGPG2) 2.2.20; Copyright (C) 2020 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  nistp521/DE3F72240989604A
     created: 2020-08-16  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  nistp521/697423BAAFF6B653
     created: 2020-08-16  expires: never       usage: E   
ssb  nistp521/5A4C21BF1FC787DB
     created: 2020-08-16  expires: never       usage: A   
[ultimate] (1). Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>
[ultimate] (2)  [jpeg image of size 8037]

gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 8

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Sign Encrypt 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Sign Encrypt Authenticate 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Encrypt Authenticate 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? E

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Authenticate 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  nistp521/DE3F72240989604A
     created: 2020-08-16  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  nistp521/697423BAAFF6B653
     created: 2020-08-16  expires: never       usage: E   
ssb  nistp521/5A4C21BF1FC787DB
     created: 2020-08-16  expires: never       usage: A   
ssb  rsa4096/7085DF63EBE406FD
     created: 2020-08-20  expires: never       usage: A   
[ultimate] (1). Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>
[ultimate] (2)  [jpeg image of size 8037]

gpg> save
jan.harasym@sm-mbp-jmh / % gpg -K --with-keygrip
/Users/jan.harasym/.gnupg/pubring.kbx
-------------------------------------
sec   nistp521 2020-08-16 [SC]
      6F1AA563C75BA41387FDDAD7DE3F72240989604A
      Keygrip = 1114A87C954A99D1BE2BBBCEFD2FEF4A8F81A17B
uid           [ultimate] Jan Martin Harasym (Expert Online Infrastructure Engineer :: Live Operations) <jmh@xxx.com>
uid           [ultimate] [jpeg image of size 8037]
ssb   nistp521 2020-08-16 [E]
      Keygrip = 8E504AC5A41C7C71905604E83B2F150B562ADFAE
ssb   nistp521 2020-08-16 [A]
      Keygrip = 1DB1E97B20FD54DF2BAB906EA64C30081DEA8C32
ssb   rsa4096 2020-08-20 [A]
      Keygrip = 933F367496118EF7CB6C457C48011DD859AA215A

jan.harasym@sm-mbp-jmh / % echo "933F367496118EF7CB6C457C48011DD859AA215A" >> ~/.gnupg/sshcontrol

sources: https://www.gnupg.org/faq/whats-new-in-2.1.html#ecc https://gregrs-uk.github.io/2018-08-06/gpg-key-ssh-mac-debian/ https://www.linode.com/docs/security/authentication/gpg-key-for-ssh-authentication/