Използвам YubiKey като ключ за двуфакторна автентикация и за подписване на Git комитите си. До преди няколко дни използвах YubiKey 4. Тъй като текущият ми компютър няма никакви USB-A портове, последната година мъкнех из раницата си USB-A към USB-C адаптери и използването на ключа беше пълна мъка. Затова реших, че е време да мина на „новия“ си YubiKey 5C и да не жонглирам повече с тези адаптери.

Всъщност ключът си стои у мен от доста време – поръчах го заедно със заместващ YubiKey 4, който получих заради проблема с Infineon TPM, който са открили, но чак сега реших, че е време да премина на новия ключ.

Другата причина да го направя точно сега е, че старите ми GPG ключове изтекоха и трябваше да ги издам наново, така че мога да използвам ключа за подписване на Git комитите си.

GPG лудницата

Ако си се занимавал с GPG ключове в миналото (или се занимаваш в момента), знаеш, че може да е доста трудно да го накараш да работи както трябва и безопасно, ако никога не си го правил. Пазене на главните ключове офлайн, местене на публични ключове, преиздаване на ключове след изтичането им, евентуално подписването им с предишни ключове за верификация, отнемане на ключове… Не е лесно да следваш най-добрите практики дори на теория. Когато стане дума за практиката, нещата стават изключително сложни.

Повечето уроци в мрежата препоръчват да използваш командния ред за генериране на ключовете, да навигираш из менюта с необичаен дизайн и общо взето е болка да ги накараш да заработят. Повечето казват да използваш офлайн машина, например Raspberry PI, и/или да генерираш главните ключове и подключовете офлайн и да държиш главния ключ далеч от компютъра си.

🤯

Занимавам се с това всеки януари вече почти 4 години. Страхувам се от момента, в който получа следната грешка, която ми показва, че подписващите ми ключове са изтекли.

error: gpg failed to sign the data
fatal: failed to write commit object

Тази година реших, че е време да направя процеса много по-лесен и да използвам вграденото генериране на сертификати, за да избегна цялата тази каша с генерирането на GPG ключове и подобни.

Генериране на ключове директно върху YubiKey

Пак ще трябва да ползваме интерфейса в командния ред, но е малко по-ясен, защото има по-малко стъпки.

Първо трябва да настроим картата/устройството.

Настройка на картата/устройството

Изпълни gpg --card-status в терминала и трябва да видиш нещо такова:

Reader ………..: Yubico Yubikey 4 OTP U2F CCID
Application ID …: <Serial number>
Version ……….: 2.1
Manufacturer …..: Yubico
Serial number ….: <Device serial number>
Name of cardholder: unspecified
Language prefs …: en
Sex …………..: unspecified
URL of public key : \[not set\]
Login data …….: <e-mail or nothing>
Signature PIN ….: not forced
Key attributes …: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 9

Ако виждаш нещо подобно и няма грешки, можеш спокойно да продължиш.

Изпълни gpg --card-edit

Ще се озовеш в интерфейс в командния ред, който показва същата информация в началото, а най-отдолу има команден промпт gpg/card>.

Напиши admin и натисни Enter.

Сега можеш да напишеш help, за да разбереш как да промениш информацията за собственика и PIN кодовете на картата.

Нещо, което ЗАДЪЛЖИТЕЛНО трябва да направиш, е да смениш PIN кодовете по подразбиране на картата. Те са два. Първият е PIN кодът, с който достъпваш ключовете на картата. Вторият е „Admin“ PIN или PUK (Personal Unblocking Code).

За целта напиши passwd и ще видиш меню:

gpg/card> passwd  
gpg: OpenPGP card no. <Serial number> detected

1 - change PIN  
2 - unblock PIN  
3 - change Admin PIN  
4 - set the Reset Code  
Q - quit

Напиши 1 и следвай указанията, за да смениш PIN кода. PIN кодът по подразбиране е 123456.

След като приключиш с това, избери 3, за да смениш Admin PIN. По подразбиране е 12345678.

След като смениш и двата кода, върни се в главното меню, за да довършиш обновяването на информацията за ключа.

Командите, които можеш да използваш, са:

  • name – за смяна на името на собственика на картата
  • login – за смяна на имейл адреса или логина на собственика на картата

След това можем да преминем към същинското генериране на ключове.

Генериране на ключове

Сега е време наистина да генерираме ключовете.

За целта напиши generate.

Ще бъдеш попитан Make off-card backup of encryption key? (Y/n), но както се споменава в документацията на YubiKey, това е само бекъп „на парче“ и няма да създаде пълен бекъп на тайните ключове, така че няма значение дали ще отговориш Yes, или No. Аз отговарям с No(n).

