使用 GnuPG 进行 SSH 验证

最近感觉把 .ssh 和 .gnupg 分别存储太麻烦了,发现 GnuPG 可以进行身份验证所以试试用 GnuPG 进行 SSH 验证。 

密钥生成

因为我已经有一个密钥了,所以我要在里面添加子密钥。要修改密钥,使用 gpg --expert --edit-key KEYID。这里使用 --expert 选项是为了生成爱德华椭圆曲线加密算法的密钥。使用椭圆曲线算法加密可以得到一个比 RSA 短的多的密钥而且不失安全性。 下面用一个测试密钥演示:

goodspeed ~$ gpg --expert --edit-key EF39B3762A999896359A9E294A70B6D07BEC89A6 
gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
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.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   5  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: depth: 1  valid:   5  signed:   0  trust: 0-, 0q, 0n, 0m, 5f, 0u
gpg: next trustdb check due at 2022-11-30
sec  rsa3072/4A70B6D07BEC89A6
     created: 2022-10-27  expires: 2024-10-26  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/8C1AAC8D5983B3A2
     created: 2022-10-27  expires: 2024-10-26  usage: E   
[ultimate] (1). TEST ETST <SHDH@SDJHAJKD.CHJSDHJAK>

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? A

Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
Current allowed actions: Sign 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? 1
Please specify how long the key should be valid.
         0 = key does not expire
        = key expires in n days
      w = key expires in n weeks
      m = key expires in n months
      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  rsa3072/4A70B6D07BEC89A6
     created: 2022-10-27  expires: 2024-10-26  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/8C1AAC8D5983B3A2
     created: 2022-10-27  expires: 2024-10-26  usage: E   
ssb  ed25519/2E0EAC3D5C434CEB
     created: 2022-10-27  expires: never       usage: SA  
[ultimate] (1). TEST ETST <SHDH@SDJHAJKD.CHJSDHJAK>

gpg> save

这样你就可以添加一个有验证功能的子密钥了。当然,你也可以自己生成一个新的单独密钥:

goodspeed ~$ gpg --full-generate-key --expert
gpg (GnuPG) 2.2.40; Copyright (C) 2022 g10 Code GmbH
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
Your selection? 11

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

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

Your selection? A

Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate 
Current allowed actions: Sign Certify 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? 1
Please specify how long the key should be valid.
         0 = key does not expire
        = key expires in n days
      w = key expires in n weeks
      m = key expires in n months
      y = key expires in n years
Key is valid for? (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: SOME NAME
Email address: EMAIL@EMAIL.EMAIL
Comment: 
You selected this USER-ID:
    SOME NAME <EMAIL@EMAIL.EMAIL>

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
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.
gpg: revocation certificate stored as '/home/goodspeed/.gnupg/openpgp-revocs.d/F87A3E254DB11F99C8C31B4CFEDAB6E07642329C.rev'
public and secret key created and signed.

pub   ed25519 2022-10-27 [SCA]
      F87A3E254DB11F99C8C31B4CFEDAB6E07642329C
uid                      SOME NAME <EMAIL@EMAIL.EMAIL>

注意,我在密钥功能那里只开启了 authenticate。生成同时可以加密/签名/验证的密钥也是可以的,但我更喜欢分离开。 # 配置 Agent

在 gpg-agent 中启用 ssh 验证:

echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf

然后把密钥的指纹写入到 sshcontrol 文件:

echo BE5F809DA25FC2409D20501A1392926F87273AEC >> ~/.gnupg

告知 ssh 使用 gpg-agent:

echo 'IdentityAgent /run/user/1000/gnupg/S.gpg-agent.ssh' >> ~/.ssh/config

告知 ssh 更新密钥:

ssh-add -l

进行 SSH 连接

注意,在配置 gpg-agent 后不能使用 ssh-copy-id 来注册密钥。要得到公钥,使用命令:

goodspeed ~$ gpg --export-ssh-key 2945CED1C88E763DB6FFBCE247FFB4C9CB4F5319
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK/GBO4ODt3qGxiexUYPUHPWGuWzoeA9noneN8y0HE70 openpgp:0xC576C4CB

不出意外的话,在复制到远端后就可以通过 GnuPG 验证 SSH 了。