Что такое SSL и зачем нужен SSL-сертификат на сайт?

Что такое SSL и зачем нужен SSL-сертификат на сайт? Сертификаты

приложение. требования к форме квалифицированного сертификата ключа проверки электронной подписи | гарант

Требования к форме квалифицированного сертификата ключа проверки электронной подписи

I. Общие положения

2. В настоящих Требованиях используются следующие основные понятия, определенные в статье 2 Федерального закона:

1) электронная подпись (далее – ЭП) – информация в электронной форме, которая присоединена к другой информации в электронной форме (подписываемой информации) или иным образом связана с такой информацией и которая используется для определения лица, подписывающего информацию;

2) ключ ЭП – уникальная последовательность символов, предназначенная для создания ЭП;

3) ключ проверки ЭП – уникальная последовательность символов, однозначно связанная с ключом ЭП и предназначенная для проверки подлинности ЭП (далее – проверка ЭП);

5) сертификат ключа проверки ЭП – электронный документ или документ на бумажном носителе, выданные УЦ либо доверенным лицом УЦ и подтверждающие принадлежность ключа проверки ЭП владельцу сертификата ключа проверки ЭП;

7) владелец сертификата ключа проверки ЭП – лицо, которому в установленном Федеральным законом порядке выдан сертификат ключа проверки ЭП;

9) средства ЭП – шифровальные (криптографические) средства, используемые для реализации хотя бы одной из следующих функций – создание ЭП, проверка ЭП, создание ключа ЭП и ключа проверки ЭП;

10) средства УЦ – программные и (или) аппаратные средства, используемые для реализации функций УЦ;

12) заявитель – коммерческая организация, некоммерческая организация, индивидуальный предприниматель, физическое лицо, не зарегистрированное в качестве индивидуального предпринимателя, но осуществляющее профессиональную деятельность, приносящую доход, в соответствии с федеральными законами на основании государственной регистрации и (или) лицензии, в силу членства в саморегулируемой организации, а также любое иное физическое лицо, лица, замещающие государственные должности Российской Федерации или государственные должности субъектов Российской Федерации, должностные лица государственных органов, органов местного самоуправления, работники подведомственных таким органам организаций, нотариусы и уполномоченные на совершение нотариальных действий лица, обращающиеся с соответствующим заявлением на выдачу сертификата ключа проверки ЭП в УЦ за получением сертификата ключа проверки ЭП в качестве будущего владельца такого сертификата.

3. Настоящие Требования устанавливают требования к совокупности и порядку расположения полей квалифицированного сертификата (далее – форма квалифицированного сертификата).

4. При включении в состав квалифицированного сертификата дополнительных полей требования к их назначению и расположению в квалифицированном сертификате определяются в техническом задании на разработку (модернизацию) средств УЦ.

II. Требования к совокупности полей квалифицированного сертификата

5. Требования к совокупности полей квалифицированного сертификата устанавливаются на основании Федерального закона.

6. В соответствии со статьями 14 и 17 Федерального закона квалифицированный сертификат должен содержать следующую информацию:

– уникальный номер квалифицированного сертификата;

– даты начала и окончания действия квалифицированного сертификата;

– фамилия, имя и отчество (если имеется) владельца квалифицированного сертификата – для физического лица, либо наименование и место нахождения владельца квалифицированного сертификата – для юридического лица, а также в случаях, предусмотренных Федеральным законом, фамилия, имя и отчество (если имеется) физического лица, действующего от имени владельца квалифицированного сертификата – юридического лица на основании учредительных документов юридического лица или доверенности (далее – уполномоченный представитель юридического лица);

– страховой номер индивидуального лицевого счета (далее – СНИЛС) владельца квалифицированного сертификата – для физического лица;

– основной государственный регистрационный номер (далее – ОГРН) владельца квалифицированного сертификата – для российского юридического лица;

– основной государственный регистрационный номер индивидуального предпринимателя (далее – ОГРНИП) – владельца квалифицированного сертификата – для физического лица, являющегося индивидуальным предпринимателем;

– идентификационный номер налогоплательщика (далее – ИНН) владельца квалифицированного сертификата – для физического лица, российского юридического лица и, при наличии, для иностранной организации (в том числе филиалов, представительств и иных обособленных подразделений иностранной организации);

– уникальный ключ проверки ЭП;

– наименование используемого средства ЭП и (или) стандарты, требованиям которых соответствует ключ ЭП и ключ проверки ЭП;

– наименования средств ЭП и средств аккредитованного УЦ, которые использованы для создания ключа ЭП, ключа проверки ЭП, квалифицированного сертификата, а также реквизиты документа, подтверждающего соответствие указанных средств требованиям, установленным в соответствии с Федеральным законом;

– наименование и место нахождения аккредитованного УЦ, который выдал квалифицированный сертификат;

– номер квалифицированного сертификата аккредитованного УЦ;

– идентификатор, однозначно указывающий на то, что идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась либо при его личном присутствии, либо без его личного присутствия с использованием квалифицированной ЭП при наличии действующего квалифицированного сертификата либо посредством идентификации заявителя – гражданина Российской Федерации с применением информационных технологий без его личного присутствия путем предоставления информации, указанной в документе, удостоверяющем личность гражданина Российской Федерации за пределами территории Российской Федерации, содержащем электронный носитель информации с записанными на нем персональными данными владельца паспорта, включая биометрические персональные данные, или путем предоставления сведений из федеральной государственной информационной системы “Единая система идентификации и аутентификации в инфраструктуре, обеспечивающей информационно-технологическое взаимодействие информационных систем, используемых для предоставления государственных и муниципальных услуг в электронной форме” 1 (далее – единая система идентификации и аутентификации) и единой информационной системы персональных данных, обеспечивающей обработку, включая сбор и хранение биометрических персональных данных, их проверку и передачу информации о степени их соответствия предоставленным биометрическим персональным данным гражданина Российской Федерации (далее – единая биометрическая система), в порядке, установленном Федеральным законом от 27 июля 2006 г. N 149-ФЗ “Об информации, информационных технологиях и о защите информации” 2.

