Началось все с того что я почитав статью Аппаратный ключ шифрования за 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.
