Токены PKCS#11: генерация ключевой пары и неизвлекаемость приватного ключа (Продолжение)

    imageВ предыдущей статье «Токены PKCS#11: сертификаты и закрытые ключи» мы рассмотрели как можно однозначно связать тройку Сертификат x ПубличныйКлюч x ПриватныйКлюч, хранимую на токене/смаркарте с интерфейсом PKCS#11 v.2.40. В данной статье мы поговорим о генерации ключевой пары. Опираться мы будем, как и прошлый раз, на «ГОСТ Р 34.10-2012 Информационная технология. Криптографическая защита информации. Процессы формирования и проверки электронной цифровой подписи».

    Итак, что такое ключевая пара?


    Ключевая пара включает в себя два ключа:

    • Закрытый ключ/Приватный /Private key — ключ, известный только своему владельцу. Только сохранение владельцем/пользователем в тайне своего закрытого ключа гарантирует невозможность подделки злоумышленником документа и цифровой подписи от имени заверяющего;

    • Открытый ключ/Публичный ключ/ Public key — ключ, который может быть опубликован в сертификате и используется для проверки подлинности подписанного документа, а также для предупреждения мошенничества со стороны заверяющего лица в виде отказа его от подписи документа.

    Следует помнить, что закрытый и открытый ключи это не только их значения (для открытого ключа ГОСТ Р 34.10-2001 это 512 бит), но и параметры схемы цифровой подписи (п. 5.2 ГОСТ Р 34.10-2012). В дальнейшем параметры схемы цифровой подписи для простоты будем называть параметрами (криптопараметрами) ключевой пары.

    Открытый ключ подписи вычисляется, как значение некоторой функции от закрытого ключа, но знание открытого ключа не дает возможности определить закрытый ключ.

    Для ключевых пар ГОСТ Р 34.10-2001 и ГОСТ Р 34.10-2012 с длиной закрытого ключа 256 бит (соответственно, публичный ключ – 512 бит) определены следующие криптопараметры:

    1. id-GostR3410-2001-CryptoPro-A-ParamSet;
    2. id-GostR3410-2001-CryptoPro-B-ParamSet;
    3. id-GostR3410-2001-CryptoPro-C-ParamSet;
    4. id-GostR3410-2001-CryptoPro-XchA-ParamSet;
    5. id-GostR3410-2001-CryptoPro-XchB-ParamSet.

    Для ключевых пар ГОСТ Р 34.10-2012 с длиной закрытого ключа 512 бит (соответственно, публичный ключ – 1024 бита) определены следующие криптопараметры («Информационная технология. Криптографическая защита информации. Параметры эллиптических кривых для криптографических алгоритмов и протоколов»):

    1. id-tc26-gost-3410-2012-512-paramSetA;
    2. id-tc26-gost-3410-2012-512-paramSetB.

    Состав криптопараметров определен в п.5.2 в ГОСТ Р 34.10-2012. В этот состав входит простое число q — порядок подгруппы группы точек эллиптической кривой:

    image

    И именно оно определяет длину закрытого/открытого ключей и корректность закрытого ключа:

    image — длина закрытого ключа 256 бит;

    image — длина закрытого ключа 512 бит.
    И так, открытый ключ получается из закрытого ключа.

    А откуда берется закрытый ключ?


    Для получения закрытого ключа сначала необходимо решить какой длины будет закрытый ключ (256 или 512 бит), затем определиться с криптопараметрами ключевой пары. Теперь берем датчик случайных чисел и получаем случайное число соответствующей длины. Собственно это случайное число и должно стать значением d закрытого ключа (ключом подписи d). Это значение должно удовлетворять следующему правилу:

    0 < d < q, где q – простое число из криптопараметров.

    Что делать, если это условие не выполняется? Если d == 0, то просто сгенерировать новое случайное число. В противном случае достаточно бывает взять остаток от деления на цело значения d, которое превышает q, на q (d % q). Остаток и станет значением закрытого ключа.

    Именно поэтому регулятор (ФСБ России) предъявляет особые требования к датчику случайных чисел.

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

    • случайными цифрами можно привести:
    • регистр TSC процессора – счетчик тактов процессора;
    • счетчик времени GTC;
    • автоинкрементируемый счетчик в отдельном потоке;
    • стандартная функция rand();
    • координаты мыши.

    В качестве дополнительных источников для заполнения данного буфера могут выступать:

    • Счетчик времени работы процесса в пользовательском режиме;
    • Таймер высокого разрешения Windows.

    Таким образом, чтобы токен/смарткарта PKCS#11 могли генерировать внутри себя ключевую пару, необходимо наличие токен/смарткарта встроенного аппаратного датчика случайных чисел, соответствующего требованиям регулятора. И только тогда можно говорить о неизвлекаемости закрытого ключа.

    Для генерации ключевой пары используется фунция C_GenerateKeyPair. В зависимости от того, какую ключевую пару (с какой длиной закрытого ключа 256 или 512 бит) мы генерируем, в ней будет использоваться соответствующий механизм:

    • CKM_GOSTR3410_KEY_PAIR_GEN для ключевой пары с закрытым ключом в 256 бит;
    • CKM_GOSTR3410_512_KEY_PAIR_GEN для ключевой пары с закрытым ключом в 512 бит.

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

    image

    Нас интересуют атрибуты извлекаемости закрытого ключа.


    Это прежде атрибут CKA_SENSITIVE, отвечающий за возможность получения значения закрытого ключа. Если значение атрибута CKA_SENSITIVE установлено в CK_TRUE, то закрытый ключ не может быть извлечен из токена в открытом виде. Второй атрибут CKA_EXTRACTABLE позволяет получать закрытый ключ в зашифрованном виде. Для этого его необходимо установить CK_TRUE.

    Установка атрибута CKA_SENSITIVE в CK_TRUE, а атрибута CKA_EXTRACTABLE в CK_FALSE при генерации ключевой пары делает закрытый ключ абсолютно неизвлекаемым. Возможность определять является ли ключ экспортабельным имеется в браузере Redfox:

    image

    Кто-то скажет, — а что если изменить значения этих атрибутов. Как правило этого сделать нельзя, защиту понизить нельзя, также как «нельзя понижать градус». Точно также можно сделать неизвлекаемым закрытый ключ после его импорта на токен (если конечно токен/смарткарта разрешают импорт). После создания (или во время создания) объекта CKO_PRIVATE_KEY необходимо установить CKA_SENSITIVE=CK_TRUE, а атрибута CKA_EXTRACTABLE=CK_FALSE.

    В последнем случае (при импорте) следует иметь в виду, что хотя закрытый ключ и стал неизвлекаемым, он появился со стороны (например, из PKCS#12), и гарантии, что нет еще где-то его дубликата нету.

    И вот здесь не мешало бы напомнить тебе, уважаемый читатель, что безопасность обеспечивается только КОМПЛЕКСОМ организационных и технических мероприятий. Поэтому не получится латать дыры в организационной безопасности за счет технических средств и наоборот — все должно быть органично согласовано. В том числе, и при доступе к значению закрытого ключа.

    Убедиться, что на токен/смарткарте находятся полноценные объекты PKCS#11 (CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_CERTIFICATE), которые участвуют в криптографических операциях на самом токене удобно с помощью доступной для свободного скачивания утилиты p11conf :

    $ /usr/local/bin64/p11conf -h
    usage:  /usr/local/bin64/p11conf [-hitsmIupPred] -A APIpath [-c slotID -U userPin -S SOPin -n newPin -L label]
            -h display usage
            -i display PKCS#11 library info
            -s display slot(s) info (-c slotID is optional)
            -t display token(s) info (-c slotID is optional)
    Others must use -c slotID
            -m display mechanism list
            -I initialize token 
            -u initialize user PIN
            -p set the user PIN
            -P set the SO PIN
            -r remove all objects
            -e enumerate objects
            -d dump all object attributes
    Copyright(C) 2011-2016
    $

    Для того, чтобы посмотреть какие объекты находятся на токене достаточно выполнить команду вида:

    bash-4.3$ /usr/local/bin64/p11conf -A /usr/local/lib64/libls11sw2016.so -c 0 -e
    Enter user PIN: ********
    Token objects:
    1: CKO_PRIVATE_KEY
             label: 'LS11SW2016:ООО;Маслов А.А.;0x23855(145493)'
    2: CKO_PUBLIC_KEY
             label: 'LS11SW2016:ООО;Маслов А.А.;0x23855(145493)'
    3: CKO_CERTIFICATE
             label: 'LS11SW2016:ООО;Маслов А.А.;0x23855(145493)'
    …
    OK
    bash-4.3$

    Если такие объекты отсутствуют на токене, а говорят, что используется токен PKCS#11 с неизвлекаемым ключом, то это скорей всего не так. Скорей всего токен используется просто как флэшка с PIN-кодом, а сертификат и ключи хранятся как объекты CKO_DATA.

    И наконец, для того, чтобы посмотреть не только какие типы объектов хранятся на токене, а объекты со всеми атрибутами необходимо использовать дополнительно флаг –d:

    bash-4.3$ /usr/local/bin64/p11conf -A /usr/local/lib64/libls11sw2016.so -c 0 –e -d
    Enter user PIN: ********
    Token objects:
    1: CKO_PRIVATE_KEY
    	 label: 'LS11SW2016:ООО;Маслов А.А.;0x23855(145493)'
    ==================================
    Object handle: 0x1
    ----------------------------------
    CKA_CLASS
    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    CKA_TOKEN
    0x01, 
    CKA_PRIVATE
    0x01, 
    CKA_LABEL
    0x4c, 0x53, 0x31, 0x31, 0x53, 0x57, 0x32, 0x30, 
    0x31, 0x36, 0x3a, 0xd0, 0x9e, 0xd0, 0x9e, 0xd0, 
    0x9e, 0x20, 0xd0, 0x9b, 0xd0, 0x98, 0xd0, 0xa1, 
    0xd0, 0xa1, 0xd0, 0x98, 0x2d, 0xd0, 0xa1, 0xd0, 
    0xbe, 0xd1, 0x84, 0xd1, 0x82, 0x3b, 0xd0, 0x9c, 
    0xd0, 0xb0, 0xd1, 0x81, 0xd0, 0xbb, 0xd0, 0xbe, 
    0x20, 0xd0, 0x90, 0x2e, 0xd0, 0x90, 0x2e, 0x3b, 
    0x30, 0x78, 0x32, 0x33, 0x38, 0x35, 0x35, 0x28, 
    0x31, 0x34, 0x35, 0x34, 0x39, 0x33, 0x29, 
    CKA_VALUE: attribute sensitive
    CKA_KEY_TYPE
    0x03, 0x10, 0x32, 0xd4, 0x00, 0x00, 0x00, 0x00, 
    CKA_SUBJECT
    0x30, 0x81, 0x9b, 0x31, 0x0b, 0x30, 0x09, 0x06, 
    0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x55, 
    0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 
    0x03, 0x0c, 0x11, 0xd0, 0x9c, 0xd0, 0xb0, 0xd1, 
    0x81, 0xd0, 0xbb, 0xd0, 0xbe, 0x20, 0xd0, 0x90, 
    0x2e, 0xd0, 0x90, 0x2e, 0x31, 0x1c, 0x30, 0x1a, 
    0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x13, 0xd0, 
    0x9b, 0xd0, 0x98, 0xd0, 0xa1, 0xd0, 0xa1, 0xd0, 
    0x98, 0x2d, 0xd0, 0xa1, 0xd0, 0xbe, 0xd1, 0x84, 
    0xd1, 0x82, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 
    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 
    0x01, 0x16, 0x10, 0x61, 0x6d, 0x61, 0x73, 0x6c, 
    0x6f, 0x76, 0x40, 0x6c, 0x69, 0x73, 0x73, 0x69, 
    0x2e, 0x72, 0x75, 0x31, 0x31, 0x30, 0x2f, 0x06, 
    0x03, 0x55, 0x04, 0x08, 0x0c, 0x28, 0x35, 0x30, 
    0x20, 0x20, 0xd0, 0x9c, 0xd0, 0xbe, 0xd1, 0x81, 
    0xd0, 0xba, 0xd0, 0xbe, 0xd0, 0xb2, 0xd1, 0x81, 
    0xd0, 0xba, 0xd0, 0xb0, 0xd1, 0x8f, 0x20, 0xd0, 
    0xbe, 0xd0, 0xb1, 0xd0, 0xbb, 0xd0, 0xb0, 0xd1, 
    0x81, 0xd1, 0x82, 0xd1, 0x8c, 0x20, 
    CKA_ID
    0x97, 0x46, 0x4e, 0xcc, 0x7c, 0xa9, 0xea, 0xb1, 
    0x0a, 0xda, 0xec, 0x10, 0xf4, 0x49, 0x7e, 0x7f, 
    0x2d, 0x71, 0x4b, 0xa7, 
    CKA_SENSITIVE
    0x01, 
    . . .
    CKA_GOSTR3410_PARAMS
    0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02, 
    0x01, 0x02, 0x01, 
    CKA_GOSTR3411_PARAMS
    0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 
    0x02, 0x03, 
    CKA_GOST28147_PARAMS
    0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1f, 
    0x01, 
    …
    OK
    bash-4.3$

    Все сказанное здесь справедливо для токена/смарткарты с интерфейсом PKCS#11, включая облачный токен.

    В заключение напомним, что токены/смаркарты с интерфейсом PKCS#11 широко используются в проектах Mozilla (браузеры, почтовые клиенты), в браузерах Chrome от Google и других проектах. Если говорить о России, то токены/смаркарты с интерфейсом PKCS#11успешно используются для доступа на портал Госуслуг.
    Поделиться публикацией
    Никаких подозрительных скриптов, только релевантные баннеры. Не релевантные? Пиши на: adv@tmtm.ru с темой «Полундра»

    Зачем оно вам?
    Реклама
    Комментарии 25
    • +1
      А ключи Yubikey не поддерживают же PKCS#11?
      У меня есть Yubikey 4, но похоже для госуслуг и других российских сервисов он бесполезен :(
      • 0
        Ключ Yubikey — это генератор одноразовых паролей. Он не поддерживает PKCS#11, а тем более российскую криптографию.
        • +2
          То что он не поддерживает российскую криптографию это очевидно. Я предполагал, что в центрах сертификации могут выдать RSA-подпись. Но Yubikey 4 это не просто генератор одноразовых паролей. Тут и OpenPGP (как смарткарта) и хранилище по американскому стандарту PIV (PKCS#11 вроде как раз)
          Информация с сайта Yubico
          The YubiKey 4 and YubiKey NEO support the Personal Identity Verification (PIV) interface specified in NIST SP 800-73 document «Cryptographic Algorithms and Key Sizes for PIV». This enables you to perform RSA or ECC sign/decrypt operations using a private key stored on the smartcard, through common interfaces like PKCS#11.
          Поэтому я и подумал, что можно получить RSA-сертификат вместо ГОСТ. Ну или даже ECC.
          • +1
            Ну наши центры сертификации (УЦ) не выдают сертификаты на RSA-ключах, на ECC-тоже. Где-нибудь на VeriSign, COMODO можно получить, если есть интерфейс PKCS#11, с помощью Firefox. Что касается OpenPgp можно посмотреть GnuPg-2, Kleopatra, KMail и российская криптография
          • 0
            Yubico уже давно не выпускает чисто OTP токены. Все Yubikey сегодня это мультифакторные аутентификационные устройства с поддержкоц PKCS#11 в том числе https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html
            • 0
              Это здорово, что все в одном флаконе. Но, к сожалению без ГОСТ-ов. А если упоминать SSH, то следует упоминуть поддержку ГОСТ-ов в openssh/putty.
            • 0
              Характеристики https://www.yubico.com/products/yubikey-hardware/
              • 0
                Спасибо. Их там целый зоопарк, начиная от одноразовых паролей OATH до поддержки ECC p256. Кстати поддержка ECC p256 в принципе позволяет положить на yubikey-hardware поддержку ГОСТ Р 34.10-2012 с длиной ключа 256 бит. Мы уже так делали с китайцами, только здесь никому не надо.
            • 0
              У меня есть Yubikey 4, но похоже для госуслуг и других российских сервисов он бесполезен :(

              Да, именно так сегодня!
            • 0
              Где-то когда-то слышал про токены с которых в принципе считать закрытый ключ нельзя т.е. у них нет программного доступа в закрытому ключу (есть только апи для подписи), а при попытке аппаратно вскрыть токен ключ неминуемо разрушается.
              Может подскажете бывает/не бывает, а если бывает, то как называется и как выдают такие ключи, ведь получается что изготовитель может иметь копию? в идеале надо печатать такой токен на личном 3d принтере, но видимо технологии ещё не дозрели.
              • +2
                Если не ошибаюсь, большинство смарткарт и токенов именно так и работает.
                Лично у меня Yubikey 4. Тут говорят, что приватный ключ не покидает устройство. Во всяком случае c OpenPGP точно. Насчет PKCS#11 не уверен, но скорее всего тоже не покидает.

                И не понял про копию. Вы же сами генерируете пару уже у себя дома. Как производитель может сделать эту копию ещё до создания пары ключей (public/private)?
                • +1
                  Да, именно так и работает. Наружу передается не ключ, а его Handle (указатель на ключ).
                  И именно этот handle используется в операциях с закрытым ключом, например, формиршвание подписи. Копию, конечно, до создания ключевой пары даже теоретически нелься. Хотя, как известно, есть вероятность, что обезьяна напишет «Войну и мир».
                • 0

                  Если к закрытому ключу есть доступ, то смысл в железке вобще отпадает.
                  Железка должна внутри себя генерять ключевую пару, хранить закрытый ключ, а юзеру предоставлять API для показа открытого ключа, короткого шифрования (обычно симетричного ключа) и ЭЦП (т.е. тоже короткого шифрования, но хэша данных).

                  • 0
                    Именно внутри себя настоящий токен/смарткарта и генерят ключевую пару. Юзер может, естественно, получить открытый ключ (хотя бы для того, чтобы положить его в сертификат). Что касается ЭЦП. Короткое шифрование, т.е. шифрование хэша — это свойство RSA. ЭЦП по ГОСТ тоже берется от хэша (ГОСТ Р 34.11-94/2012), но это не совсем шифрование. ЭЦП по ГОСТ естественно делается на закрытом ключе. Значение ключа юзер не получает, а получает указатель на него (HANDLE),. Именно этот указатель и передается в API. И подпись формируется, естественно, внутри токена/смарткарты. Наружу попадает только значение подписи (512 или 1024 бита).
                    Поэтому, если доступ к ключу — это получение HANDLE, то именно железка и обеспечивает неизвлекаемость. Но если железка дает (как это может быть написано в статье), то смысл в железке все же есть, но не глобальный.
                • 0
                  Еще в список:

                  • id-tc26-gost-3410-2012-256- paramSetA
                  • id-tc26-gost-3410-2012-512-paramSetC
                  • 0
                    Да, документе они есть, но для
                    эквивалентного представления в форме скрученных кривых Эдвардса

                    Это немного отдельная песня и я бы сейчас на этом не зацикливался!
                  • 0
                    Можно спросить — какие конкретно модели USB-токенов обладают функцией неизвлекаемости ключа?
                    • 0
                      У каждого токена может быть своя политика выставления флагов:

                      CKA_SENSITIVE=CK_TRUE, а атрибута CKA_EXTRACTABLE=CK_FALSE


                      Из тех, что на слуху, это RuToken ECP (РуТокен ЭЦП) — ключ не извлекаемый!!! Хотя на него можно импортировать закрытый ключ, например, из PKCS#12.
                      Установив флаги CKA_SENSITIVE=CK_TRUE && CKA_EXTRACTABLE=CK_FALSE
                      можно сделать неизвлекаемым ключ даже программно-аппаратных токенах на USB-флэшках.
                      • 0
                        Что-то я не пойму — как можно сделать неизвлекаемый ключ на базе обычной флешки? Что помешает мне её скопировать в месте с меткой тома на флешку из той же партии (на том же контроллере)?
                        • 0
                          Первое, все объекты токена хранятся на флэшке зашифрованные на PIN-е.
                          Создаваемый токен жестко привязан к флэшке (в частности, к ее серийному номеру) и «партия» не прокатит. Неизвлекаемость нафлэшке подразумевает (впрочем, так же и классическом токене) невозможность экспортировать значение закрытьго ключа (CKA_SENSITIVE=CK_TRUE && CKA_EXTRACTABLE=CK_FALSE).
                          Да, здесь криптографические операции, например, подпись, выполняются не в отдельном устройстве (аппаратном токене), а на компьютере (библиотеке), к которому подключена флэшка. И это, естественно, отличает аппаратный токен от программно-аппаратного токена.
                          • 0
                            Да хоть на номере паспорта зашифруйте, если закрытый ключ считывается попадает в память компьютера(контроллер флешки же не занимается шифрованием?) — ключ на данном носителе нельзя назвать неизвлекаемым.
                            Следовательно здесь обман потребителя.
                            • 0
                              Да, так выше и написано, что именно в этом случае ключ естественно на период сессии попадает на компьютер. Так что здесь нет обмана. А вот, что польшинство текенов используется как кранилище для ключей и сертификатов, т.е. как флэшка это плохо.
                              Вообще-то закрытый ключ доступен тому процессору, где с помощью него проводятся криптографические операции
                    • 0
                      Эмм, а где эти «флаги» выставлять?
                      Могули я, имея рутокен, поместить на него существующие ключи указав, что они неизвлекаемые? В стандартном интерфейсе рутокеновских утилит…
                      • 0
                        Можете. У вас ключи хранятся вместе с сертификатом в PKCS#12?
                        Если это так, то для импорта можно воспользоваться Redfox или FoxXCA.
                        В РуТокен ЭЦП флаги устанавливаются по умолчанию и ключ становится неизвлекаемым.
                        Эмм, а где эти «флаги» выставлять?

                        В программе, которую вы можете написать сами в соответствии с PKCS#11 v.2.30, например:
                        priv_atts <<
                        pk11_attr_bool(CKA_TOKEN, true) <<
                        pk11_attr_bool(CKA_PRIVATE, true) <<
                        pk11_attr_data(CKA_LABEL, getIntName().toUtf8()) <<
                        new_id <<
                        pk11_attr_bool(CKA_SENSITIVE, true) <<
                        pk11_attr_bool(CKA_DECRYPT, true) <<
                        pk11_attr_bool(CKA_SIGN, true) <<
                        pk11_attr_bool(CKA_UNWRAP, true)<<
                        pk11_attr_bool(CKA_EXTRACTABLE, false);

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.