Началось все с того что я почитав статью Аппаратный ключ шифрования за 3$ — возможно ли это? решил запилить такую штуку. В итоге stlink приехал со второго раза. Первый потерялся в недрах почты.
После приезда я выяснил что там стоит чип cks и по второй статье залил прошивку. В системе ключ определился
[612524.102634] usb 4-5: new full-speed USB device number 26 using ohci-pci
[612524.264962] usb 4-5: New USB device found, idVendor=234b, idProduct=0000, bcdDevice= 2.00
[612524.264969] usb 4-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[612524.264973] usb 4-5: Product: Gnuk Token
[612524.264976] usb 4-5: Manufacturer: Free Software Initiative of Japan
[612524.264979] usb 4-5: SerialNumber: FSIJ-1.0.4-9A760301
Но после этого начались проблемы.
Проблема с доступом к ключу
gpg не видел ключ. Точнее видел его, но только под root. Последовало долгое изучение проблемы и гугления. В итоге выяснилось
- У меня банально нет правила для пользовательского доступа к устройству
- Доступ к карте может осуществляться более чем одним методом из gpg
Первая проблема решается через добавление файла /etc/udev/rules.d/60-gnuk.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="234b", ATTRS{idProduct}=="0000", \
ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg"
И перезагрузку udev
devadm control --reload-rules
Это больше касается тех у кого не debian. В нем и его производных этой проблемы нет, но у меня fedora. После этого ключ увиделся.
Вторая проблема может быть решена двумя способами
- Отключить сервис pcscd
- Настроить использование pcscd сервиса в gnupg
Отключить сервис можно через его удаление или же банально остановив сервис
systemctl stop pcscd
systemctl disable pcscd
Второй вариант настраиваем сервис gnupg на использование pcscd
touch ~/.gnupg/scdaemon.conf
echo -e "pcsc-driver /usr/lib64/libpcsclite.so.1\ndisable-ccid]\n" > ~/.gnupg/scdaemon.conf
В этом случае родной scdaemon из gnupg ходит в ключ через pcscd.
Отлично карта доступна можно же залить ключ как описано и вперед! А вот и нет. Ну вообще да оно работает как описано в первой статье. Но есть нюанс.
Проблема с выбором ключей на самом ключе
Формулировка конечно великолепна, но поясню суть проблемы. Авторы предыдущих статей упускают следующий момент
gpg --card-status
Reader ...........: 234B:0000:FSIJ-1.0.4-9A760301:0
Application ID ...: D276000124010200FFFE9A7603010000
Application type .: OpenPGP
Version ..........: 2.0
Manufacturer .....: unmanaged S/N range
Serial number ....: 9A760301
Name of cardholder: [не установлено]
Language prefs ...: [не установлено]
Salutation .......:
URL of public key : [не установлено]
Login data .......: [не установлено]
Signature PIN ....: требуется
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
На самом деле ключ содержит 3 ключа. Один для подписи, который как раз и грузили. Но тут есть момент. При таком вызове
$ ssh -I /usr/lib/opensc-pkcs11.so martin@remotehost
- У вас должен быть включен pcscd. Если он не включен не будет доступа к ключу.
- При этом сначала идет обращение к Authentication key. А уже потом если облом, то идет обращение к Signature key. Что приводит к двойному запросу pin. Не очень то удобно.
Но тут опять есть два пути, но оба подразумевают добавление Authentication key
- Использовать gpg-agent совместно с ssh
- Использовать pcscd как указано
Но сначала стоит решить проблему с пустым Authentication key.
Мне помогла вот эта статья
Она рассказывает кстати где взять pem2openpgp он входит в состав monkeysphere, что отдельно прекрасно в Fedora пакет дропнули в 31 версии. Ладно из 30 версии пакет завелся.
Далее надо создать нормальный pgp ключ. Например так:
$ gpg --quick-gen-key "Niibe Yutaka <gniibe@fsij.org>"
About to create a key for:
"Niibe Yutaka <gniibe@fsij.org>"
Continue? (Y/n) y
Пример честно сперт из официальной документации gnuk.
Далее сконвертировать ssh ключ и добавить его в gpg
pem2openpgp temporary_id < .ssh/my_fancy_key | gpg2 --import
gpg: key 66091F2C70AF02A9: public key "temporary_id" imported
gpg: key 66091F2C70AF02A9: secret key imported
gpg: Total number processed: 1
gpg: imported: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
А далее добавить этот ключ к ранее созданному ключу.
Для этого смотрим список ключей
gpg2 -K --with-keygrip
/home/bexelbie/.gnupg/pubring.kbx
--------------------------------
sec rsa2048 2019-03-21 [SC] [expires: 2021-03-20]
96F33EA7F4E0F7051D75FC208715AF32191DB135
Keygrip = 90E08830BC1AAD225E657AD4FBE638B3D8E50C9E
uid [ unknown] Niibe Yutaka <gniibe@fsij.org>
ssb rsa2048 2019-03-21 [E] [expires: 2021-03-20]
Keygrip = 5FA04ABEBFBC5089E50EDEB43198B4895BCA2136
sec rsa2048 2019-03-23 [C]
D4F6B35B52B96A092FB8F418A41A06197749FBA4
Keygrip = 1F824257B107D9E3371B9A4957751D78FC8BB190
uid [ unknown] temporary_id
Редактируем созданный ключ
gpg2 --expert --edit-key 96F33EA7F4E0F7051D75FC208715AF32191DB135
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
Your selection? 13
Enter the keygrip: 1F824257B107D9E3371B9A4957751D78FC8BB190
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? s
Your selection? e
Your selection? a
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
Please specify how long the key should be valid.
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
sec rsa2048/8715AF32191DB135
created: 2019-03-21 expires: 2021-03-20 usage: SC
trust: unknown validity: unknown
ssb rsa2048/150F16909B9AA603
created: 2019-03-21 expires: 2021-03-20 usage: E
ssb rsa2048/4A9EE7790817C411
created: 2019-03-23 expires: never usage: A
[ unknown] (1). Niibe Yutaka <gniibe@fsij.org>
gpg> quit
Save changes? (y/N) y
Указываем в качестве добавляемого ключа импортированный ssh ключ. При добавлении выключаем подписывание и шифрование, а аутентификацию включаем. В итоге получаем ключ содержащий наш ssh ключ как пригодный для аутентификации.
Теперь осталось совсем немного. Перенести все это в аппаратный ключ. Снова запускаем редактирование ключа
gpg2 --expert --edit-key 96F33EA7F4E0F7051D75FC208715AF32191DB135
Вызываем запись ключа
gpg> keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
Замечу, что если просто писать ssh ключ как есть то пункта 3 не будет.
После записи выбираем ключ 1
gpg> key 1
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
При этом выделится ключ используемый для шифрования. Опять выполняем
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
Как видим выбор есть только как ключ шифрования. Если он вам не нужен, то пункт можно пропустить
Ну и наконец импортированный ssh ключ. Для начала убираем выделение с ключа 1
gpg> key 1
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
Выбираем ключ 2
gpg> key 2
sec ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
*ssb ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
[ultimate] (1). NIIBE Yutaka <gniibe@fsij.org>
[ultimate] (2) NIIBE Yutaka <gniibe@debian.org>
Записываем ключ
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
Далее если вы хотите сохранить ключи только на карте делаем
gpg> save
Иначе же, просто не сохраняем изменения.
gpg> quit
Save changes? (y/N) n
Quit without saving? (y/N) y
В этом случае ключи не удалятся из локального хранилища и можно сделать бекап.
В итоге получим добавленные на ключ три ключа. И ssh ключ будет занесен не как ключ подписи, а как ключ аутентификации
Reader ...........: 234B:0000:FSIJ-1.2.0-87193059:0
Application ID ...: D276000124010200FFFE871930590000
Version ..........: 2.0
Manufacturer .....: unmanaged S/N range
Serial number ....: 87193059
Name of cardholder: Yutaka Niibe
Language prefs ...: ja
Sex ..............: male
URL of public key : http://www.gniibe.org/gniibe-20150813.asc
Login data .......: gniibe
Signature PIN ....: not forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: 249C B377 1750 745D 5CDD 323C E267 B052 364F 028D
created ....: 2015-08-12 07:10:48
Encryption key....: E228 AB42 0F73 3B1D 712D E50C 850A F040 D619 F240
created ....: 2015-08-12 07:10:48
Authentication key: E63F 31E6 F203 20B5 D796 D266 5F91 0521 FAA8 05B1
created ....: 2015-08-12 07:16:14
General key info..: pub ed25519/E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
sec> ed25519/E267B052364F028D created: 2015-08-12 expires: never
card-no: FFFE 87193059
ssb> cv25519/850AF040D619F240 created: 2015-08-12 expires: never
card-no: FFFE 87193059
ssb> ed25519/5F910521FAA805B1 created: 2015-08-12 expires: never
card-no: FFFE 87193059
Это конечно здорово, но как это все использовать? Тут есть два пути
- Использовать ключ через gpg-agent
- Использовать через pcscd
Использование ключа через gpg-agent
В этом случае gpg-agent прикидывается ssh-agent и транслирует ключи аутентификации из gpg в ssh. Плюсы в том, что он не требует на каждый вход вводить pin, ну и более логично вписывается в ssh.
Для включения режима в ~/.gnupg/gpg.conf добавляем
use-agent
Создаем файл ~/.gnupg/gpg-agent.conf следующего содержания
default-cache-ttl 600
max-cache-ttl 7200
enable-ssh-support
Это включает кеширование и поддержку ssh.
Добавляем в ~/.bashrc
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent
Если хотим попробовать запускаем те же команды в локальном shell или просто открываем новый терминал/сессию. Если все сделали хорошо то
ssh-add -l
2048 SHA256:4v+TWsgZkr509VHQyJw9vnRcDb5HmcQwcdo5kMloi/s cardno:FFFE9A760301 (RSA)
Покажет наличие ключа на карте.
Далее запускаем как обычно ssh -v куда-нибудь и увидим
debug1: Will attempt key: cardno:FFFE9A760301 RSA SHA256:4v+TWsgZkr509VHQyJw9vnRcDb5HmcQwcdo5kMloi/s agent
Это говорит что ключ запрашивается с карты. Обратите внимание что пин будет запрашиваться не постоянно, а только когда истечет кеш в gpg-agent. Но если ключ вынут и вставлен по новой то кеш сбросится и при первом входе потребуется ввести его снова.
Использование ключа через pcks#11
Тут все просто. Первое проверяем что демон pcscd запущен
systemctl status pcscd.service
● pcscd.service - PC/SC Smart Card Daemon
Loaded: loaded (/usr/lib/systemd/system/pcscd.service; indirect; vendor preset: disabled)
Active: active (running) since Wed 2020-06-17 10:30:43 +05; 3s ago
Далее делаем как и приводилось до этого
ssh -I /usr/lib/opensc-pkcs11.so martin@remotehost
PIN при этом будет запрашиваться каждый раз, но зато один раз, а не два :)
И да на fedora команда меняется на такую
ssh -I /usr/lib64/opensc-pkcs11.so martin@remotehost
С моей точки зрения первый метод все же лучше, так-как предоставляет больше удобства и карта и так изменяется из gpg. Но если планируется так же организовать вход через токен, то надо использовать прослойку через pkcs.