Подробный гайд по программной блокировке Рутокенов в Linux - Часть 1
Коротко
1. Стандартный PKCS#11 не умеет программно «извлекать», выключать или блокировать USB-токен.
В PKCS#11 есть операции с сессиями, объектами, PIN и т.п., но нет стандартной функции вроде C_EjectToken() или C_DisableSlot(). Если такая возможность и существует, то только в проприетарном расширении Aktiv/Рутокен.
2. Стандартного способа получить из PKCS#11 соответствие «слот → USB-устройство» нет.
CK_SLOT_ID, slotDescription, CK_TOKEN_INFO не обязаны содержать путь в /sys, busnum, devnum или порт USB.
3. Если USB-дескриптор iSerial у всех Рутокенов одинаковый, например Aktiv_Rutoken_ECP, то udev не может различить токены по этому полю. В этом случае различить их можно только:
- по уникальному внутреннему серийному номеру токена через PKCS#11/SDK;
- по физическому порту/пути в дереве USB;
- временным отключением конкретного USB-устройства и наблюдением, какой токен исчез из PKCS#11.
4. Наиболее универсальный и практичный способ для нескольких одновременно подключенных токенов — поочередно временно деавторизовать USB-устройства через /sys/.../authorized и смотреть, какой серийный номер токена исчез из PKCS#11. Так можно установить соответствие между serialNumber токена и конкретным sysfs-путем USB-устройства.
1. Что можно и нельзя через PKCS#11
Что можно
Через PKCS#11 можно:
- получить список слотов:
C_GetSlotList(CK_TRUE, slots, &count);
- получить информацию о токене:
CK_TOKEN_INFO tokenInfo;
C_GetTokenInfo(slotID, &tokenInfo);
- прочитать
tokenInfo.serialNumber; - читать объекты токена: сертификаты, ключи, метки,
CKA_IDи т.д.; - открывать/закрывать сессии;
- выполнять криптографические операции.
Чего нельзя стандартно
В стандарте PKCS#11 нет штатного средства:
- отключить токен от шины USB;
- «вынуть» его программно;
- запретить доступ к нему другим процессам;
- получить путь
/sys/bus/usb/devices/...; - получить
busnum/devnum; - привязать
CK_SLOT_IDк физическому порту.
То есть если задача именно в том, чтобы ОС перестала видеть устройство, нужно работать уже не с PKCS#11, а с USB-подсистемой Linux.
2. Чем блокировать Рутокен в Linux
Для программного отключения USB-устройства лучше всего использовать механизм USB authorization:
/sys/bus/usb/devices/<device>/authorized
Запись 0 запрещает использование устройства, запись 1 разрешает.
Например:
echo 0 > /sys/bus/usb/devices/1-2/authorized
или через tee, если нужен sudo:
echo 0 | sudo tee /sys/bus/usb/devices/1-2/authorized
Обратно:
echo 1 | sudo tee /sys/bus/usb/devices/1-2/authorized
После этого желательно подождать завершения событий udev:
sudo udevadm settle --timeout=5
Почему лучше authorized, а не remove
Есть также:
echo 1 > /sys/bus/usb/devices/1-2/remove
но это удаляет устройство из ядра, а для возвращения обычно нужен rescan или физическое переподключение. Это более жесткий вариант.
authorized=0 обычно удобнее:
- обратимо;
- не требует физического перетыкания;
- не требует обязательного
rescan; - подходит для сценария «запретить, если токен не разрешен».
3. Как найти нужное устройство в /sys
3.1. По busnum и devnum
Если вы видите устройство, например, в lsusb:
Bus 001 Device 005: ID 0a89:00b1 Aktiv Rutoken ECP
то можно найти соответствующий каталог в /sys.
Пример функции:
find_usb_syspath_by_busdev() {
local bus="$1"
local dev="$2"
# Убираем ведущие нули, например 001 -> 1, 005 -> 5
bus=$((10#$bus))
dev=$((10#$dev))
local d
for d in /sys/bus/usb/devices/*; do
[[ -f "$d/busnum" && -f "$d/devnum" ]] || continue
if [[ "$(cat "$d/busnum")" == "$bus" && \
"$(cat "$d/devnum")" == "$dev" ]]; then
echo "$d"
return 0
fi
done
return 1
}
Пример:
find_usb_syspath_by_busdev 001 005
Может вернуть:
/sys/bus/usb/devices/1-2
3.2. Перечислить все потенциальные Рутокены
Например:
list_rutoken_usb_devices() {
local d base v p
for d in /sys/bus/usb/devices/*; do
base="${d##*/}"
# Пропускаем корневые хабы
[[ "$base" == usb* ]] && continue
# Пропускаем интерфейсы вида 1-2:1.0
[[ "$base" == *:* ]] && continue
[[ -f "$d/idVendor" && -f "$d/idProduct" ]] || continue
v=$(cat "$d/idVendor")
p=$(cat "$d/idProduct")
# Важно: замените 0a89 и набор idProduct на реальные значения ваших Рутокенов.
# idVendor у Aktiv часто 0a89, но точные значения лучше взять из:
# lsusb -v | grep -i rutoken
if [[ "$v" == "0a89" ]]; then
echo "$d"
fi
done
}
Вызов:
list_rutoken_usb_devices
Может вернуть:
/sys/bus/usb/devices/1-2
/sys/bus/usb/devices/1-3
/sys/bus/usb/devices/2-1
Важно: не блокируйте устройства вида usb1, usb2 — это корневые концентраторы. Также не нужно блокировать интерфейсы вида 1-2:1.0. Блокировать лучше само устройство, например 1-2.
4. Как получить серийный номер токена через PKCS#11
Если у вас уже настроена работа с библиотекой Рутокен через pkcs11-tool, можно использовать её.
Например:
pkcs11-tool --module /usr/lib/librtpkcs11ecp.so --list-slots
или, в зависимости от установки:
pkcs11-tool --module /usr/lib64/librtpkcs11ecp.so --list-slots
Также можно использовать:
p11-kit list-tokens --verbose
Но для автоматизации удобнее извлекать серийные номера скриптом.
Пример:
PKCS11_MODULE="/usr/lib/librtpkcs11ecp.so"
list_pkcs11_serials() {
pkcs11-tool --module "$PKCS11_MODULE" --list-slots 2>/dev/null |
sed -n 's/.*Serial Number:[[:space:]]*//p' |
sed 's/[[:space:]]*$//' |
sort -u
}
Проверка:
list_pkcs11_serials
Может вернуть что-то вроде:
1234567890ABCDEF
FEDCBA0987654321
Важно:
- серийный номер в
CK_TOKEN_INFOобычно дополнен пробелами; - его надо обрезать и нормализовать;
- не стоит привязываться к номеру слота
CK_SLOT_ID: он может меняться между перезагрузками и переподключениями.
Информация предоставлена в ознакомительных целях. Применение описанных настроек в системах, должно осуществляться только после согласования с ответственными за информационную безопасность и в соответствии с требованиями ФСТЭК, ФСБ и иных уполномоченных органов.