------------------------------

1Постановление Правительства Российской Федерации от 28 ноября 2021 г. N 977 “О федеральной государственной информационной системе “Единая система идентификации и аутентификации в инфраструктуре, обеспечивающей информационно-технологическое взаимодействие информационных систем, используемых для предоставления государственных и муниципальных услуг в электронной форме” (Собрание законодательства Российской Федерации, 2021, N 49 (ч. V), ст. 7284; 2020, N 34, ст. 5484).

2 Собрание законодательства Российской Федерации, 2006, N 31 (ч. I), ст. 3448; 2020, N 24, ст. 3751.

------------------------------

7. Квалифицированный сертификат должен содержать квалифицированную ЭП аккредитованного УЦ (доверенного лица аккредитованного УЦ, уполномоченного федерального органа), подтверждающую принадлежность ключа проверки ЭП владельцу квалифицированного сертификата.

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

10. Структура квалифицированного сертификата в форме электронного документа, определенная в соответствии со спецификацией абстрактной синтаксической нотации версии один 2, должна иметь следующий общий вид:

Certificate ::= SIGNED { SEQUENCE {
    version                 [0]     Version DEFAULT v l,
    serialNumber                    CertificateSerialNumber,
    signature                       AlgorithmIdentifier,
    issuer                          Name,
    validity                        Validity,
    subject                         Name,
    subjectPublicKeyInfo            SubjectPublicKeyInfo,
    issuerUniqueIdentifier  [1]     IMPLICIT UniqueIdentifier OPTIONAL,
    subjectUniqueIdentifier [2]     IMPLICIT UniqueIdentifier OPTIONAL,
    extensions              [3]     Extensions OPTIONAL } }
SIGNED { ToBeSigned } ::= SEQUENCE {
    toBeSigned                      ToBeSigned,
    COMPONENTS OF                   SIGNATURE { ToBeSigned } }
SIGNATURE { ToBeSigned } ::= SEQUENCE {
    algorithmIdentifier             AlgorithmIdentifier,
    encrypted                       ENCRYPTED-HASH { ToBeSigned } }
ENCRYPTED-HASH { ToBeSigned } ::= BIT STRING (CONSTRAINED BY
                                       { ToBeSigned }).
------------------------------

2 Справочно: Спецификация абстрактной синтаксической нотации версии один определена в ГОСТ Р ИСО/МЭК 8824-1-2001 “Информационная технология. Абстрактная синтаксическая нотация версии один (АСН.1). Часть 1. Спецификация основной нотации”.

------------------------------

12. Поле encrypted содержит ЭП, сформированную аккредитованным УЦ, доверенным лицом аккредитованного УЦ либо уполномоченным федеральным органом под структурированной совокупностью полей квалифицированного сертификата (toBeSigned).

15. Поле signature (подпись) содержит идентификатор криптографического алгоритма, с использованием которого аккредитованный УЦ, доверенное лицо аккредитованного УЦ либо уполномоченный федеральный орган сформировали ЭП данного квалифицированного сертификата. Содержимое данного поля должно совпадать с содержимым поля algorithmIdentifier.

17. Стандартные атрибуты имени описаны в справочнике выбранных типов атрибутов 1. При описании формы квалифицированного сертификата используются следующие стандартные атрибуты имени:

------------------------------

1 Справочно: Выбранные типы атрибутов определены в ГОСТ Р ИСО/МЭК 9594-6-98 “Информационная технология. Взаимосвязь открытых систем. Справочник. Часть 6. Выбранные типы атрибутов” и в международном стандарте ISO/IEC 9594-6:2008 “Information technology – Open systems interconnection – The Directory: Selected attribute types”, опубликованном по адресу в информационно-телекоммуникационной сети Интернет: http://www.itu.int/rec/T-REC-X.520-200811-I/en.

------------------------------

18. К дополнительным атрибутам имени, необходимость использования которых устанавливается в соответствии с Федеральным законом, относятся:

20. Поле subject имеет тип Name и идентифицирует владельца квалифицированного сертификата.

Про сертификаты:  Буровой раствор как обязательный компонент технологии бурения

22. Необязательные поля issuerUniqueIdentifier и subjectUniqueIdentifier имеют тип UniqueIdentifier. Настоящие Требования не устанавливают требований к использованию указанных полей.

25. Дополнение keyUsage определяет область использования ключа проверки ЭП, содержащегося в поле subjectPublicKeylnfo квалифицированного сертификата. Дополнение keyUsage имеет тип KeyUsage, структура которого определяется следующим образом:

KeyUsage ::= BIT STRING {
    digitalSignature      (0),
    contentCommitment     (1),
    keyEncipherment       (2),
    dataEncipherment      (3),
    keyAgreement          (4),
    keyCertSign           (5),
    cRLSign               (6),
    encipherOnly          (7),
    decipherOnly         (8)}.

Значение “1” в нулевом бите означает, что область использования ключа включает проверку ЭП под электронными документами, отличными от квалифицированных сертификатов и списков уникальных номеров квалифицированных сертификатов ключей проверки ЭП, действие которых на определенный момент было прекращено УЦ до истечения их действия (далее – список аннулированных сертификатов), предназначенными для выполнения процедур аутентификации или контроля целостности.

