Содержание

Использование GPG для подписи коммитов в Git

Заметка по командам и настройке GPG для подписи в Git.

В GPG есть публичные и приватные ключи. Подписываем приватным, проверяем подпись публичным. Всё как обычно.

Также есть мастер-ключ (master-key) и дочерние (sub-key). У ключей есть набор предназначений (capabilities). В общем, похоже на PKI.

Так вот мастер ключ имеет предназначения подписи (S signing) и удостоверения других ключей (C certifying), аналог удостоверяющего центра (certificate authority). Поэтому использовать его нужно только для выпуска дочерних ключей, а хранить подальше от рабочей станции, идеально в оффлайн хранилище.

Используем команду gpg --full-generate-key, для установки расширенных опций используем флаг --expert:

cmd

$ gpg --full-generate-key --expert

gpg (GnuPG) 2.2.29-unknown; Copyright (C) 2021 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.

Выбираем только подпись и, например, ECC:

cmd

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

Выбираем тип кривой, например, Curve 25519:

cmd

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

Выбираем срок действия:

cmd

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

Указываем идентификатор (имя, почта):

cmd

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

Real name: qwerty
Email address: qwerty@example.com
Comment:
You selected this USER-ID:
    "qwerty <qwerty@example.com>"

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

Двигаем мышкой и задаём пароль:

cmd

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.

Готово:

cmd

gpg: key 1F3D4A3F59B015FC marked as ultimately trusted
gpg: revocation certificate stored as 
  '~.gnupg/openpgp-revocs.d/B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC.rev'
public and secret key created and signed.

pub   ed25519 2023-04-21 [SC]
      B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC
uid                      qwerty <qwerty@example.com>

Для генерации дочернего ключа нужно отредактировать мастер-ключ:

cmd

$ gpg --expert --edit-key B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC

gpg (GnuPG) 2.2.29-unknown; Copyright (C) 2021 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.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
sec  ed25519/1F3D4A3F59B015FC
     created: 2023-04-21  expires: never       usage: SC
     trust: ultimate      validity: ultimate
[ultimate] (1). qwerty <qwerty@example.com>

Добавляем дочерний ключ:

cmd

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? 10
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
      <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) 1y
Key expires at Sat Apr 27 18:12:39 2024 BST
Is this correct? (y/N) y

Готово:

cmd

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  ed25519/1F3D4A3F59B015FC
     created: 2023-04-21  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  ed25519/53FE09215FE59025
     created: 2023-04-21  expires: 2024-04-20  usage: S
[ultimate] (1). qwerty <qwerty@example.com>

Сохраняем:

cmd

gpg> save

Просмотр списка публичных ключей:

shell-session

$ gpg -k
---------------------------------
pub   ed25519 2023-04-21 [SC]
      B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC
uid           [ultimate] qwerty <qwerty@example.com>
sub   ed25519 2023-04-21 [S] [expires: 2024-04-20]

Или:

shell-session

$ gpg --list-keys --keyid-format long --list-options show-unusable-subkeys --with-subkey-fingerprints
---------------------------------
pub   ed25519/1F3D4A3F59B015FC 2023-04-21 [SC]
      B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC
uid                 [ultimate] qwerty <qwerty@example.com>
sub   ed25519/53FE09215FE59025 2023-04-21 [S] [expires: 2024-04-20]

Просмотр списка приватных ключей:

shell-session

$ gpg -K
---------------------------------
sec   ed25519 2023-04-21 [SC]
      B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC
uid           [ultimate] qwerty <qwerty@example.com>
ssb   ed25519 2023-04-21 [S] [expires: 2024-04-20]

Или:

shell-session

$ gpg --list-secret-keys --keyid-format long --list-options show-unusable-subkeys --with-subkey-fingerprints
---------------------------------
sec   ed25519/1F3D4A3F59B015FC 2023-04-21 [SC]
      B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC
uid                 [ultimate] qwerty <qwerty@example.com>
ssb   ed25519/53FE09215FE59025 2023-04-21 [S] [expires: 2024-04-20]

Публичные ключи экспортируются связкой — мастер вместе со всеми дочерними:

shell-session

$ gpg --output qwerty@example.com.pub.gpg --export B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC

Приватные ключи по умолчанию тоже экспортируются связкой + публичные:

shell-session

$ gpg --output qwerty@example.com.gpg --export-secret-keys B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC

Но можно эеспортировать только конкретный дочерний приватный + публичные:

shell-session

$ gpg --output qwerty@example.com.sign1.gpg --export-secret-subkey 53FE09215FE59025!

Для резервной копии добавляем опцию --export-options backup.

Для импорта единая команда:

cmd

$ gpg --import qwerty@example.com.gpg

Для резервной копии добавляем опцию --import-options restore.

Перед удалением публичного ключа нужно удалить приватный:

cmd

$ gpg --delete-secret-key 1F3D4A3F59B015FC

sec  ed25519/1F3D4A3F59B015FC 2023-04-21 qwerty <qwerty@example.com>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

Если удалять мастер-ключ, то потребует подтверждения удаления и дочерних. Удалять дочерний отказался:

cmd

gpg: deleting secret subkey failed: Not confirmed
gpg: 1F3D4A3F59B015FC: delete key failed: Not confirmed

При этом мастер удалился (# указывает на это):

shell-session

$ gpg --list-secret-keys --keyid-format long
---------------------------------
sec#  ed25519/1F3D4A3F59B015FC 2023-04-21 [SC]
      B6FAB23B1A4F62B5F279AFF21F3D4A3F59B015FC
uid                 [ultimate] qwerty <qwerty@example.com>
ssb   ed25519/53FE09215FE59025 2023-04-21 [S] [expires: 2024-04-20]

Удаление публичного ключа производится командой:

shell-session

$ gpg --delete-key 1F3D4A3F59B015FC

cmd

$ gpg --edit-key qwerty@example.com
gpg> passwd
gpg> save

Запуск агента:

shell-session

$ gpgconf --launch gpg-agent

Настройка таймаутов:

shell-session

$ echo 'max-cache-ttl 86400' > ~/.gnupg/gpg-agent.conf
$ echo 'default-cache-ttl 14400' > ~/.gnupg/gpg-agent.conf

Восстановление доверия после импорта:

cmd

$ gpg --edit-key qwerty@example.com

gpg> trust

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5

gpg> save

Распаковка ключа:

shell-session

$ gpgsplit qwerty@example.com.gpg

Включение автоматической подписи в Git:

shell-session

$ git config user.signingkey 53FE09215FE59025!
$ git config commit.gpgsign true
  1. Signing Git commits with GPG keys that use modern encryption
  2. How to create a GPG master key and subkeys
  3. Telling Git about your signing key
  4. Backup and Restore a GPG Key
  5. Is it possible to export a GPG subkey’s public component?
  6. Short OpenPGP key IDs are insecure, how to configure GnuPG to use long key IDs instead?
  7. Are exported private keys in GPG still encrypted?
  8. gpg —list-keys command outputs uid [ unknown ] after importing private key onto a clean install
  9. GPG Option Summary
  10. How do I install and use gpg-agent on Windows?
  11. GPG Agent Option Summary
  12. GPG Change Passphrase Secret Key Password Command
  13. Why is gpg –list-keys sometimes printing subkeys, sometimes not?