Ако на картата вече има запазени ключове, ще бъдеш попитан дали искаш да ги замениш:

gpg: Note: keys are already stored on the card!

Replace existing keys? (y/N)

Увери се, че няма да заменяш нещо важно, от което нямаш бекъп, и продължи с Y. Ако има нещо важно, по-добре прекъсни целия процес с Ctrl+C.

Ще бъдеш попитан за PIN кода на картата, който зададе по-рано.

После трябва да избереш за колко време ще са валидни ключовете:

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)

Ако искаш ключовете да са валидни само 1 година, напиши 1y.

Ще бъдеш помолен да потвърдиш датата на изтичане. Провери дали всичко е правилно и потвърди.

След това ще трябва да въведеш информация за собственика на ключа:

Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: <Your name>
Email address: <Your e-mail>
Comment: <Comment is optional>
 You selected this USER-ID:
     "<Your name> <comment> <your e-mail>
 Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?

Type `O` to confirm if everything seems correct.

След това ще бъдеш попитан за Admin PIN или PUK. Това е необходимо, защото ще се извърши запис върху картата.

После, ако всичко е наред, YubiKey ще започне да мига и ще продължи да го прави известно време (при мен отнема към пет минути).

Когато приключи, ще видиш следното съобщение:

gpg: key <Short ID> marked as ultimately trusted
gpg: revocation certificate stored as '/Users/bisko/.gnupg/openpgp-revocs.d/<LONG ID>.rev' public and secret key created and signed.

Запиши си <Short ID>, защото ще ни трябва по-късно.

В този момент можеш да излезеш от GPG промпта с quit или Ctrl+C.

Сега е време да запазим публичния ключ, за да можем да го използваме на друг компютър.

За целта изпълни следната команда:

gpg --armor --export <Short ID> > <Short ID>.asc

Това ще експортира публичния ключ във файл с име <Short ID>.asc. Той ще ти трябва в бъдеще, ако искаш да използваш YubiKey на друг компютър или ако изгубиш GPG конфигурацията си.

За да възстановиш публичния ключ във връзката си с ключове (keyring), направи следното:

gpg --import < <Short ID>.asc
gpg: key <Short ID>: public key "Your Name <your@email>" imported
gpg: Total number processed: 1
gpg: imported: 1

Много важна забележка. Ако това е нова инсталация на GPG или друг компютър, GPG няма сам да разпознае ключовете на картата. Трябва да изпълниш gpg --card-status, за да може да прочете картата и да засече ключовете върху нея.

Настройка на Git за подписване

За да настроиш Git да подписва комитите ти, трябва да добавиш следното в ~/.gitconfig.

В секцията [user] трябва да добавиш (или обновиш) следния ред:

signingkey = 0x<Short ID>

После, ако искаш да подписваш всичките си комити, добави следното в края на файла:

[gpg]
  program = /usr/local/bin/gpg
[commit]
  gpgsign = true

Така Git ще подписва всички твои комити.

За да настроиш GitHub, трябва да добавиш публичния си ключ към профила си. За целта отиди на GitHub -> Settings -> SSH and GPG keys -> New GPG key.

Ще видиш текстово поле, в което трябва да поставиш цялото съдържание на файла <Short ID>.asc, който генерирахме по-горе.

Ако искаш да копираш съдържанието на файла (на macOS), можеш да направиш така:

cat <Short ID>.asc | pbcopy

Това ще копира съдържанието на целия файл в клипборда.

Постави го в текстовото поле в GitHub и натисни бутона Add GPG key.

След това можеш да пробваш да направиш комит и push към GitHub и трябва да видиш симпатичния етикет Verified.

Дебъгване

Понякога нещата не работят от раз. За да съберем повече информация, можем да опитаме следното:

Подписване с GPG

Първо опитай да подпишеш нещо с ключа:

gpg -s <file>

Ако това не успее, опитай да разбереш защо, аз не съм експерт, за да помогна с това.

Погледни изхода на GitGIT_TRACE=1 git commit -am “test”

Това ще ти покаже точно какво прави Git, докато се опитва да направи комита и да го подпише. Ще ти даде насока защо подписването може да се проваля.

От него можеш да видиш и че Git изпълнява следната команда:

/usr/local/bin/gpg --status-fd=2 -bsau <Key ID>

Можеш да опиташ да я изпълниш ръчно, за да видиш дали ще ти даде по-добра грешка.