Значение “1” в первом бите означает, что область использования ключа включает проверку ЭП под электронными документами, отличными от квалифицированных сертификатов и списков аннулированных сертификатов, в отношении которых ставится задача обеспечения невозможности отказа подписавшего лица от своего действия.

Значение “1” во втором бите означает, что область использования ключа включает зашифрование закрытых или секретных ключей, например в целях их защищенной доставки.

Значение “1” в третьем бите означает, что область использования ключа включает непосредственно зашифрование пользовательских данных без дополнительного использования методов симметричной криптографии.

Значение “1” в четвертом бите означает, что область использования ключа включает согласование ключей.

Значение “1” в пятом бите означает, что область использования ключа включает проверку подписей под квалифицированными сертификатами.

Значение “1” в шестом бите означает, что область использования ключа включает проверку подписей под списками аннулированных сертификатов.

Значение “1” в седьмом бите означает, что область использования ключа включает зашифрование данных в процессе согласования ключей (при этом в четвертом бите должно быть значение “1”).

Значение “1” в восьмом бите означает, что область использования ключа включает расшифрование данных в процессе согласования ключей (при этом в четвертом бите должно быть значение “1”).

Объектный идентификатор дополнения keyUsage имеет вид 2.5.29.15.

28. Сведения о классе средств ЭП владельца квалифицированного сертификата должны быть указаны в дополнении certificatePolicies путем включения следующих идентификаторов:

– для класса средств ЭП КС 1: 1.2.643.100.113.1,

– для класса средств ЭП КС2: 1.2.643.100.113.1, 1.2.643.100.113.2,

– для класса средств ЭП КС3: 1.2.643.100.113.1, 1.2.643.100.113.2, 1.2.643.100.113.3,

– для класса средств ЭП КВ1: 1.2.643.100.113.1, 1.2.643.100.113.2, 1.2.643.100.113.3, 1.2.643.100.113.4,

– для класса средств ЭП КВ2: 1.2.643.100.113.1, 1.2.643.100.113.2, 1.2.643.100.113.3, 1.2.643.100.113.4, 1.2.643.100.113.5,

– для класса средств ЭП КА1: 1.2.643.100.113.1, 1.2.643.100.113.2, 1.2.643.100.113.3, 1.2.643.100.113.4, 1.2.643.100.113.5, 1.2.643.100.113.6.

Для средств ЭП, класс которых отличается от класса средств УЦ, в которых используются указанные средства ЭП, следует указывать идентификаторы для класса средств ЭП, соответствующего классу средств УЦ.

28.1. Для указания в квалифицированном сертификате идентификатора, однозначно указывающего на то, что идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась при его личном присутствии или без его личного присутствия с использованием квалифицированной ЭП при наличии действующего квалифицированного сертификата либо без личного присутствия заявителя – гражданина Российской Федерации с применением информационных технологий путем предоставления информации, указанной в документе, удостоверяющем личность гражданина Российской Федерации за пределами территории Российской Федерации, содержащем электронный носитель информации с записанными на нем персональными данными владельца паспорта, включая биометрические персональные данные, или путем предоставления сведений из единой системы идентификации и аутентификации и единой биометрической системы в порядке, установленном Федеральным законом от 27 июля 2006 г. N 149-ФЗ “Об информации, информационных технологиях и о защите информации”, должно использоваться некритичное дополнение identificationKind типа IdentificationKind, имеющего следующее представление:

IdentificationKind ::= INTEGER { personal(O), remote_cert(l), remote_passport(2), remote_system(3) }.

В случае, если идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась при его личном присутствии, дополнение identificationKind должно иметь значение 0.

В случае, если идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с использованием квалифицированной ЭП при наличии действующего квалифицированного сертификата, дополнение identificationKind должно иметь значение 1.

В случае, если идентификация заявителя – гражданина Российской Федерации при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с применением информационных технологий путем предоставления информации, указанной в документе, удостоверяющем личность гражданина Российской Федерации за пределами территории Российской Федерации, содержащем электронный носитель информации с записанными на нем персональными данными владельца паспорта, включая биометрические персональные данные, дополнение identificationKind должно иметь значение 2.

В случае, если идентификация заявителя – гражданина Российской Федерации при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с применением информационных технологий путем предоставления сведений из единой системы идентификации и аутентификации и единой биометрической системы в порядке, установленном Федеральным законом от 27 июля 2006 г. N 149-ФЗ “Об информации, информационных технологиях и о защите информации”, дополнение identificationKind должно иметь значение 3.

Объектный идентификатор типа IdentificationKind имеет вид 1.2.643.100.114.

29. Для указания в квалифицированном сертификате наименования используемого владельцем квалифицированного сертификата средства ЭП должно использоваться некритичное дополнение subjectSignTool типа UTF8String SIZE(1..200), объектный идентификатор которого имеет вид 1.2.643.100.111.

30. Для указания в квалифицированном сертификате наименования средств ЭП и средств аккредитованного УЦ, которые использованы для создания ключа ЭП, ключа проверки ЭП, квалифицированного сертификата, а также реквизитов документа, подтверждающего соответствие указанных средств требованиям, установленным законодательством Российской Федерации, должно использоваться некритичное дополнение issuerSignTool типа IssuerSignTool, имеющего следующее представление:

IssuerSignTool ::= SEQUENCE {
    signTool            UTF8String SIZE(1.200),
    cATool              UTF8String SIZE(1..200),
    signToolCert        UTF8String SIZE(1.. 100),
    cAToolCert          UTF8String SIZE(1.100) }.

