7 сентября 2021 года мне пришло электронное письмо:
Я честно ответил, что как только освобожусь, то проведу доработку библиотеки. Тем более, что в связи с выходом новых требований, доработки требовали и другие продукты, в первую очередь утилита crypnjarmpkcs.
И вот время настало. Что же нового в этих требованиях? Первое и самое главное, с моей точки зрения, это то, что будет наведён порядок с идентификационным номером налогоплательщика (далее — ИНН) для физических и юридических лиц. Текущий ИНН (INN) с oid-ом «1.2.643.3.131.1.1» теперь однозначно закрепляется за физическими лицами с длиной в 12 десятичных цифр. Для юридических лиц вводится свой ИНН (INNLE) с oid-ом «1.2.643.100.4». Можно надеяться, что наконец-то исчезнут из тела сертификатов ИНН для юридических лиц длиной в 12 цифр, первые две из которых должны быть нулями. Вообще, я думаю, это какой-то нонсенс для российского программистского сообщества: вместо того, чтобы корректно разбирать сертификаты и строго следовать требованиям Приказа №795, что длина ИНН может быть либо 10 цифр (юридическое лицо) либо 12 цифр (физическое лицо), некая программа при разборе сертификата стала требовать ИНН в 12 цифр. А дальше пошло и поехало, вместо того чтобы привести программу в порядок, стали требовать выдачи сертификатов с полем ИНН в 12 цифр. Изменится ли что-то после выхода новой редакции? Конечно изменится, но мы ещё долго будем видеть в сертификатах старые ИНН для юридических лиц. По крайней мере, до конца срока действия (если не будет принято решение о перевыпуске) сертификатов аккредитованных удостоверяющих центров (УЦ) и корневого сертификата Минкомсвязи. Неделю назад я как физическое лицо получил в аккредитованном УЦ новый сертификат, в котором уживаются, как новые атрибуты для квалифицированного сертификата, так и старые:
В качестве нового атрибута в сертификате здесь выступает дополнение IdentificationKind, которое позволяет определить, как проходила идентификация владельца сертификата при выдачи ему сертификата. В качестве старых атрибутов, это пресловутый ИНН с двумя первыми нулями у издателя сертификата.
Аналогично ИНН, определены различные oid-ы основного государственного регистрационного номера (ОГРН) для юридический лиц и индивидуальных предпринимателей (ОГРНИП). ОГРН для юридических лиц (OGRN) имеет oid «1.2.643.100.1» и состоит из 13-ти цифр. ОГРНИП для индивидуальных предпринимателей (OGRNIP) состоит из 15-ти цифр и имеет oid «1.2.643.100.5».
А теперь вернёмся к дополнению (расширению) IdentidicationKind. Это расширение позволяет в любой момент времени узнать, как производилась идентификация личности владельца сертификата при его получении. Это дополнение имеет oid «1.2.643.100.114» и имеет значение от 0 до 3:
В случае, если идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась при его личном присутствии, дополнение identificationKind должно иметь значение 0.
В случае, если идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с использованием квалифицированной ЭП при наличии действующего квалифицированного сертификата, дополнение identificationKind должно иметь значение 1.
В случае, если идентификация заявителя — гражданина Российской Федерации при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с применением информационных технологий путем предоставления информации, указанной в документе, удостоверяющем личность гражданина Российской Федерации за пределами территории Российской Федерации, содержащем электронный носитель информации с записанными на нем персональными данными владельца паспорта, включая биометрические персональные данные, дополнение identificationKind должно иметь значение 2.
В случае, если идентификация заявителя — гражданина Российской Федерации при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с применением информационных технологий путем предоставления сведений из единой системы идентификации и аутентификации и единой биометрической системы в порядке, установленном Федеральным законом от 27 июля 2006 г. N 149-ФЗ «Об информации, информационных технологиях и о защите информации», дополнение identificationKind должно иметь значение 3.
Я свой новый сертификат получал за несколько дней до истечения срока действия предыдущего сертификата. Фактически я написал запрос на выдачу нового сертификата и подписал его ещё действующим сертификатом. Отправил его в УЦ и после процедуры проверки получил новый сертификат, которым и воспользовался для доступа в личный кабинет на сайте ГОСУСЛУГИ и уплаты налогов, чтобы спать спокойно. Всё прошло на ура. Если посмотреть на скриншот моего сертификата выше, то можно увидеть, что значение расширения IdentificationKind равно 1 (remote_cert).
При разработке или доработке программного обеспечения, работающего с квалифицированными сертификатами в свете новой редакции Приказа ФСБ №795, следует иметь в виду, что в имени (DN) владельца и издателя сертификата, являющихся юридическими лицами, сегодня может присутствовать ИНН двух видов. Это и новый INNLE с oid-ом «1.2.643.100.4» длиною 10 цифр и старый INN с oid-ом «1.2.643.3.131.1.1» длиною в 12 цифр, из которых две первые цифры нули.
С учётом сказанного и были внесены доработки в пакет fsb795 для Python и в графическую утилиту cryptoarmpkcs.
Пакет fsb795 обеспечивает доступ к сертификаты и его полям через класс Certificate:
В поле <сертификат> может быть задана переменная с телом сертификата в DER или PEM кодировках или путь к файлу с сертификатом.
Установить пакет fsb795 можно установить традиционным путём для Python:
Для учёта при разборе квалифицированного сертификата атрибутов INNLE и OGRNIP имени (в DN) издателя и/или владельца достаточно было включить их в словарь InfoMap метода
А вот для доступа к значению дополнения IdentificationKind необходимо было добавить новый метод в класс Certificate:
Вот и всё, не считая того что по ходу модификации были устранены некоторые багги. Ниже приводится пример использования пакета для разбора сертификата. Этот пример полностью раскрывает функционал пакета fsb795.
II. Графическая утилита cryptoarmpkcs
Основное назначение утилиты cryptoarmpkcs7 — это формирование запроса на квалифицированный сертификат и/или электронной подписи под документами. При этом в качестве криптографического ядра может использоваться любой криптографический токен PKCS#11 с поддержкой российской криптографии:
Для доступа к криптографическим и другим возможностях токенов утилита cryptoarmpkcs использует пакет TclPKCS11. Аналогичный пакет с именем pyp11 есть и для Python.
Оба модуля tclpkcs11 и pyp11 написаны на языке Си.
Отметим также, что для подписания документов утилита может использовать и защищенный контейнер PKCS#12. Полный функционал утилиты отображён в левой части скриншота.
Загрузить дистрибутивы утилиты cryptoarmpkcs можно здесь:
Как видим, есть и реализация утилиты на плаnформе Android:
Для того, чтобы успешно работать с новыми oid-ами (INNLE, IdentificationKind), их необходимо добавить в массив ::pki::oids пакета pki:
А вот для доступа к значению дополнения IdentificationKind по аналогии с пакетом fsb795 для Python добавили функцию idkind:
Всё это можно увидеть в исходном коде. При этом следует обратить внимание на то, что функция parse_cert в пакете pki меняется на другую, которая позволяет разбирать ГОСТ-овые сертификаты:
По ходу доработки выяснилось, что Github полностью перешёл на использование протокола tls1.3. Это значит, что для скачивания дистрибутивов напрямую из утилиты надо использовать пакет tls именно с поддержкой протокола tls1.3. Использование в утилите cryptoarmpkcs до последнего времени пакета tls версии 1.6.7 привело к тому, что скачивание дистрибутивов с Github непосредственно в утилите стало невозможным:
Пришлось заменить в дистрибутивах пакет tls на более свежий:
После этого у утилиты не возникало проблем с загрузкой дистрибутивов из репозитория Github:
Для использования утилиты в учебных целях на странице «Просмотр запроса/сертификата» добавлен функционал для выпуска сертификатов:
При этом корневой сертификат вместе с закрытым ключом должен быть упакован в защищенный контейнер PKCS#12 и находиться в «Папка для сертификатов». Сертификаты могут использоваться не только в учебных целях, но и для внутрикорпоративных целей. Корневой сертификат может быть выпущен на вкладке «Самоподписанный сертификат».
Но главное назначение утилиты это всё же формирование электронной подписи под документами, включая усиленную усовершенствованную квалифицированную подпись (CADES-XLT1).
Можно заканчивать, требования Приказа ФСБ РФ №795 в редакции от 29.01.2021 учтены в пакете fsb795 для Python и в графической утилите cryptoarmpkcs.
fsb795Было понятно, что речь идет о пакете fsb795, написанном на Python для разбора квалифицированных сертификатов. Требования к составу и форме квалифицированного сертификата установлены Приказом ФСБ России от 27.12.2011 №795. Но 29 января 2021 года в этот приказ были внесены изменения. Именно об этих изменениях мне и напомнил автор письма. Письмо я получил 7 сентября, а изменения вступили в силу 1-го сентября 2021 года. В этот период времени я был увлечён написанием статьи, связанной с пятидесятилетием окончания Казанского суворовского военного училища и выбора мною стези программиста:
Добрый день.
не планируете библиотеку подправить под свежие изменения в приказе 795 ?
Я честно ответил, что как только освобожусь, то проведу доработку библиотеки. Тем более, что в связи с выходом новых требований, доработки требовали и другие продукты, в первую очередь утилита crypnjarmpkcs.
И вот время настало. Что же нового в этих требованиях? Первое и самое главное, с моей точки зрения, это то, что будет наведён порядок с идентификационным номером налогоплательщика (далее — ИНН) для физических и юридических лиц. Текущий ИНН (INN) с oid-ом «1.2.643.3.131.1.1» теперь однозначно закрепляется за физическими лицами с длиной в 12 десятичных цифр. Для юридических лиц вводится свой ИНН (INNLE) с oid-ом «1.2.643.100.4». Можно надеяться, что наконец-то исчезнут из тела сертификатов ИНН для юридических лиц длиной в 12 цифр, первые две из которых должны быть нулями. Вообще, я думаю, это какой-то нонсенс для российского программистского сообщества: вместо того, чтобы корректно разбирать сертификаты и строго следовать требованиям Приказа №795, что длина ИНН может быть либо 10 цифр (юридическое лицо) либо 12 цифр (физическое лицо), некая программа при разборе сертификата стала требовать ИНН в 12 цифр. А дальше пошло и поехало, вместо того чтобы привести программу в порядок, стали требовать выдачи сертификатов с полем ИНН в 12 цифр. Изменится ли что-то после выхода новой редакции? Конечно изменится, но мы ещё долго будем видеть в сертификатах старые ИНН для юридических лиц. По крайней мере, до конца срока действия (если не будет принято решение о перевыпуске) сертификатов аккредитованных удостоверяющих центров (УЦ) и корневого сертификата Минкомсвязи. Неделю назад я как физическое лицо получил в аккредитованном УЦ новый сертификат, в котором уживаются, как новые атрибуты для квалифицированного сертификата, так и старые:
В качестве нового атрибута в сертификате здесь выступает дополнение IdentificationKind, которое позволяет определить, как проходила идентификация владельца сертификата при выдачи ему сертификата. В качестве старых атрибутов, это пресловутый ИНН с двумя первыми нулями у издателя сертификата.
Аналогично ИНН, определены различные oid-ы основного государственного регистрационного номера (ОГРН) для юридический лиц и индивидуальных предпринимателей (ОГРНИП). ОГРН для юридических лиц (OGRN) имеет oid «1.2.643.100.1» и состоит из 13-ти цифр. ОГРНИП для индивидуальных предпринимателей (OGRNIP) состоит из 15-ти цифр и имеет oid «1.2.643.100.5».
А теперь вернёмся к дополнению (расширению) IdentidicationKind. Это расширение позволяет в любой момент времени узнать, как производилась идентификация личности владельца сертификата при его получении. Это дополнение имеет oid «1.2.643.100.114» и имеет значение от 0 до 3:
IdentificationKind ::= INTEGER { personal(0), remote_cert(1), remote_passport(2), remote_system(3)}
В случае, если идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась при его личном присутствии, дополнение identificationKind должно иметь значение 0.
В случае, если идентификация заявителя при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с использованием квалифицированной ЭП при наличии действующего квалифицированного сертификата, дополнение identificationKind должно иметь значение 1.
В случае, если идентификация заявителя — гражданина Российской Федерации при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с применением информационных технологий путем предоставления информации, указанной в документе, удостоверяющем личность гражданина Российской Федерации за пределами территории Российской Федерации, содержащем электронный носитель информации с записанными на нем персональными данными владельца паспорта, включая биометрические персональные данные, дополнение identificationKind должно иметь значение 2.
В случае, если идентификация заявителя — гражданина Российской Федерации при выдаче сертификата ключа проверки ЭП проводилась без его личного присутствия с применением информационных технологий путем предоставления сведений из единой системы идентификации и аутентификации и единой биометрической системы в порядке, установленном Федеральным законом от 27 июля 2006 г. N 149-ФЗ «Об информации, информационных технологиях и о защите информации», дополнение identificationKind должно иметь значение 3.
Я свой новый сертификат получал за несколько дней до истечения срока действия предыдущего сертификата. Фактически я написал запрос на выдачу нового сертификата и подписал его ещё действующим сертификатом. Отправил его в УЦ и после процедуры проверки получил новый сертификат, которым и воспользовался для доступа в личный кабинет на сайте ГОСУСЛУГИ и уплаты налогов, чтобы спать спокойно. Всё прошло на ура. Если посмотреть на скриншот моего сертификата выше, то можно увидеть, что значение расширения IdentificationKind равно 1 (remote_cert).
При разработке или доработке программного обеспечения, работающего с квалифицированными сертификатами в свете новой редакции Приказа ФСБ №795, следует иметь в виду, что в имени (DN) владельца и издателя сертификата, являющихся юридическими лицами, сегодня может присутствовать ИНН двух видов. Это и новый INNLE с oid-ом «1.2.643.100.4» длиною 10 цифр и старый INN с oid-ом «1.2.643.3.131.1.1» длиною в 12 цифр, из которых две первые цифры нули.
С учётом сказанного и были внесены доработки в пакет fsb795 для Python и в графическую утилиту cryptoarmpkcs.
I. Пакет fsb795
Пакет fsb795 обеспечивает доступ к сертификаты и его полям через класс Certificate:
import os, sys
import fsb795
cert = fsb795.Certificate(<сертификат>)
…
В поле <сертификат> может быть задана переменная с телом сертификата в DER или PEM кодировках или путь к файлу с сертификатом.
Установить пакет fsb795 можно установить традиционным путём для Python:
python –m pip install fsb795
Для учёта при разборе квалифицированного сертификата атрибутов INNLE и OGRNIP имени (в DN) издателя и/или владельца достаточно было включить их в словарь InfoMap метода
parse_issuer_subject:
class Certificate:
. . .
def parse_issuer_subject (self, who):
if(self.cert == ''):
return ({})
infoMap = {
"1.2.840.113549.1.9.2": "unstructuredName",
"1.2.643.100.1": "OGRN",
"1.2.643.100.5": "OGRNIP",
"1.2.643.3.131.1.1": "INN",
"1.2.643.100.4": "INNLE",
"1.2.643.100.3": "SNILS",
"2.5.4.3": "CN",
"2.5.4.4": "SN",
"2.5.4.5": "serialNumber",
"2.5.4.42": "GN",
"1.2.840.113549.1.9.1": "E",
"2.5.4.7": "L",
"2.5.4.8": "ST",
"2.5.4.9": "street",
"2.5.4.10": "O",
"2.5.4.11": "OU",
"2.5.4.12": "title",
"2.5.4.6": "Country",
}
. . .
А вот для доступа к значению дополнения IdentificationKind необходимо было добавить новый метод в класс Certificate:
def identKind(self):
if(self.cert == ''):
return ('')
for ext in self.cert["extensions"]:
#Ищем расширение IdentificationKind
if(str(ext['extnID']) == "1.2.643.100.114"):
#Переводит из двоичной системы счисления (2) в hex
kc = ext['extnValue'].prettyPrint()
kc1 = kc[2:4]
#Проверяем tag integer
if(kc1 != '02'):
# print ('not integer')
return (-1)
#Проверяем длину
kc1 = kc[4:6]
if(kc1 != '01'):
# print ('bad length')
return (-1)
type = kc[6:8]
#Переводим в целое из 16-ной системы счисления
type = int(type, 16)
if (type > 3):
# print ('Неизвестный тип идентификации = ' + str(type))
return (-1)
return (type)
return (-1)
Вот и всё, не считая того что по ходу модификации были устранены некоторые багги. Ниже приводится пример использования пакета для разбора сертификата. Этот пример полностью раскрывает функционал пакета fsb795.
Пример использования пакета fsb795:
# -*- coding: utf-8 -*-
import os, sys
import fsb795
certpem = """
-----BEGIN CERTIFICATE-----
MIIE9TCCBKCgAwIBAgIEYYlVGzAMBggqhQMHAQEDAgUAMIIB3TELMAkGA1UEBhMC
UlUxLDAqBgNVBAgMI9Cc0L7RgdC60L7QstGB0LrQsNGPINC+0LHQu9Cw0YHRgtGM
MT8wPQYDVQQDDDbQotC10YHRgtC+0LLRi9C5INCj0LTQvtGB0YLQvtCy0LXRgNGP
0Y7RidC40Lkg0KbQtdGC0YAxPzA9BgNVBAoMNtCi0LXRgdGC0L7QstGL0Lkg0KPQ
tNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDQptC10YLRgDEXMBUGCSqGSIb3DQEJ
ARYIY2FAY2EucnUxIjAgBgNVBAcMGdCR0LXRgNC10L3QtNC10LXQsiDQu9C10YEx
KjAoBgNVBAkMIdCi0YDQvtC/0LjQvdC60LAg0Y7QttC90LDRjywg0LQuMTEcMBoG
A1UECwwT0KPRh9C10LHQvdGL0Lkg0KPQpjEZMBcGA1UEDAwQ0JTQuNGA0LXQutGC
0L7RgDEbMBkGA1UEBAwS0JHQsNC70LDQs9Cw0L3QvtCyMS4wLAYDVQQqDCXQkNC7
0LXQutGB0LDQvdC00YAg0J7RgdGC0LDQv9C+0LLQuNGHMRgwFgYFKoUDZAESDTEy
MzQ1Njc4OTAxMjMxFTATBgUqhQNkBBIKMjM0NTY3ODkwMTAeFw0yMTExMDgxNjUx
MzlaFw0yMjExMTgxNjUxMzlaMIIBbTELMAkGA1UEBhMCUlUxLDAqBgNVBAgMI9Cc
0L7RgdC60L7QstGB0LrQsNGPINC+0LHQu9Cw0YHRgtGMMUMwQQYDVQQDDDrQktC+
0YDQvtCx0YzRj9C90LjQvdC+0LIg0JjQv9C/0L7Qu9C40YIg0JzQsNGC0LLQtdC1
0LLQuNGHMSEwHwYDVQQEDBjQktC+0YDQvtCx0YzRj9C90LjQvdC+0LIxKjAoBgNV
BCoMIdCY0L/Qv9C+0LvQuNGCINCc0LDRgtCy0LXQtdCy0LjRhzEXMBUGCSqGSIb3
DQEJARYIdnZAdnYudnYxITAfBgNVBAcMGNCzLiDQp9C10YDQvdC+0LzQvtGA0YHQ
ujEsMCoGA1UECQwj0YPQuy7Qp9C10YDQvdC+0LzQvtGA0YHQutCw0Y8g0LQuMTUx
GjAYBggqhQMDgQMBARIMNDQ0NDQ0NDQ0NDQ0MRYwFAYFKoUDZAMSCzMzMzMzMzMz
MzMzMGgwIQYIKoUDBwEBAQEwFQYJKoUDBwECAQEBBggqhQMHAQECAgNDAARAvwRh
R9Lh8AF2WwiJ6ns3kdPnSBYM26gwYxaPzpSVwPOKGTeWZafBtqkXLlYreClCxgS9
Aqtwav+CijUcP+vweKOBqDCBpTAPBgNVHRMBAQAEBTADAQEAMAsGA1UdDwQEAwIE
8DBFBgUqhQNkbwQ8DDrQndCw0LjQvNC10L3QvtCy0LDQvdC40LUg0KHQmtCX0Jgg
0L/QvtC70YzQt9C+0LLQsNGC0LXQu9GPMB0GA1UdDgQWBBTQW3oAqF+nF6jwfLiR
e2vijovlqjAfBgNVHSMEGDAWgBTHGxxICwmKlpqhbZgevtL8VWD0gjAMBggqhQMH
AQEDAgUAA0EAOsbZ+ky8Acjvrys2ZenOnBFS6vfGeiXD3NSTX/4elK+kmRVbtoBz
ro9C95WRbPdJ5zn0t+/9S8op8aQVb3Op/g==
-----END CERTIFICATE-----
"""
#Если задан параметр, то читаем сертификат из файла
if len(sys.argv) == 2:
c1 = fsb795.Certificate(sys.argv[1])
else:
c1 = fsb795.Certificate(certpem)
if (c1.pyver == ''):
print('Context for certificate not create')
exit(-1)
print('=================formatCert================================')
print(c1.formatCert)
res = c1.subjectSignTool()
print('=================subjectSignTool============================')
print (res)
print('=================issuerSignTool=============================')
res1 = c1.issuerSignTool()
for key in res1:
print (key)
print('=================prettyPrint===============================')
res2 = c1.prettyPrint()
#print(res2)
print('=================classUser================================')
res3 = c1.classUser()
print (res3)
print('=================issuerCert================================')
iss, vlad_is = c1.issuerCert()
print ('vlad_is=' + str(vlad_is))
for key in iss.keys():
print (key + '=' + iss[key])
print('=================subjectCert================================')
sub, vlad_sub = c1.subjectCert()
print ('vlad_sub=' + str(vlad_sub))
for key in sub.keys():
print (key + '=' + sub[key])
print('================publicKey=================================')
key_info = c1.publicKey()
for key in key_info.keys():
print (key + '=' + key_info[key])
print('================serialNumber===============================')
print(c1.serialNumber())
print('================validityCert================================')
valid = c1.validityCert()
print(valid['not_after'])
print(valid['not_before'])
print('================signatureCert=================================')
algosign, value = c1.signatureCert()
print(algosign)
print(value)
print('================KeyUsage=================================')
ku = c1.KeyUsage()
for key in ku:
print (key)
print('================IdentificationKind============================')
idkind = c1.identKind()
print('type identification kind=' + str(idkind))
print('================Private Key Usage Period==================')
period = c1.keyPeriod()
print('not_before=' + str(period['not_before']))
print('not_after=' + str(period['not_after']))
print('================END=================================')
import os, sys
import fsb795
certpem = """
-----BEGIN CERTIFICATE-----
MIIE9TCCBKCgAwIBAgIEYYlVGzAMBggqhQMHAQEDAgUAMIIB3TELMAkGA1UEBhMC
UlUxLDAqBgNVBAgMI9Cc0L7RgdC60L7QstGB0LrQsNGPINC+0LHQu9Cw0YHRgtGM
MT8wPQYDVQQDDDbQotC10YHRgtC+0LLRi9C5INCj0LTQvtGB0YLQvtCy0LXRgNGP
0Y7RidC40Lkg0KbQtdGC0YAxPzA9BgNVBAoMNtCi0LXRgdGC0L7QstGL0Lkg0KPQ
tNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDQptC10YLRgDEXMBUGCSqGSIb3DQEJ
ARYIY2FAY2EucnUxIjAgBgNVBAcMGdCR0LXRgNC10L3QtNC10LXQsiDQu9C10YEx
KjAoBgNVBAkMIdCi0YDQvtC/0LjQvdC60LAg0Y7QttC90LDRjywg0LQuMTEcMBoG
A1UECwwT0KPRh9C10LHQvdGL0Lkg0KPQpjEZMBcGA1UEDAwQ0JTQuNGA0LXQutGC
0L7RgDEbMBkGA1UEBAwS0JHQsNC70LDQs9Cw0L3QvtCyMS4wLAYDVQQqDCXQkNC7
0LXQutGB0LDQvdC00YAg0J7RgdGC0LDQv9C+0LLQuNGHMRgwFgYFKoUDZAESDTEy
MzQ1Njc4OTAxMjMxFTATBgUqhQNkBBIKMjM0NTY3ODkwMTAeFw0yMTExMDgxNjUx
MzlaFw0yMjExMTgxNjUxMzlaMIIBbTELMAkGA1UEBhMCUlUxLDAqBgNVBAgMI9Cc
0L7RgdC60L7QstGB0LrQsNGPINC+0LHQu9Cw0YHRgtGMMUMwQQYDVQQDDDrQktC+
0YDQvtCx0YzRj9C90LjQvdC+0LIg0JjQv9C/0L7Qu9C40YIg0JzQsNGC0LLQtdC1
0LLQuNGHMSEwHwYDVQQEDBjQktC+0YDQvtCx0YzRj9C90LjQvdC+0LIxKjAoBgNV
BCoMIdCY0L/Qv9C+0LvQuNGCINCc0LDRgtCy0LXQtdCy0LjRhzEXMBUGCSqGSIb3
DQEJARYIdnZAdnYudnYxITAfBgNVBAcMGNCzLiDQp9C10YDQvdC+0LzQvtGA0YHQ
ujEsMCoGA1UECQwj0YPQuy7Qp9C10YDQvdC+0LzQvtGA0YHQutCw0Y8g0LQuMTUx
GjAYBggqhQMDgQMBARIMNDQ0NDQ0NDQ0NDQ0MRYwFAYFKoUDZAMSCzMzMzMzMzMz
MzMzMGgwIQYIKoUDBwEBAQEwFQYJKoUDBwECAQEBBggqhQMHAQECAgNDAARAvwRh
R9Lh8AF2WwiJ6ns3kdPnSBYM26gwYxaPzpSVwPOKGTeWZafBtqkXLlYreClCxgS9
Aqtwav+CijUcP+vweKOBqDCBpTAPBgNVHRMBAQAEBTADAQEAMAsGA1UdDwQEAwIE
8DBFBgUqhQNkbwQ8DDrQndCw0LjQvNC10L3QvtCy0LDQvdC40LUg0KHQmtCX0Jgg
0L/QvtC70YzQt9C+0LLQsNGC0LXQu9GPMB0GA1UdDgQWBBTQW3oAqF+nF6jwfLiR
e2vijovlqjAfBgNVHSMEGDAWgBTHGxxICwmKlpqhbZgevtL8VWD0gjAMBggqhQMH
AQEDAgUAA0EAOsbZ+ky8Acjvrys2ZenOnBFS6vfGeiXD3NSTX/4elK+kmRVbtoBz
ro9C95WRbPdJ5zn0t+/9S8op8aQVb3Op/g==
-----END CERTIFICATE-----
"""
#Если задан параметр, то читаем сертификат из файла
if len(sys.argv) == 2:
c1 = fsb795.Certificate(sys.argv[1])
else:
c1 = fsb795.Certificate(certpem)
if (c1.pyver == ''):
print('Context for certificate not create')
exit(-1)
print('=================formatCert================================')
print(c1.formatCert)
res = c1.subjectSignTool()
print('=================subjectSignTool============================')
print (res)
print('=================issuerSignTool=============================')
res1 = c1.issuerSignTool()
for key in res1:
print (key)
print('=================prettyPrint===============================')
res2 = c1.prettyPrint()
#print(res2)
print('=================classUser================================')
res3 = c1.classUser()
print (res3)
print('=================issuerCert================================')
iss, vlad_is = c1.issuerCert()
print ('vlad_is=' + str(vlad_is))
for key in iss.keys():
print (key + '=' + iss[key])
print('=================subjectCert================================')
sub, vlad_sub = c1.subjectCert()
print ('vlad_sub=' + str(vlad_sub))
for key in sub.keys():
print (key + '=' + sub[key])
print('================publicKey=================================')
key_info = c1.publicKey()
for key in key_info.keys():
print (key + '=' + key_info[key])
print('================serialNumber===============================')
print(c1.serialNumber())
print('================validityCert================================')
valid = c1.validityCert()
print(valid['not_after'])
print(valid['not_before'])
print('================signatureCert=================================')
algosign, value = c1.signatureCert()
print(algosign)
print(value)
print('================KeyUsage=================================')
ku = c1.KeyUsage()
for key in ku:
print (key)
print('================IdentificationKind============================')
idkind = c1.identKind()
print('type identification kind=' + str(idkind))
print('================Private Key Usage Period==================')
period = c1.keyPeriod()
print('not_before=' + str(period['not_before']))
print('not_after=' + str(period['not_after']))
print('================END=================================')
II. Графическая утилита cryptoarmpkcs
Основное назначение утилиты cryptoarmpkcs7 — это формирование запроса на квалифицированный сертификат и/или электронной подписи под документами. При этом в качестве криптографического ядра может использоваться любой криптографический токен PKCS#11 с поддержкой российской криптографии:
Для доступа к криптографическим и другим возможностях токенов утилита cryptoarmpkcs использует пакет TclPKCS11. Аналогичный пакет с именем pyp11 есть и для Python.
Оба модуля tclpkcs11 и pyp11 написаны на языке Си.
Отметим также, что для подписания документов утилита может использовать и защищенный контейнер PKCS#12. Полный функционал утилиты отображён в левой части скриншота.
Загрузить дистрибутивы утилиты cryptoarmpkcs можно здесь:
- OS X
- Linux64
- Linux32
- Win64
- Win32
- Android
Как видим, есть и реализация утилиты на плаnформе Android:
Для того, чтобы успешно работать с новыми oid-ами (INNLE, IdentificationKind), их необходимо добавить в массив ::pki::oids пакета pki:
…
package require pki
…
set ::pki::oids(1.2.643.100.1) "OGRN"
#Для физическлого лица
set ::pki::oids(1.2.643.3.131.1.1) "INN"
set ::pki::oids(1.2.643.100.3) "SNILS"
#ВВЕДЕНЫ Приказом ФСБ России от 29.01.2021 N31
#Для юридического лица
set ::pki::oids(1.2.643.100.4) "INNLE"
#Для ИП
set ::pki::oids(1.2.643.100.5) "OGRNIP"
#IdentificationKind - как выдавался сертификат
#set ::pki::oids(1.2.643.100.114) "IDKIND"
А вот для доступа к значению дополнения IdentificationKind по аналогии с пакетом fsb795 для Python добавили функцию idkind:
proc idkind {idkind_hex} {
set ret ""
set kind [binary format H* $idkind_hex]
::asn::asnGetInteger kind idk
switch $idk {
0 { set ret [lindex $::listkind 0]}
1 { set ret [lindex $::listkind 1]}
2 { set ret [lindex $::listkind 2]}
3 { set ret [lindex $::listkind 3]}
default {
set ret "$idk - неизвестный тип идентификации"
}
}
return $ret
}
Всё это можно увидеть в исходном коде. При этом следует обратить внимание на то, что функция parse_cert в пакете pki меняется на другую, которая позволяет разбирать ГОСТ-овые сертификаты:
. . .
package require pki
#удаляем родную функцию
rename ::pki::x509::parse_cert ::pki::x509::parse_cert_old
#добавляем свою функцию
proc ::pki::x509::parse_cert {cert} {
array set parsed_cert [::pki::_parse_pem $cert "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"]
set cert_seq $parsed_cert(data)
array set ret [list]
. .
return [array get ret]
}
. . .
По ходу доработки выяснилось, что Github полностью перешёл на использование протокола tls1.3. Это значит, что для скачивания дистрибутивов напрямую из утилиты надо использовать пакет tls именно с поддержкой протокола tls1.3. Использование в утилите cryptoarmpkcs до последнего времени пакета tls версии 1.6.7 привело к тому, что скачивание дистрибутивов с Github непосредственно в утилите стало невозможным:
Пришлось заменить в дистрибутивах пакет tls на более свежий:
После этого у утилиты не возникало проблем с загрузкой дистрибутивов из репозитория Github:
Для использования утилиты в учебных целях на странице «Просмотр запроса/сертификата» добавлен функционал для выпуска сертификатов:
При этом корневой сертификат вместе с закрытым ключом должен быть упакован в защищенный контейнер PKCS#12 и находиться в «Папка для сертификатов». Сертификаты могут использоваться не только в учебных целях, но и для внутрикорпоративных целей. Корневой сертификат может быть выпущен на вкладке «Самоподписанный сертификат».
Но главное назначение утилиты это всё же формирование электронной подписи под документами, включая усиленную усовершенствованную квалифицированную подпись (CADES-XLT1).
Можно заканчивать, требования Приказа ФСБ РФ №795 в редакции от 29.01.2021 учтены в пакете fsb795 для Python и в графической утилите cryptoarmpkcs.