В строковом поле signTool должно содержаться полное наименование средства ЭП, которое было использовано для создания ключа ЭП, ключа проверки ЭП и квалифицированного сертификата.

В строковом поле cATool должно содержаться полное наименование средства аккредитованного УЦ, которое было использовано для создания ключа ЭП, ключа проверки ЭП и квалифицированного сертификата.

В строковом поле signToolCert должны содержаться реквизиты заключения ФСБ России о подтверждении соответствия средства ЭП, которое было использовано для создания ключа ЭП, ключа проверки ЭП, требованиям, установленным в соответствии с Федеральным законом (далее – заключение о подтверждении соответствия средства электронной подписи).

В строковом поле cAToolCert должны содержаться реквизиты заключения ФСБ России о подтверждении соответствия средства УЦ, которое было использовано для создания квалифицированного сертификата, требованиям, установленным в соответствии с Федеральным законом (далее – заключение о подтверждении соответствия средства удостоверяющего центра).

Объектный идентификатор типа IssuerSignTool имеет вид 1.2.643.100.112.

IV. Требования к форме квалифицированного сертификата
на бумажном носителе

Идентификаторы объектов

При принятии решения об использовании данного сертификата для конкретной цели и доверии к нему пользователь может ориентироваться на указательППС в сертификате формата X.509 версии 3.

Таким указателем, характеризующим политику применения сертификатов, является уникальный зарегистрированный идентификатор объектаObject Identifier.

Идентификаторы объектов – это один из простых типов данных, определяемых абстрактной синтаксической нотацией ASN.1. Идентификатор объекта задается последовательностью целочисленных компонентов (например, 1.3.6.1.4.1.6943 ), которая уникально идентифицирует объект (алгоритм, тип атрибута и т.п.) или центр регистрации идентификаторов.

Регистрацияидентификаторов объектов выполняется в соответствии с процедурами, определенными стандартами Международной организации стандартизации (ISO), Международной электротехнической комиссии (IEC)

и Международным союзом по телекоммуникациям (ITU). Сторона, регистрирующая Object Identifier, публикует текстовую спецификацию ППС для ознакомления с ней пользователей сертификатов.

Каждый УЦ аккредитуется с учетом заявленных им политик, которые считаются базовыми. Перечень заявленных политик указывается в сертификате этого центра. Существует система международных, национальных и корпоративных центров регистрации. Во многих странах национальные организации стандартизации поддерживают регистридентификаторов объектов.

Центры регистрации идентификаторов создают иерархию идентификаторов объектов и гарантируют уникальность каждого идентификатора в общей системе. Каждый центр определяет смысл значений Object Identifier данной последовательности компонентов и несет ответственность за все последовательности компонентов, начиная с данной последовательности [2]. Центр может делегировать полномочия другому подчиненному центру регистрации идентификаторов.

Идентификаторы объектов часто применяют в сертификатах X.509 для:

Модель доверия стандарта X.509 предполагает анализ идентификаторов ППС при обработке пути сертификации.

Про сертификаты:  Нефрология повышение квалификации | Курс нефрологии и гемодиализа - МЦПО дистанционное обучение в Москве

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

Вообще говоря, корпоративная PKI может поддерживать 4-5 разных политик применения сертификатов. Иногда новые идентификаторы требуются для задания узкоспециальных дополнений сертификатов и списков САС. Идентификаторы объектов, определенные для удовлетворения этих локальных требований одной PKI, часто называются частными идентификаторами объектов,
поскольку они принадлежат конкретной компании или организации (в табл. 13.

Планирование сроков действия crl

Это всё было о составе списков отзыва для каждого ЦС. Теперь следует определить сроки:

Здесь тоже можно применить подход в зависимости от условий эксплуатации. Риск отзыва промежуточного ЦС весьма низкий, следовательно, нет смысла слишком часто публиковать пустой CRL. В современной практике применяются следующие типовые значения по сроку действия CRL для ЦС, которые выписывают сертификаты только другим ЦС:

Для подчиненных ЦС схема такая же. Поскольку риск отзыва клиентских сертификатов высокий, то можно предположить и высокую частоту отзыва. Следовательно, таким ЦС следует выполнять публикацию списков отзыва гораздо чаще, а для экономии трафика комбинировать базовые и дифференциальные CRL.

Можно понять желание администраторов уменьшить это время (в идеале – мгновенно), чтобы клиенты не признавали отозванный сертификат действительным. Однако, уменьшение одного риска приводит к увеличению другого риска. Представьте, что по какой-то причине отказал сервер ЦС в момент, когда предыдущий CRL близок к истечению срока действия, а новый CRL невозможно опубликовать.

Microsoft CA по умолчанию уже закладывает некоторый резерв по времени на непредвиденные случаи и когда распространение списков отзыва по всем точкам публикации занимает некоторое время (например, вызваны латентностью репликации). Этот резерв в английской терминологии называется CRL overlap.

Это достигается использованием двух полей в списке отзыва: Next CRL Publish и Next Update. Поле Next CRL Publish указывает на время, когда ЦС опубликует обновлённый список отзыва (автоматически). Next Update указывает на время, когда срок действия текущего списка истечёт.

Поле Next Update будет всегда выставлен на несколько позднее время, чем Next CRL Publish. Другими словами, ЦС опубликует обновлённый список отзыва до истечения срока предыдущего. Алгоритм вычисления автоматических значений для этих полей нетривиален и описан в следующей статье:

How ThisUpdate, NextUpdate and NextCRLPublish are calculated (v2). Если значения по умолчанию вас не устраивают по тем или иным причинам, их можно отредактировать. Необходимо учитывать, что запас по времени имеет нижние и верхние границы.

Например, верхняя граница не может превышать срока действия самого CRL. Так, если срок действия CRL составляет 1 день, то запас может составлять максимум 1 день, и тогда ЦС будет публиковать списки отзыва ежедневно, но срок действия будет составлять 2 дня. Тем самым достигается запас времени на восстановление ЦС в случае непредвиденных обстоятельств.

На практике я достаточно часто наблюдал желание администраторов закрутить настройки сроков действия CRL до минимального предела с таким обоснованием: «пользователь уволился и не должен иметь возможность аутентифицироваться с отозванным сертификатом».

При планировании сроков действия CRL и периодичности следует руководствоваться следующими рекомендациями:

Подготовительный этап

Мы реализовали его внутри функцииinit_pkcs11:

#include "utils.h"

CK_FUNCTION_LIST_PTR functionList;                 // Указатель на список функций PKCS#11, хранящийся в структуре CK_FUNCTION_LIST
CK_FUNCTION_LIST_EXTENDED_PTR functionListEx;      // Указатель на список функций расширения PKCS#11, хранящийся в структуре CK_FUNCTION_LIST_EXTENDED
static HMODULE module;

int init_pkcs11()
{
    CK_C_GetFunctionList getFunctionList;              // Указатель на функцию C_GetFunctionList
    CK_C_EX_GetFunctionListExtended getFunctionListEx; // Указатель на функцию C_EX_GetFunctionListExtended

    /* Параметры для инициализации библиотеки: разрешаем использовать объекты синхронизации операционной системы */
    CK_C_INITIALIZE_ARGS initArgs = { NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR, CKF_OS_LOCKING_OK, NULL_PTR };

    CK_RV rv;                      // Код возврата PKCS#11 функций
    int errorCode = 1;                                 // Флаг ошибки

    /*************************************************************************
    * Выполнить действия для начала работы с библиотекой PKCS#11             *
    *************************************************************************/
    printf("Initialization...n");

    /*************************************************************************
    * Загрузить библиотеку                                                   *
    *************************************************************************/
    module = LoadLibrary(PKCS11_LIBRARY_DIR "/" PKCS11ECP_LIBRARY_NAME);
    CHECK(" LoadLibrary", module != NULL, exit);

    /*************************************************************************
    * Получить адрес функции запроса структуры с указателями на функции      *
    *************************************************************************/
    getFunctionList = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList");
    CHECK(" GetProcAddress (C_GetFunctionList)", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
    * Получить адрес функции запроса структуры с указателями на функции      *
    * расширения стандарта PKCS#11                                           *
    *************************************************************************/
    getFunctionListEx = (CK_C_EX_GetFunctionListExtended)GetProcAddress(module, "C_EX_GetFunctionListExtended");
    CHECK(" GetProcAddress (C_EX_GetFunctionListExtended)", getFunctionList != NULL, unload_pkcs11);

    /*************************************************************************
    * Получить структуру с указателями на функции                            *
    *************************************************************************/
    rv = getFunctionList(&functionList);
    CHECK_AND_LOG(" Get function list", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
    * Получить структуру с указателями на функции расширения стандарта       *
    *************************************************************************/
    rv = getFunctionListEx(&functionListEx);
    CHECK_AND_LOG(" Get function list extended", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    /*************************************************************************
    * Инициализировать библиотеку                                            *
    *************************************************************************/
    rv = functionList->C_Initialize(&initArgs);
    CHECK_AND_LOG(" C_Initialize", rv == CKR_OK, rvToStr(rv), unload_pkcs11);

    errorCode = 0;

    /*************************************************************************
    * Выгрузить библиотеку из памяти                                         *
    *************************************************************************/
unload_pkcs11:
    if (errorCode)
        CHECK_RELEASE(" FreeLibrary", FreeLibrary(module), errorCode);
exit:
    return errorCode;
}

Здесь происходит следующее:

  1. В память процесса подгружается PKCS#11-библиотека, хранящаяся по пути PKCS11ECP_LIBRARY_NAME, с помощью функции LoadLibrary (стандартная функция для Windows-систем, для Linux-систем определена обертка).

  2. Далее из библиотеки вытаскиваются указатели на функции C_GetFunctionList и C_EX_GetFunctionListExtended. Первая функция определена в стандарте PKCS#11 и позволяет получить структуру указателей на функции библиотеки. Вторая — является специфичной для библиотеки rtpkcs11ecp и позволяет получить схожую структуру указателей на функции расширения библиотеки. О функциях расширения мы поговорим позже.

  3. Потом мы вызываем полученную функцию C_GetFunctionList и получаем уже саму структуру указателей на функции.

  4. С помощью функции C_Initialize инициализируется загруженная библиотека. Функция C_Initialize в качестве аргумента принимает параметры инициализации библиотеки. Подробнее о них можно почитать здесь, для нас же важен флаг CKF_OS_LOCKING_OK. Его необходимо использовать, если мы хотим использовать библиотеку в нескольких потоках. В нашем примере мы могли бы опустить этот флаг.

Поиск объектов и создание сырой подписи

В прошлом разделе мы сгенерировали ключевую пару. На этот раз будем считать, что у нас нет хендлов на сгенерированные ключи, но мы знаем их идентификатор – CKA_ID. Попробуем найти объект закрытого ключа на токене:

int findObjects(CK_SESSION_HANDLE session,         // Хэндл открытой сессии
                CK_ATTRIBUTE_PTR attributes,       // Массив с шаблоном для поиска
                CK_ULONG attrCount,                // Количество атрибутов в массиве поиска
                CK_OBJECT_HANDLE objects[],        // Массив для записи найденных объектов
                CK_ULONG* objectsCount             // Количество найденных объектов
                       )
{
    CK_RV rv;                                           // Код возврата. Могут быть возвращены только ошибки, определенные в PKCS#11
    int errorCode = 1;                                  // Флаг ошибки

    /*************************************************************************
    * Инициализировать операцию поиска                                       *
    *************************************************************************/
    rv = functionList->C_FindObjectsInit(session, attributes, attrCount);
    CHECK_AND_LOG("  C_FindObjectsInit", rv == CKR_OK, rvToStr(rv), exit);

    /*************************************************************************
    * Найти все объекты, соответствующие критериям поиска                    *
    *************************************************************************/

    rv = functionList->C_FindObjects(session, objects, *objectsCount, objectsCount);
    CHECK_AND_LOG("  C_FindObjects", rv == CKR_OK, rvToStr(rv), find_final);

    errorCode = 0;

    /*************************************************************************
    * Деинициализировать операцию поиска                                     *
    *************************************************************************/
find_final:
    rv = functionList->C_FindObjectsFinal(session);
    CHECK_RELEASE_AND_LOG("  C_FindObjectsFinal", rv == CKR_OK, rvToStr(rv), errorCode);

exit:
    return errorCode;
}

int find_private_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR privateKey)
{
        CK_BYTE keyPairIdGost2021_256[] = { "GOST R 34.10-2021 (256 bits) sample key pair ID (Aktiv Co.)" };
        CK_OBJECT_CLASS privateKeyObject = CKO_PRIVATE_KEY;

        CK_ATTRIBUTE privateKeyTemplate[] =
        {
                { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject)},              // Класс - закрытый ключ
                { CKA_ID, &keyPairIdGost2021_256, sizeof(keyPairIdGost2021_256) - 1},   // Идентификатор ключевой пары (должен совпадать у открытого и закрытого ключей)
        };

        CK_ULONG cnt = 1;

        CK_RV rv;
        int errorCode = 1;

        rv = findObjects(session, privateKeyTemplate,
        arraysize(privateKeyTemplate), privateKey, &cnt);

        CHECK(" findObjects", rv == 0, exit);
        CHECK_AND_LOG(" Checking number of keys found", cnt == 1, "No objects foundn", exit);

        errorCode = 0;
exit:
        return errorCode;
}

Данный пример иллюстрирует работу с функцией поиска объекта по заданным атрибутам. Как можно заметить, операция поиска объекта на токене является составной и работа с ней сводится как минимум к вызову трёх функций: C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal.

Функция C_FindObjects может вызываться по несколько раз, и каждый раз она будет возвращать следующие объекты поиска. Предпоследний аргумент функции C_FindObjects задаёт размер выходного массива объектов. А последний — количество полученных объектов после очередного поиска.

Поиск приватного ключа производился по атрибуту его класса и идентификатору. Мы рассчитывали, что найдётся хотя бы один объект по заданному шаблону и брали любой из них. Используем найденный ключ для вычисления сырой подписи:

int sign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE privateKey)
{    
    /* OID алгоритма хеширования ГОСТ Р 34.11-2021(256)                     */
    CK_BYTE parametersGostR3411_256[] = {0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02};

    /* Механизм подписи/проверки подписи по алгоритму ГОСТ Р 34.10-2021(256) и хешированием по алгоритму ГОСТ Р 34.11-2021(256) */
    CK_MECHANISM gost3410SignWith3411Mech = { CKM_GOSTR3410_WITH_GOSTR3411_12_256, ¶metersGostR3411_256, sizeof(parametersGostR3411_256)};

    CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
               0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };

    CK_BYTE_PTR signature;                            // Указатель на буфер, содержащий цифровую подпись для данных
    CK_ULONG signatureSize;                           // Размер буфера, содержащего цифровую подпись для данных, в байтах

    CK_RV rv;
    int errorCode = 1;

    /*************************************************************************
    * Вычислить подпись от данных                                            *
    *************************************************************************/
    printf(" Signing data...n");

    /*************************************************************************
    * Инициализировать операцию подписи данных                               *
    *************************************************************************/
    rv = functionList->C_SignInit(session, &gost3410SignWith3411Mech, privateKey);
    CHECK_AND_LOG("  >C_SignInit", rv == CKR_OK, rvToStr(rv), exit);

    /*************************************************************************
    * Определить размер данных подписи                                       *
    *************************************************************************/
    rv = functionList->C_Sign(session, data, sizeof(data), NULL_PTR, &signatureSize);
    CHECK_AND_LOG("  C_Sign(get size)", rv == CKR_OK, rvToStr(rv), exit);

    /*************************************************************************
    * Подписать данные                                                       *
    *************************************************************************/

    signature = (CK_BYTE*)malloc(signatureSize * sizeof(CK_BYTE));
    CHECK("  Memory allocation for signature", signature != NULL, exit);

    rv = functionList->C_Sign(session, data, sizeof(data), signature, &signatureSize);
    CHECK_AND_LOG("  C_Sign (signing)", rv == CKR_OK, rvToStr(rv), free_signature);


    /*************************************************************************
    * Распечатать буфер, содержащий подпись                                  *
    *************************************************************************/
    printf("  Signature buffer is: n");
    printHex(signature, signatureSize);
    printf("Data has been signed successfully.n");

    errorCode = 0;

free_signature:
    free(signature);
exit:
    return errorCode;
}

В этом примере подпись и хеш можно считать одновременно. Такой вариант рекомендован для безопасности: цепочку “хеширование-подпись” лучше не «разрывать». Чтобы показать, какой алгоритм хеширования использовать, мы передали его OID.

Про сертификаты:  ТЕРМОМЕТР МЕДИЦИНСКИЙ ЦИФРОВОЙ LD-300 - цена 190 руб., купить в интернет аптеке в Строителе ТЕРМОМЕТР МЕДИЦИНСКИЙ ЦИФРОВОЙ LD-300, инструкция по применению

Также имеется возможность считать сырую подпись в два этапа: сначала брать хеш от данных, а затем вычислялась подпись от хеша. Такой подход более модульный, т.к. алгоритмы хеширования и вычисления подписи могут быть любыми и их можно комбинировать. Естественно, комбинировать можно с некоторыми ограничениями, которые налагаются стандартами, например, на длину хеша.

Создание объектов — на примере генерации ключевых пар

В первую очередь, напишем функцию, которая будет генерировать ключевую пару ГОСТ Р 34.10-2021 256 бит на указанном слоте:

int gen_gost_key_pair(CK_SESSION_HANDLE session)
{
    CK_KEY_TYPE keyTypeGostR3410_2021_256 = CKK_GOSTR3410;
    CK_BYTE keyPairIdGost2021_256[] = { "GOST R 34.10-2021 (256 bits) sample key pair ID (Aktiv Co.)" };
    CK_BYTE parametersGostR3410_2021_256[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 };
    CK_BYTE parametersGostR3411_2021_256[] = { 0x06, 0x08, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x01, 0x02, 0x02 };
    CK_BBOOL attributeTrue = CK_TRUE;
    CK_BBOOL attributeFalse = CK_FALSE;

    CK_OBJECT_CLASS publicKeyObject = CKO_PUBLIC_KEY;

    CK_ATTRIBUTE publicKeyTemplate[] =
    {
        { CKA_CLASS, &publicKeyObject, sizeof(publicKeyObject)},                                        // Класс - открытый ключ
        { CKA_ID, &keyPairIdGost2021_256, sizeof(keyPairIdGost2021_256) - 1 },                          // Идентификатор ключевой пары (должен совпадать у открытого и закрытого ключей)
        { CKA_KEY_TYPE, &keyTypeGostR3410_2021_256, sizeof(keyTypeGostR3410_2021_256) },                // Тип ключа - ГОСТ Р 34.10-2021(256)
        { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue)},                                            // Ключ является объектом токена
        { CKA_PRIVATE, &attributeFalse, sizeof(attributeFalse)},                                        // Ключ доступен без аутентификации на токене
        { CKA_GOSTR3410_PARAMS, parametersGostR3410_2021_256, sizeof(parametersGostR3410_2021_256) },   // Параметры алгоритма ГОСТ Р 34.10-2021(256)
        { CKA_GOSTR3411_PARAMS, parametersGostR3411_2021_256, sizeof(parametersGostR3411_2021_256) }    // Параметры алгоритма ГОСТ Р 34.11-2021(256)
    };

    CK_OBJECT_CLASS privateKeyObject = CKO_PRIVATE_KEY;

    CK_ATTRIBUTE privateKeyTemplate[] =
    {
        { CKA_CLASS, &privateKeyObject, sizeof(privateKeyObject)},                                      // Класс - закрытый ключ
        { CKA_ID, &keyPairIdGost2021_256, sizeof(keyPairIdGost2021_256) - 1 },                          // Идентификатор ключевой пары (должен совпадать у открытого и закрытого ключей)
        { CKA_KEY_TYPE, &keyTypeGostR3410_2021_256, sizeof(keyTypeGostR3410_2021_256) },                // Тип ключа - ГОСТ Р 34.10-2021(256)
        { CKA_TOKEN, &attributeTrue, sizeof(attributeTrue)},                                            // Ключ является объектом токена
        { CKA_PRIVATE, &attributeTrue, sizeof(attributeTrue)},                                          // Ключ доступен только после аутентификации на токене
        { CKA_GOSTR3410_PARAMS, parametersGostR3410_2021_256, sizeof(parametersGostR3410_2021_256) },   // Параметры алгоритма ГОСТ Р 34.10-2021(256)
        { CKA_GOSTR3411_PARAMS, parametersGostR3411_2021_256, sizeof(parametersGostR3411_2021_256) }    // Параметры алгоритма ГОСТ Р 34.11-2021(256)
    };

    CK_OBJECT_HANDLE privateKey;                      // Хэндл закрытого ключа ГОСТ (ключевая пара для подписи и шифрования)    
    CK_OBJECT_HANDLE publicKey;                       // Хэндл открытого ключа ГОСТ (ключевая пара для подписи и шифрования)    

    CK_MECHANISM gostR3410_2021_256KeyPairGenMech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL_PTR, 0 };

    CK_RV rv;   
    int errorCode = 1;

    /*************************************************************************
    * Генерация ключевой пары на токене                                      *
    *************************************************************************/
    rv = functionList->C_GenerateKeyPair(session, &gostR3410_2021_256KeyPairGenMech, 
    publicKeyTemplate, arraysize(publicKeyTemplate),
    privateKeyTemplate, arraysize(privateKeyTemplate),
    &publicKey, &privateKey);
    CHECK_AND_LOG(" C_GenerateKeyPair", rv == CKR_OK, rvToStr(rv), exit);

    errorCode = 0;
    printf("Gost key pair generated successfullyn");

exit:
    return errorCode;
}

В этом примере для нас много нового. Можно заметить, что здесь вызывается всего одна функция C_GenerateKeyPair. Эта функция является стандартной функцией генерации ключей, работающей внутри открытой сессии. Также стоит отметить, что пользователь должен быть аутентифицирован перед вызовом этой функции.

Теперь перейдём к объектам. Внутри функции gen_gost_key_pair происходит создание двух объектов на токене: открытого и закрытого ключей. Вот, что стандарт PKCS#11 говорит про объекты:

Cryptoki recognizes a number of classes of objects, as defined in the CK_OBJECT_CLASS data type. An object consists of a set of attributes, each of which has a given value. Each attribute that an object possesses has precisely one value.

То есть стандарт не даёт явное определение объекта, но из того, что там написано, мы знаем:

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

Иерархия PKCS#11 объектов
Иерархия PKCS#11 объектов

Заголовок диаграммы определяет класс объекта, а то что ниже — некоторые из его атрибутов. Видно, что объектом может являться некоторый механизм (о механизмах мы поговорим позже), встроенные функции токена (Hardware feature), некоторые данные на токене (Storage). В нашем случае мы выполнили действие с данными.

Название всех атрибутов начинается с префикса “CKA_”. Одним из самых важных атрибутов является CKA_ID. Он задаёт идентификатор объекта и используется для связи ключевых пар и сертификатов. Атрибут CKA_TOKEN является булевым и показывает, является ли объект — объектом токена.

Атрибут CKA_PRIVATE тоже является булевым и определяет нужна ли предварительная аутентификация для получения доступа к объекту. Атрибут CKA_ID — задаёт шестнадцатеричный идентификатор объекта. Также есть булевые атрибуты CKA_MODIFIABLE, CKA_COPYABLE, CKA_DESTROYABLE для более тонкой настройки доступа к объекту.

Объекты данных могут быть самыми разнообразными: асимметричные ключи, симметричные ключи, сертификаты, просто какая-либо информация на токене. В нашем примере мы создали два объекта, но сделали это неявно с помощью механизма генерации ключей. C_GenerateKeyPair приняла на вход механизм генерации ключевой пары, шаблоны открытого и закрытого ключа и с помощью механизма сгенерировала объекты ключевой пары (publicKey и privateKey).

Формирование cms-подписи

Данная возможность является расширением библиотеки Рутокен и может работать только с ГОСТ-ключами. Для создания подписи в формате CMS требуется наличие закрытого ключа и сертификата (неявно содержащего в себе открытый ключ). Создание CMS-подписи реализовано в функции sign_cms:

int sign_cms(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE certificate, CK_OBJECT_HANDLE privateKey)
{
    /*************************************************************************
    * Данные для подписи                                                     *
    *************************************************************************/
    CK_BYTE data[] =
    {
        0x01, 0x00, 0x02, 0x35, 0x35,
        0x02, 0x00, 0x01, 0x01,
        0x81, 0x00, 0x09, 0x34, 0x30, 0x34, 0x34, 0x34, 0x35, 0x39, 0x39, 0x38,
        0x82, 0x00, 0x0A, 0x37, 0x37, 0x38, 0x31, 0x35, 0x36, 0x34, 0x36, 0x31, 0x31,
        0x83, 0x00, 0x13, 0x41, 0x6B, 0x74, 0x69, 0x76, 0x20, 0x52, 0x75, 0x74, 0x6F, 0x6B, 0x65, 0x6E, 0x20, 0x42, 0x61, 0x6E, 0x6B, 0x2E,
        0x84, 0x00, 0x14, 0x34, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x37, 0x36,
        0x85, 0x00, 0x0A, 0x33, 0x32, 0x32, 0x38, 0x37, 0x33, 0x36, 0x37, 0x36, 0x35,
        0x86, 0x00, 0x03, 0x52, 0x55, 0x42,
        0xFF, 0x00, 0x0D, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
    };

    CK_BYTE_PTR signature;                             // Указатель на буфер, содержащий подпись исходных данных
    CK_ULONG signatureSize;                            // Размер буфера, содержащего подпись исходных данных, в байтах
    char* signaturePem;                                // Строка с CMS в формате PEM

    CK_RV rv;
    int errorCode = 1;                                 // Флаг ошибки

    /*************************************************************************
    * Подписать данные                                                       *
    *************************************************************************/
    rv = functionListEx->C_EX_PKCS7Sign(session, data, sizeof(data), certificate,
        &signature, &signatureSize, privateKey, NULL_PTR, 0, USE_HARDWARE_HASH);
    CHECK_AND_LOG(" C_EX_PKCS7Sign", rv == CKR_OK, rvToStr(rv), exit);

        /*************************************************************************
        * Сконвертировать и распечатать буфер в формате PEM                      *
        *************************************************************************/
        GetCMSAsPEM(signature, signatureSize, &signaturePem);
        CHECK(" Get CMS in PEM format", signaturePem != NULL, free_signature);

        printf("nSignature is:n");
        printf("%sn", signaturePem);


    errorCode = 0;
    printf("Data has been signed successfully.n");

free_signature_pem:
    free(signaturePem);

    /*************************************************************************
    * Освободить память, выделенную в библиотеке                             *
    *************************************************************************/
free_signature:
    rv = functionListEx->C_EX_FreeBuffer(signature);
    CHECK_RELEASE_AND_LOG(" C_EX_FreeBuffer", rv == CKR_OK, rvToStr(rv), errorCode);

exit:
    return errorCode;
}

Создание CMS-подписи произошло вызовом всего лишь одной функции расширения C_EX_PKCS7Sign. А объект сертификата нашелся так же просто, как и объект ключа с минимальными отличиями в коде. Все это показывает, как просто и лаконично (по меркам языка C) спроектирован стандарт PKCS#11 с идеей объектного подхода.

Оцените статью
Мой сертификат
Добавить комментарий