Разбираем и просматриваем квалифицированные сертификаты средствами Python/Tkinter

    Квалифицированные сертификаты быстро стали неотъемлемой частью повседневной жизни. И все больше людей хотят увидеть этого «зверя» изнутри. Это с одной стороны. А с другой стороны разрабатывается все больше приложений, в которых задействуется информация иэ этих сертификатов. И это не только атрибуты ИНН или ОГРН владельца или издателя сертификата. Это может быть и информация о том какой криптопровайдер использован владельцем сертификата (атрибут subjectSignTool) для генерации закрытого ключа или на базе каких сертифицированных средств создан удостоверяющий центр (УЦ), выпустивший тот или иной сертификат. И если написать программку, которая будет анализировать выпускаемые сертификаты, то можно будут собрать интересную статистику по тому какие СКЗИ используют владельцы сертификатов и на базе каких (правда это менее интересно) сертифицированных (или несертифицированных) средств развернуты УЦ (атрибут issuerSignTools):



    На просторах Хабра уже предпринималась успешная попытка разобрать квалифицированный сертификат. К сожалению, разбор коснулся только получения атрибутов ИНН, ОГРН и СНИЛС, входящие в состав отличительного имени DN (Distinguished Name). Хотя, почему к сожалению? Перед автором стояла конкретная задача и она была решена. Мы же хотим получить доступ к атрибутам квалифицированного сертификата через Python и дать графическую утилиту для их просмотра.

    Для доступа к атрибутам сертификата будем использовать пакет fsb795. Пакет доступен как для Pytho2, так и для Python3, как для Linux, так и для Windows. Для его установки достаточно выполнить традиционную команду:

    # python -m pip install fsb795
    Collecting fsb795
    Requirement already satisfied: pyasn1-modules>=0.2.2 in /usr/lib/python2.7/site-packages (from fsb795) (0.2.2)
    Collecting pyasn1>=0.4.4 (from fsb795)
      Using cached https://files.pythonhosted.org/packages/d1/a1/7790cc85db38daa874f6a2e6308131b9953feb1367f2ae2d1123bb93a9f5/pyasn1-0.4.4-py2.py3-none-any.whl
    Requirement already satisfied: six in /usr/lib/python2.7/site-packages (from fsb795) (1.11.0)
    Installing collected packages: pyasn1, fsb795
    Successfully installed fsb795-1.5.2 pyasn1-0.4.4
    [root@localhost GCryptGOST]# 

    Пакет fsb795 необходимы пакеты pyasn1 и pyasn1-modules. Поэтому если они не установлены, то будет предпринята попытка их установить.

    Для python3 эта команда выглядит следующим образом:

    # python -m pip install fsb795
    ...
    #

    Можно также скачать установочные пакеты python3 и python2 и локально их установить.
    Название пакета, по аналогии с модулями из пакета pyasn1-modules, например, rfc2459 и т.д., указывает на то, что он предназначен для работы с сертификатами, соответствующими требованиям Приказа ФСБ РФ от 27 декабря 2011 г. № 795 «Об утверждении требований к форме квалифицированного сертификата...».

    Доступ к сертификату в пакете fsb795 реализован через класс Certificate:

    #  -*- coding: utf-8 -*-
    import os, sys
    import pyasn1
    import binascii
    import six
    from pyasn1_modules import rfc2459, pem
    from pyasn1.codec.der import decoder
    from datetime import datetime, timedelta
    
    class Certificate:
    #Атрибуты класса
      cert_full = ''
      cert = ''
      pyver = ''
      formatCert = ''
      def __init__ (self,fileorstr):
    #Проверка наличия файла с сертификатом
        if not os.path.exists(fileorstr):
    #Если файла нет, то предполагается, что это может быть
    #строка с сертификатом в PEM-формате
            strcert = fileorstr.strip('\n')
            if (strcert[0:27] != '-----BEGIN CERTIFICATE-----'):
        	    return
            idx, substrate = pem.readPemBlocksFromFile(six.StringIO(
    	    strcert), ('-----BEGIN CERTIFICATE-----',
                        '-----END CERTIFICATE-----')
    	)
            self.pyver = sys.version[0]
            try:
        	    self.cert_full, rest = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())
        	    self.cert = self.cert_full["tbsCertificate"]
        	    self.formatCert = 'PEM'
            except:
                self.pyver = ''
                self.formatCert = ''
            return
    #Сертификат в фвйле
    #В атрибут self.pyver заносится версия python
        self.pyver = sys.version[0]
        filename = fileorstr
        if (self.pyver == '2'):
            if sys.platform != "win32":
                filename = filename.encode("UTF-8")
            else:
                filename = filename.encode("CP1251")
    #Проверяем на DER
        file1 = open(filename, "rb")
        substrate = file1.read()
        if (self.pyver == '2'):
                b0 = ord(substrate[0])
                b1 = ord(substrate[1])
        else:
                b0 = substrate[0]
                b1 = substrate[1]
    #Проверка на PEM/DER, наличие последовательности 0x30, длина сертификата не может быть меньше 127 байт
        if (b0 == 48 and b1 > 128) :
        	self.formatCert = 'DER'
        else:
            self.formatCert = 'PEM'
            file1 = open(filename, "r")
            idx, substrate = pem.readPemBlocksFromFile(
        	    file1, ('-----BEGIN CERTIFICATE-----',
                    '-----END CERTIFICATE-----')
            )
        file1.close()
        try:
            self.cert_full, rest = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())
            self.cert = self.cert_full["tbsCertificate"]
        except:
            self.pyver = ''
            self.formatCert = ''
    #Методы класса для доступа к атрибутам сертификата
      def subjectSignTool(self):
     . . .
    #Тест, запускаемый из командной строки
    if __name__ == "__main__":
     . . .

    Для создании экземпляра объекта для конкретного сертификата достаточно выполнить следующий оператор:

    $ python
    Python 2.7.15 (default, May 23 2018, 14:20:56) 
    [GCC 5.4.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>import fsb795
    >>tek_cert = fsb795.Certificate(<файл/строка с сертификатом>)
    >>
    

    В качестве параметра при создании экземпляра класса указывается сертификат, который может находится либо в файле формата PEM или DER или быть строкой в формате PEM.

    После создания каждый экземпляр имеет четыре атрибута: pyver, formatCert, cert_full и cert.
    По атрибуту pyver можно проверить как прошло распарсивание сертификата. Если pyver равен пустой строке, то файл или строка не содержит сертификата. В противном случае атрибут pyver содержит версию языка python:

    >>> c1=fsb795.Certificate('Эта строка не может быть сертификатом') 
    >>> if (c1.pyver == ''):                        
    ...    print  ('Вы не предоставили сертификат')    
    ...  
    Вы не предоставили сертификат 
    >>> c2 = fsb795.Certificate('/home/a513/cert_nss.der') 
    >>> if (c2.pyver != ""): 
    ...    print(c2.pyver) 
    ...  
    2 
    >>> print(c2.formatCert) 
    DER 
    >>>

    Атрибут formatCert при успешном создании экземпляра класса Certificate содержит тип формата файла/строки с сертификатом. Это может быть PEM или DER. Зачем этот атрибут нужен станет ясно ниже.

    Пакет fsb795 создавался с использованием пакета pyasn1. Итак, осталось нерассмотренными два атрибута. В атрибуте cert хранится tbs-сертификат, готовый к использованию с пакетом pyasn1. Другой атрибут cert_full хранит весь декодированный сертификат с учетом rfc2459. Покажем, как можно получить алгоритм публичного ключа, имея атрибут cert и подключенный пакет pyasn1:

    >>> pubkey = c2.cert['subjectPublicKeyInfo']
    >>> ff = pubkey['algorithm']
    >>> ff1 = ff['algorithm']
    >>> print (ff1) 
    1.2.643.2.2.19 
    >>>

    В конце можно будет оценить возможности пакета fsb795 по получению информации о публичном ключе квалифицированного сертификата.

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

    >>> c3 = fsb795.Certificate('cert.der')                 
    >>> key_info=c3.publicKey() 
    >>> for opt in key_info.keys():
    ...   val = str(key_info[opt])    
    ...   print (opt + '=' + val)     
    ...  
    curve=1.2.643.2.2.36.0 
    hash=1.2.643.2.2.30.1 
    valuepk=5b785f86f0dd5316ba37c8440e398e83f2ec0c34478f90da9c0c8046d341ff66f9044cd00a0e25530
    acefd51e6be852dbecacbaabc55e807be8e1f861658bd58 
    algo=1.2.643.2.2.19 
    >>>
    

    На данный момент класс Certificate содержит следующие методы:

    • subjectSignTool() – возвращает строку с наименованием СКЗИ владельца сертификата;
    • issuerSignTool() – возвращает список из четырех элементов с информацией криптографических средствах издателя сертификата;
    • classUser() – возвращает строку с oid-ами классов защищенности СКЗИ владельца сертификата, разделенными символами ";;";
    • issuerCert() – возвращает словарь с полями и значениями отличительного имени DN издателя сертификата и число, определяющее принадлежность сертификата (2 – юридическое лицо);
    • subjectCert() – возвращает словарь с полями и значениями отличительного имени DN владельца сертификата и число, определяющее принадлежность сертификата (2 – юридическое лицо);
    • publicKey() – возвращает словарь, содержащий значение ключа ('valuepk') и параметры ключа ('curve' и 'hash');
    • signatureCert – возвращает два значения: алгоритм подписи и значение подписи;
    • validityCert – возвращает словарь с двумя ключами 'not_after' и 'not_before';
    • keyUsage() – возвращает список областей действия ключа;
    • serialNumber() – возвращает серийный номер сертификата в десятичном виде;
    • prettyPrint() – возвращает строку с 'распечаткой' сертификата в терминах pyasn1 (self.cert_full.prettyPrint()).

    В спойлере лежит тестовый пример, который наглядно демонстрирует работу этих методов.

    Тест test795.py для тестирования пакета fsb795
    import fsb795
    
    certpem = """
    -----BEGIN CERTIFICATE-----
    MIIG3DCCBougAwIBAgIKE8/KkAAAAAAC4zAIBgYqhQMCAgMwggFKMR4wHAYJKoZI
    hvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYDVQQIDBM3
    NyDQsy4g0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxPzA9BgNV
    BAkMNjEyNTM3NSDQsy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXRgNGB0LrQ
    sNGPLCDQtC4gNzEsMCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfRjCDQoNC+
    0YHRgdC40LgxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqFAwOBAwEB
    EgwwMDc3MTA0NzQzNzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg0YPQtNC+
    0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMB4XDTE4MDcwOTE1MjYy
    NFoXDTI3MDcwOTE1MjYyNFowggFVMR4wHAYJKoZIhvcNAQkBFg9jb250YWN0QGVr
    ZXkucnUxITAfBgNVBAMMGNCe0J7QniDCq9CV0LrQtdC5INCj0KbCuzEwMC4GA1UE
    Cwwn0KPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMSEwHwYD
    VQQKDBjQntCe0J4gwqvQldC60LXQuSDQo9CmwrsxCzAJBgNVBAYTAlJVMRgwFgYD
    VQQIDA83NyDQnNC+0YHQutCy0LAxRDBCBgNVBAkMO9Cj0JvQmNCm0JAg0JjQm9Cs
    0JjQndCa0JAsINCULjQsINCQ0J3QotCgIDMg0K3Qojsg0J/QntCcLjk0MRgwFgYD
    VQQHDA/Qsy7QnNC+0YHQutCy0LAxGDAWBgUqhQNkARINMTE0Nzc0NjcxNDYzMTEa
    MBgGCCqFAwOBAwEBEgwwMDc3MTA5NjQzNDgwYzAcBgYqhQMCAhMwEgYHKoUDAgIk
    AAYHKoUDAgIeAQNDAARAW3hfhvDdUxa6N8hEDjmOg/LsDDRHj5DanAyARtNB/2b5
    BEzQCg4lUwrO/VHmvoUtvsrLqrxV6Ae+jh+GFli9WKOCA0AwggM8MBIGA1UdEwEB
    /wQIMAYBAf8CAQAwHQYDVR0OBBYEFMQYnG5GfYRnj2ehEQ5tv8Fso/qBMAsGA1Ud
    DwQEAwIBRjAdBgNVHSAEFjAUMAgGBiqFA2RxATAIBgYqhQNkcQIwKAYFKoUDZG8E
    Hwwd0KHQmtCX0JggwqvQm9CY0KDQodCh0JstQ1NQwrswggGLBgNVHSMEggGCMIIB
    foAUi5g7iRhR6O+cAni46sjUILJVyV2hggFSpIIBTjCCAUoxHjAcBgkqhkiG9w0B
    CQEWD2RpdEBtaW5zdnlhei5ydTELMAkGA1UEBhMCUlUxHDAaBgNVBAgMEzc3INCz
    LiDQnNC+0YHQutCy0LAxFTATBgNVBAcMDNCc0L7RgdC60LLQsDE/MD0GA1UECQw2
    MTI1Mzc1INCzLiDQnNC+0YHQutCy0LAsINGD0LsuINCi0LLQtdGA0YHQutCw0Y8s
    INC0LiA3MSwwKgYDVQQKDCPQnNC40L3QutC+0LzRgdCy0Y/Qt9GMINCg0L7RgdGB
    0LjQuDEYMBYGBSqFA2QBEg0xMDQ3NzAyMDI2NzAxMRowGAYIKoUDA4EDAQESDDAw
    NzcxMDQ3NDM3NTFBMD8GA1UEAww40JPQvtC70L7QstC90L7QuSDRg9C00L7RgdGC
    0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YCCEDRoHkDLQe8zqaC3yHaSmikw
    WQYDVR0fBFIwUDAmoCSgIoYgaHR0cDovL3Jvc3RlbGVjb20ucnUvY2RwL2d1Yy5j
    cmwwJqAkoCKGIGh0dHA6Ly9yZWVzdHItcGtpLnJ1L2NkcC9ndWMuY3JsMIHGBgUq
    hQNkcASBvDCBuQwj0J/QkNCa0JwgwqvQmtGA0LjQv9GC0L7Qn9GA0L4gSFNNwrsM
    INCf0JDQmiDCq9CT0L7Qu9C+0LLQvdC+0Lkg0KPQpsK7DDbQl9Cw0LrQu9GO0YfQ
    tdC90LjQtSDihJYgMTQ5LzMvMi8yLTk5OSDQvtGCIDA1LjA3LjIwMTIMONCX0LDQ
    utC70Y7Rh9C10L3QuNC1IOKEliAxNDkvNy8xLzQvMi02MDMg0L7RgiAwNi4wNy4y
    MDEyMAgGBiqFAwICAwNBALvjFGhdFE9llvlvKeQmZmkI5J+yO2jFWTh8nXPjIpiL
    OutUew2hIZv15pJ1QM/VgRO3BTBGDOoIrq8LvgC+3kA=
    -----END CERTIFICATE-----
    """
    
    #c1 = fsb795.Certificate('OOO_VOLGA.der')
    #c1 = fsb795.Certificate('cert.der')
    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()
    print (res1[0])
    print (res1[1])
    print (res1[2])
    print (res1[3])
    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()
    print(key_info['curve'])
    print(key_info['hash'])
    print(key_info['valuepk'])
    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(ku)
    print('================END=================================')
    


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

    $python test795.py

    Имея в своем распоряжении пакет fsb795 было естественным написать на языке python самодостаточную платформонезависимую графическую утилиту для просмотра квалифицированных сертификатов. В качестве графической поддержки использован пакет Tkinter:



    Утилита viewCertFL63 имеет три вкладки. На вкладке «О сертификате » помимо прочего отображается текущее время. Мы еще вернемся к нему ниже. Для выбора сертификата достаточно нажать кнопку «Выбрать»:



    Обратите внимание на кнопку (те кто работают на Windows этой кнопки не увидят), она позволяет скрывать так называемые невидимые файлы/каталоги (hidden). Для того чтобы эта кнопка появилась достаточно выполнить следующие команды:

    if sys.platform != "win32":
            root.tk.call('set', '::tk::dialog::file::showHiddenBtn', '1')
            root.tk.call('set', '::tk::dialog::file::showHiddenVar', '0')
    

    Очень полезная кнопка. Итак, после выбора сертификата вкладка «О сертификате» примет вид:



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



    И, наконец, третья вкладка «Текст». В этой вкладке отображается содержимое всего сертификата:



    Для просмотра сертификата можно использовать не только Python (кнопка «Python»), то и утилиты openssl и pp из состава Network Serurity Services (NSS). Если у кого-то не окажется этих утилит, то первую можно получить, собрав openssl с поддержкой российской криптографии. Что касается второй утилиты, то можно заглянуть вот сюда:



    Выше мы упоминали про атрибут formatCert класса Certificate пакета fsb795. Так вот значение этого атрибута нам необходимо для указания формата файла с сертификатом при запуске той или утилиты. Например, вызов утилиты pp при формате файле PEM выглядит следующим образом:

    $pp –t c –u –a –i <файл сертификата>

    Параметр «-a» и указывает на формат файла PEM. Для формата DER он не указывается.
    Аналогичным образом задается и параметр "–inform " для openssl.
    Кнопка «Утилита» служит для указания пути к утилитам openssl или pp.
    Дистрибутивы утилиты viewCertFL63 находятся здесь.
    Сборка дистрибутивов была сделана с использованием пакета pyinstaller:

    $python pyinstaller.py --noconsole -F viewCertFL63.py
    
    Поделиться публикацией

    Комментарии 24

      –2
      Код — жуть. На PEP8 и юнит тесты наплевали с высокой колокольни. Не стыдно такое выкладывать?
        +2
        Нормальный код. Понятный. Мне бы было не стыдно.
        Вы слишком перфекционист, не надо так.
          –1
          Пардон, но нет. Для студента-второкурсника — нормальный. Для профессионала, который в разработке не один год (судя по профилю автора), это позорище. Я понимаю, когда люди пишут для себя, для себя можно гавнякать сколько угодно, но выкладывать такое в пакет для общего пользования лично я бы постеснялся. Ладно PEP, но тесты-то, тем более, что основа для тестов в самом коде как раз присутствует.
          PS: И нет, не перфекционизм совершенно, а элементарные стандарты. Вы не знакомы?
            +1
            На мой личный взгляд, работающий пакет без тестов неизмеримо лучше идеально_прекрасного_покрытого_тестами_и_полностью_соответствующего_пеп_стандартам, но несуществующего.
              0
              Зря вы так. Обычно как раз тесты дают до некоторой степени уверенность в работоспособности кода, тем более кода на таких языках, как питон. Без тестов автору можно разве что поверить на слово.
                –2
                Ну тогда и не надейтесь, что кто-нибудь захочет доработать ваш говнокод. Такой код живёт до тех пор автор заинтересован или жив. Потом это никто в здравом уме поддерживать не станет, проще переписать с нуля.
                  +2

                  Да автор вроде и не предлагает дорабатывать. Тем людям с манией величия)

            +2

            А что такое PEP8? Без него никак код на Python-e из командной строки Linux писать нельзя? То есть у меня как у той обезьяны с "Войной и миром" получилось. По теории вероятности тыкал-тыкал и столько имоций вызвал. А какие юнит тесты для графической утилиты нужно написать? Запускаешь и смотришь то она показывает или нет. Для пакета fsb795 тоже из командной строки его запускаешь и видишь тестовый результат:


            $python fsb795.py
            ...

            Но за критику спасибо. Буду знать, что главное одежка.

              0
              А что такое PEP8? Без него никак код на Python-e из командной строки Linux писать нельзя?

              Т.е., вы кодите на Python, мало того, вы получившийся результат выкладываете на обозрение и при этом специально игнорируете «Style Guide for Python Code»?
                +1

                Не пойму в чем игнорирование, если и python2 и python3 с удовольствием принимают этот код?

                  0
                  В том, что вы показываете этот код другим людям, а не только интерпретаторам python.
                    +1

                    Не понял! Я вам ничего не показывал, вы сами смотрите, это ваш выбор.
                    А другие спасибо говорят и я на них ориентируюсь.
                    Хорошо, в следующий раз учту PEP8 по максимуму. Но вы не назвали ни одного пункта из этих РЕКОМЕНДАЦИЙ, который был бы серьезно нарушен.
                    А задача-то решена или нет? Работает или нет?

                      –2
                      Я вам ничего не показывал, вы сами смотрите, это ваш выбор.

                      Уберите тогда вставки кода из статьи, вы же его не показываете, тогда и смотреть не будем?

                      А задача-то решена или нет?

                      Какая?

                      Работает или нет?

                      Вам про тесты уже написали.

                      А другие спасибо говорят и я на них ориентируюсь.

                      А может вы им зп платите, продолжайте ориентироваться.
                        0
                        Но вы не назвали ни одного пункта из этих РЕКОМЕНДАЦИЙ, который был бы серьезно нарушен.

                        Отступы, то 2 пробела, то 4, даже не буду это комментировать.

                        Не вычистили непонятные комментарии из кода, не убрали отладочные принты, спасибо что хоть закомментировали. Вы же в публичный репозиторий выложили, неужели даже какой-то попытки ревью не было?
                          +1
                          flake8 my_python_script.py does the job.
                    0
                    Для вашей графической утилиты вам решать какие тесты для нее писать и писать ли вообще. Я говорил про пакет, который вы отправили в репозиторий. Вот для него тесты желательны. Вы действительно не понимаете смысл автоматических тестов? Вы пакет выложили для того, чтобы потешить свое самолюбие, или для пользы всеобщей? Вот представьте, что кто-то (допустим, я) решил воспользоваться вашим пакетом в своей работе. Тестов у вас нет. Как убедиться, что пакет хотя бы отчасти работает правильно? Мамой клянетесь? Это несерьезно.
                      +1

                      Я уже ответил:


                      fsb795.py
                      #  -*- coding: utf-8 -*-
                      import os, sys
                      import pyasn1
                      import binascii
                      import six
                      from pyasn1_modules import rfc2459, pem
                      from pyasn1.codec.der import decoder
                      from datetime import datetime, timedelta
                      
                      class Certificate:
                        cert_full = ''
                        cert = ''
                        pyver = ''
                        formatCert = ''
                        def __init__ (self,fileorstr):
                          if not os.path.exists(fileorstr):
                      #Сертификат в PEM-кодировке из строки
                              strcert = fileorstr.strip('\n')
                              if (strcert[0:27] != '-----BEGIN CERTIFICATE-----'):
                                  return
                              idx, substrate = pem.readPemBlocksFromFile(six.StringIO(
                              strcert), ('-----BEGIN CERTIFICATE-----',
                                          '-----END CERTIFICATE-----')
                          )
                              self.pyver = sys.version[0]
                              try:
                                  self.cert_full, rest = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())
                                  self.cert = self.cert_full["tbsCertificate"]
                                  self.formatCert = 'PEM'
                      #           print (self.cert_full["signatureAlgorithm"])
                      #           print (self.cert_full["signatureAlgorithm"]['algorithm'])
                      #           print (self.cert_full["signatureValue"].prettyPrint())
                              except:
                                  self.pyver = ''
                                  self.formatCert = ''
                              return
                      
                          self.pyver = sys.version[0]
                          filename = fileorstr
                          if (self.pyver == '2'):
                              if sys.platform != "win32":
                                  filename = filename.encode("UTF-8")
                              else:
                                  filename = filename.encode("CP1251")
                      #Проверяем на DER
                          file1 = open(filename, "rb")
                          substrate = file1.read()
                          if (self.pyver == '2'):
                                  b0 = ord(substrate[0])
                                  b1 = ord(substrate[1])
                          else:
                                  b0 = substrate[0]
                                  b1 = substrate[1]
                      #Проверка наличия последовательности 0x30, длина сертификата не может быть меньше 127 байт
                          if (b0 == 48 and b1 > 128) :
                              self.formatCert = 'DER'
                          else:
                              self.formatCert = 'PEM'
                              file1 = open(filename, "r")
                              idx, substrate = pem.readPemBlocksFromFile(
                                  file1, ('-----BEGIN CERTIFICATE-----',
                                      '-----END CERTIFICATE-----')
                              )
                          file1.close()
                          try:
                              self.cert_full, rest = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())
                              self.cert = self.cert_full["tbsCertificate"]
                          except:
                              self.pyver = ''
                              self.formatCert = ''
                      
                        def notation_OID(self, oidhex_string):
                          ''' Input is a hex string and as one byte is 2 charecters i take an 
                              empty list and insert 2 characters per element of the list.
                              So for a string 'DEADBEEF' it would be ['DE','AD','BE,'EF']. '''
                          hex_list = []
                          for char in range(0, len(oidhex_string), 2):
                              hex_list.append(oidhex_string[char]+oidhex_string[char+1])
                      
                          ''' I have deleted the first two element of the list as my hex string
                              includes the standard OID tag '06' and the OID length '0D'. 
                              These values are not required for the calculation as i've used 
                              absolute OID and not using any ASN.1 modules. Can be removed if you
                              have only the data part of the OID in hex string. '''
                          del hex_list[0]
                          del hex_list[0]
                      
                          # An empty string to append the value of the OID in standard notation after
                          # processing each element of the list.
                          OID_str = ''
                      
                          # Convert the list with hex data in str format to int format for
                          # calculations.
                          for element in range(len(hex_list)):
                              hex_list[element] = int(hex_list[element], 16)
                      
                          # Convert the OID to its standard notation. Sourced from code in other
                          # languages and adapted for python.
                      
                          # The first two digits of the OID are calculated differently from the rest.
                          x = int(hex_list[0] / 40)
                          y = int(hex_list[0] % 40)
                          if x > 2:
                              y += (x-2)*40
                              x = 2
                      
                          OID_str += str(x)+'.'+str(y)
                      
                          val = 0
                          for byte in range(1, len(hex_list)):
                              val = ((val << 7) | ((hex_list[byte] & 0x7F)))
                              if (hex_list[byte] & 0x80) != 0x80:
                                  OID_str += "."+str(val)
                                  val = 0
                      
                          # print the OID in dot notation.
                          return (OID_str)
                      
                        def subjectSignTool(self):
                          if(self.cert == ''):
                              return ('')
                          for ext in self.cert["extensions"]:
                              #Ищем расширение subjectSignTool
                              if(str(ext['extnID']) == "1.2.643.100.111"):
                                      #Его значение надо возвращать
                                      if sys.platform != "win32":
                                          seek = 4
                                      else:
                                          seek = 4
                      #Проверка версии python-а
                                      if (self.pyver == '2'):
                      #                    print ('V==2')
                                          return ext['extnValue'][seek-2:]
                                      seek = seek - 2
                      #                print ('V!=2')
                                      sst = ext['extnValue'][seek:].prettyPrint()
                                      if (len(sst) > 1 and sst[0] == '0' and sst[1] == 'x'):
                                          sst = binascii.unhexlify(sst[2:])
                                          sst = sst.decode('utf-8')
                      
                                      return (sst)
                          return ('')
                      
                        def issuerSignTool(self):
                          if(self.cert == ''):
                              return ([])
                          for ext in self.cert["extensions"]:
                              #Ищем расширение subjectSignTool
                              if(str(ext['extnID']) == "1.2.643.100.112"):
                                      #Его значение надо возвращать
                                      vv = ext['extnValue']
                      #                print(vv)
                      #Проверка версии python-а
                                      of2 = 1
                                      if (self.pyver == '2'):
                                          of1 = ord(vv[of2])
                                      else:
                                          of1 = vv[of2]
                      
                                      if (of1 > 128):
                                          of2 += (of1 - 128)
                                      of2 += 1
                      #Add for 0x30
                                      of2 += 1            
                                      if (self.pyver == '2'):
                                          of1 = ord(vv[of2])
                                      else:
                                          of1 = vv[of2]
                      
                                      if (of1 > 128):
                                          of2 += (of1 - 128)
                                          of2 += 1
                      # Поля issuerSignTools          
                                      fsbCA = []
                      #Длина первого поля
                      #                print(of2)
                                      for j in range(0,4):
                                          if (self.pyver == '2'):
                                              ltek = ord(vv[of2])
                                              stek = of2 + 1
                                          else:
                                              ltek = vv[of2 + 0]
                                              stek = of2 + 1
                                          fsb = vv[stek: stek+ltek]
                                          if (self.pyver == '3'):
                                              fsb = vv[stek: stek+ltek].prettyPrint()
                                              if (len(fsb) > 1 and fsb[0] == '0' and fsb[1] == 'x'):
                                                  try:
                                                      val1 = binascii.unhexlify(fsb[2:])
                                                      fsb = val1.decode('utf-8')
                                                  except:
                                                      fsb = vv[stek: stek+ltek].prettyPrint()
                      
                      #                            fsb = val1
                      #                    print(fsb)
                                          fsbCA.append(fsb)
                                          of2 += (ltek + 2)
                      #Возврат значений issuerSignTools
                                      return(fsbCA)
                          return ([])
                      
                        def classUser(self):
                          if(self.cert == ''):
                              return ('')
                          for ext in self.cert["extensions"]:
                              #Ищем расширение subjectSignTool
                              if(str(ext['extnID']) == "2.5.29.32"):
                                      print ('2.5.29.32')
                                      #Классы защищенности
                                      #           print (ext['extnValue'])
                      #Переводит из двоичной системы счисления (2) в hex
                                      kc = ext['extnValue'].prettyPrint()
                      #                print(kc)
                      #Сдвиг на 0x
                      #Проверка версии python-а
                                      if (self.pyver == '2'):
                                          kc_hex = kc[2:]
                                      else:
                                          kc_hex = kc[2:]
                      #                print(kc_hex)
                      # 4 - длина заголовка           
                                      kc_hex = kc_hex[4:]
                      #                print(kc_hex)
                                      i32 = kc_hex.find('300806062a85036471')
                                      tmp_kc = ''
                                      while (i32 != -1 ) :
                                          #'300806062a85036471' - 10 байт бинарных и 20 hex-овых; 4 - это 3008
                      #                    print ('НАШЛИ КС i32=' + str(i32))
                                          kcc_tek = kc_hex[i32+4: i32 + 20]
                      #           print (kcc_tek)
                                          oid_kc = self.notation_OID(kcc_tek)
                      #                    print (oid_kc)
                                          tmp_kc = tmp_kc + oid_kc +';;'
                                          kc_hex = kc_hex[i32 + 20:]
                                          i32 = kc_hex.find('300806062a85036471')
                      
                      #           for ext1 in ext:
                      #               print (ext1)
                      #                print ('2.5.29.32 END')
                      #           print (ext['extnID'])
                      #           print (ext['extnValue'])
                                      return (tmp_kc)
                          return ('')
                      
                        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.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",
                          }
                          issuer_or_subject = {}
                      #Владелец сертификата: 0 - неизвестно 1 - физ.лицо 2 - юр.лицо
                          vlad = 0
                          vlad_o = 0
                          for rdn in self.cert[who][0]:
                              if not rdn:
                                  continue
                              oid = str(rdn[0][0])
                      #            oid = str(rdn[0]['type'])
                              value = rdn[0][1]
                      #            value = rdn[0]['value']
                      #SNILS
                              if(oid == '1.2.643.100.3'):
                                  vlad = 1
                      #OGRN
                              elif(oid == '1.2.643.100.1'):
                                  vlad = 2
                      #O
                              elif(oid == '2.5.4.10'):
                                  vlad_o = 1
                              value = value[2:]
                      #        print(value)
                              if (self.pyver == '3'):
                      #           value = str(value).encode('raw_unicode_escape').decode('utf8')
                                  val = value.prettyPrint()
                      #            if (len(val) > 2 and val[1] != '\''):
                      #            if ((len(val) > 1 and val[1] != '\'') or (len(val) == 2 and (val[0] == '\xD0' or val[0] == '\xD1'))):
                                  if (len(val) > 1 and val[0] == '0' and val[1] == 'x'):
                                      try:
                                            val1 = binascii.unhexlify(val[2:])
                                            value = val1.decode('utf-8')
                                      except:
                                            pass
                              try:
                                  if not infoMap[oid] == "Type":
                                      issuer_or_subject[infoMap[oid]] = value
                                  else:
                                      try:
                                          issuer_or_subject[infoMap[oid]] += ", %s" % value
                                      except KeyError:
                                          issuer_or_subject[infoMap[oid]] = value
                              except KeyError:
                                  issuer_or_subject[oid] = value
                              if(vlad_o == 1):
                                  vlad = 2
                          return issuer_or_subject, vlad
                      
                        def issuerCert(self):
                          return (self.parse_issuer_subject ("issuer"))
                      
                        def subjectCert(self):
                          return (self.parse_issuer_subject ('subject'))
                      
                        def signatureCert(self):
                          if(self.cert == ''):
                              return ({})
                          algosign = self.cert_full["signatureAlgorithm"]['algorithm']
                          kk = self.cert_full["signatureValue"].prettyPrint()
                          if kk[-3:-1] == "'B":
                      #        print(kk[-3:-1])
                              #Избавляемся от "' в начале строки и 'B" и конце строки
                              kk = kk[2:-3]
                      #Переводит из двоичной системы счисления (2) в целое
                              kkh=int(kk, 2)
                      ##    else: 
                              #В MS из десятичной системы в целое
                      ##        kkh=int(kk, 10)
                          else:
                             kkh=int(kk, 10)
                          sign_hex = hex(kkh)
                          sign_hex = sign_hex.rstrip('L')
                          return (algosign, sign_hex[2:])
                      
                        def publicKey(self):
                          if(self.cert == ''):
                              return ({})
                          pubkey = self.cert['subjectPublicKeyInfo']
                          tmp_pk = {}
                          ff = pubkey['algorithm']
                          algo = ff['algorithm']
                          tmp_pk['algo'] = algo
                      #Проверка на ГОСТ
                          if (str(algo).find("1.2.643") == -1):
                              print ('НЕ ГОСТ')
                              return (tmp_pk)
                      
                          param = ff['parameters']
                          lh = param.prettyPrint()[2:]
                      #Со 2-й по 11 позиции, первые два байта тип и длина hex-oid-а
                          l1 = int(lh[7:8], 16)
                          lh1 = self.notation_OID(lh [4:4+4+l1*2])
                      #Длина следующего oid-а
                          l2 = int(lh[4+4+l1*2 + 3: 4+4+l1*2  + 4], 16)
                      #oid из hex в точечную форму
                          lh2 = self.notation_OID(lh [4+4+l1*2:4+4+l1*2 + 4 + l2*2])
                      
                          key_bytes = pubkey['subjectPublicKey']
                      #Читаем значение открытого ключа как битовую строку
                          kk = key_bytes.prettyPrint()
                      ##    if sys.platform != "win32":
                          if kk[-3:-1] == "'B":
                      #        print(kk[-3:-1])
                              #Избавляемся от "' в начале строки и 'B" и конце строки
                              kk = kk[2:-3]
                      #Переводит из двоичной системы счисления (2) в целое
                              kkh=int(kk, 2)
                      ##    else: 
                              #В MS из десятичной системы в целое
                      ##        kkh=int(kk, 10)
                          else:
                             kkh=int(kk, 10)
                      #    print (kkh)
                      #Из целого в HEX
                          kk_hex = hex(kkh)
                      #Значение ключа в hex хранится как 0x440... (длина ключа 512 бит) или 0x48180... (длина ключа 1024 бита)
                          if (kk_hex[3] == '4'):
                              kk_hex = kk_hex[5:]
                          elif (kk_hex[3] == '8'):
                              kk_hex = kk_hex[7:]
                      #Обрезвем концевик
                          kk_hex = kk_hex.rstrip('L')
                      
                          tmp_pk['curve'] = lh1
                          tmp_pk['hash'] = lh2
                          tmp_pk['valuepk'] = kk_hex
                          return (tmp_pk)
                      
                        def prettyPrint(self):
                          if(self.cert == ''):
                              return ('')
                          return (self.cert_full.prettyPrint())
                      
                        def serialNumber(self):
                          return(self.cert.getComponentByName('serialNumber'))
                      
                        def validityCert(self):
                          valid_cert = self.cert.getComponentByName('validity')
                          validity_cert = {}
                          not_before = valid_cert.getComponentByName('notBefore')
                          not_before = str(not_before.getComponent())
                      
                          not_after = valid_cert.getComponentByName('notAfter')
                          not_after = str(not_after.getComponent())
                      #    if isinstance(not_before, GeneralizedTime):
                      #        not_before = datetime.strptime(not_before, '%Y%m%d%H%M%SZ')
                      #    else:
                          validity_cert['not_before'] = datetime.strptime(not_before, '%y%m%d%H%M%SZ')
                      
                      #    if isinstance(not_after, GeneralizedTime):
                      #        not_after = datetime.strptime(not_after, '%Y%m%d%H%M%SZ')
                      #    else:
                          validity_cert['not_after'] = datetime.strptime(not_after, '%y%m%d%H%M%SZ')
                      
                      #    print (validity_cert) 
                          return validity_cert
                      
                        def KeyUsage(self):
                          X509V3_KEY_USAGE_BIT_FIELDS = (
                          'digitalSignature',
                          'nonRepudiation',
                          'keyEncipherment',
                          'dataEncipherment',
                          'keyAgreement',
                          'keyCertSign',
                          'CRLSign',
                          'encipherOnly',
                          'decipherOnly',
                          )
                          if(self.cert == ''):
                              return ([])
                          ku = []
                          for ext in self.cert["extensions"]:
                              #Ищем расширение keyUsage
                              if(str(ext['extnID']) != "2.5.29.15"):
                                   continue
                              print ('2.5.29.15')
                              os16 = ext['extnValue'].prettyPrint()
                      #        print(os16)
                              os16 = '0404' + os16[2:]
                      #        print(os16)
                              os = binascii.unhexlify(os16[0:])
                              octet_strings = os
                              e, f= decoder.decode(decoder.decode(octet_strings)[0], rfc2459.KeyUsage())
                      #        print (e)
                              n = 0
                              while n < len(e):
                                if e[n]:
                                  ku.append(X509V3_KEY_USAGE_BIT_FIELDS[n])
                      #            print(X509V3_KEY_USAGE_BIT_FIELDS[n])
                                n += 1
                              return(ku)
                          return ([])
                      
                      if __name__ == "__main__":
                      
                      #For test
                          certpem = """
                      -----BEGIN CERTIFICATE-----
                      MIIG3DCCBougAwIBAgIKE8/KkAAAAAAC4zAIBgYqhQMCAgMwggFKMR4wHAYJKoZI
                      hvcNAQkBFg9kaXRAbWluc3Z5YXoucnUxCzAJBgNVBAYTAlJVMRwwGgYDVQQIDBM3
                      NyDQsy4g0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQutCy0LAxPzA9BgNV
                      BAkMNjEyNTM3NSDQsy4g0JzQvtGB0LrQstCwLCDRg9C7LiDQotCy0LXRgNGB0LrQ
                      sNGPLCDQtC4gNzEsMCoGA1UECgwj0JzQuNC90LrQvtC80YHQstGP0LfRjCDQoNC+
                      0YHRgdC40LgxGDAWBgUqhQNkARINMTA0NzcwMjAyNjcwMTEaMBgGCCqFAwOBAwEB
                      EgwwMDc3MTA0NzQzNzUxQTA/BgNVBAMMONCT0L7Qu9C+0LLQvdC+0Lkg0YPQtNC+
                      0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMB4XDTE4MDcwOTE1MjYy
                      NFoXDTI3MDcwOTE1MjYyNFowggFVMR4wHAYJKoZIhvcNAQkBFg9jb250YWN0QGVr
                      ZXkucnUxITAfBgNVBAMMGNCe0J7QniDCq9CV0LrQtdC5INCj0KbCuzEwMC4GA1UE
                      Cwwn0KPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDRhtC10L3RgtGAMSEwHwYD
                      VQQKDBjQntCe0J4gwqvQldC60LXQuSDQo9CmwrsxCzAJBgNVBAYTAlJVMRgwFgYD
                      VQQIDA83NyDQnNC+0YHQutCy0LAxRDBCBgNVBAkMO9Cj0JvQmNCm0JAg0JjQm9Cs
                      0JjQndCa0JAsINCULjQsINCQ0J3QotCgIDMg0K3Qojsg0J/QntCcLjk0MRgwFgYD
                      VQQHDA/Qsy7QnNC+0YHQutCy0LAxGDAWBgUqhQNkARINMTE0Nzc0NjcxNDYzMTEa
                      MBgGCCqFAwOBAwEBEgwwMDc3MTA5NjQzNDgwYzAcBgYqhQMCAhMwEgYHKoUDAgIk
                      AAYHKoUDAgIeAQNDAARAW3hfhvDdUxa6N8hEDjmOg/LsDDRHj5DanAyARtNB/2b5
                      BEzQCg4lUwrO/VHmvoUtvsrLqrxV6Ae+jh+GFli9WKOCA0AwggM8MBIGA1UdEwEB
                      /wQIMAYBAf8CAQAwHQYDVR0OBBYEFMQYnG5GfYRnj2ehEQ5tv8Fso/qBMAsGA1Ud
                      DwQEAwIBRjAdBgNVHSAEFjAUMAgGBiqFA2RxATAIBgYqhQNkcQIwKAYFKoUDZG8E
                      Hwwd0KHQmtCX0JggwqvQm9CY0KDQodCh0JstQ1NQwrswggGLBgNVHSMEggGCMIIB
                      foAUi5g7iRhR6O+cAni46sjUILJVyV2hggFSpIIBTjCCAUoxHjAcBgkqhkiG9w0B
                      CQEWD2RpdEBtaW5zdnlhei5ydTELMAkGA1UEBhMCUlUxHDAaBgNVBAgMEzc3INCz
                      LiDQnNC+0YHQutCy0LAxFTATBgNVBAcMDNCc0L7RgdC60LLQsDE/MD0GA1UECQw2
                      MTI1Mzc1INCzLiDQnNC+0YHQutCy0LAsINGD0LsuINCi0LLQtdGA0YHQutCw0Y8s
                      INC0LiA3MSwwKgYDVQQKDCPQnNC40L3QutC+0LzRgdCy0Y/Qt9GMINCg0L7RgdGB
                      0LjQuDEYMBYGBSqFA2QBEg0xMDQ3NzAyMDI2NzAxMRowGAYIKoUDA4EDAQESDDAw
                      NzcxMDQ3NDM3NTFBMD8GA1UEAww40JPQvtC70L7QstC90L7QuSDRg9C00L7RgdGC
                      0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YCCEDRoHkDLQe8zqaC3yHaSmikw
                      WQYDVR0fBFIwUDAmoCSgIoYgaHR0cDovL3Jvc3RlbGVjb20ucnUvY2RwL2d1Yy5j
                      cmwwJqAkoCKGIGh0dHA6Ly9yZWVzdHItcGtpLnJ1L2NkcC9ndWMuY3JsMIHGBgUq
                      hQNkcASBvDCBuQwj0J/QkNCa0JwgwqvQmtGA0LjQv9GC0L7Qn9GA0L4gSFNNwrsM
                      INCf0JDQmiDCq9CT0L7Qu9C+0LLQvdC+0Lkg0KPQpsK7DDbQl9Cw0LrQu9GO0YfQ
                      tdC90LjQtSDihJYgMTQ5LzMvMi8yLTk5OSDQvtGCIDA1LjA3LjIwMTIMONCX0LDQ
                      utC70Y7Rh9C10L3QuNC1IOKEliAxNDkvNy8xLzQvMi02MDMg0L7RgiAwNi4wNy4y
                      MDEyMAgGBiqFAwICAwNBALvjFGhdFE9llvlvKeQmZmkI5J+yO2jFWTh8nXPjIpiL
                      OutUew2hIZv15pJ1QM/VgRO3BTBGDOoIrq8LvgC+3kA=
                      -----END CERTIFICATE-----
                      """
                      
                          c1 = Certificate(certpem)
                      #    c1 = Certificate('cert.der')
                      #    c1 = Certificate('p10.p10')
                          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 ist in range(len(res1)):
                              print (str(ist) + '=' + res1[ist])
                          print('=================classUser================================')
                          res2 = c1.prettyPrint()
                      #    print(res2)
                          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()
                          if(len(key_info) > 0):
                              print(key_info['curve'])
                              print(key_info['hash'])
                              print(key_info['valuepk'])
                          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(ku)
                          print('================END=================================')

                      Сохраняем в файле fsb795.py и выполняем команду:


                      $python fsb795

                      или


                      $python3 fsb795

                      Получаем релультат тестирования:

                      =================formatCert================================
                      PEM
                      =================subjectSignTool================================
                      СКЗИ «ЛИРССЛ-CSP»
                      =================issuerSignTool================================
                      0=ПАКМ «КриптоПро HSM»
                      1=ПАК «Головной УЦ»
                      2=Заключение № 149/3/2/2-999 от 05.07.2012
                      3=Заключение № 149/7/1/4/2-603 от 06.07.2012
                      =================classUser================================
                      2.5.29.32
                      1.2.643.100.113.1;;1.2.643.100.113.2;;
                      =================issuerCert================================
                      vlad_is=2
                      E=dit@minsvyaz.ru
                      CN=Головной удостоверяющий центр
                      Country=RU
                      L=Москва
                      O=Минкомсвязь России
                      ST=77 г. Москва
                      INN=007710474375
                      street=125375 г. Москва, ул. Тверская, д. 7
                      OGRN=1047702026701
                      =================subjectCert================================
                      vlad_sub=2
                      E=contact@ekey.ru
                      CN=ООО «Екей УЦ»
                      Country=RU
                      L=г.Москва
                      O=ООО «Екей УЦ»
                      ST=77 Москва
                      INN=007710964348
                      street=УЛИЦА ИЛЬИНКА, Д.4, АНТР 3 ЭТ; ПОМ.94
                      OGRN=1147746714631
                      OU=Удостоверяющий центр
                      =================publicKey================================
                      1.2.643.2.2.36.0
                      1.2.643.2.2.30.1
                      5b785f86f0dd5316ba37c8440e398e83f2ec0c34478f90da9c0c8046d341ff66f9044cd00a0e25530acefd51e6be852dbecacbaabc55e807be8e1f861658bd58
                      =================serialNumber================================
                      93558035364173444023011
                      =================validityCert================================
                      2027-07-09 15:26:24
                      2018-07-09 15:26:24
                      =================signatureCert================================
                      1.2.643.2.2.3
                      bbe314685d144f6596f96f29e426666908e49fb23b68c559387c9d73e322988b3aeb547b0da1219bf5e6927540cfd58113b70530460cea08aeaf0bbe00bede40
                      ================KeyUsage=================================
                      2.5.29.15
                      nonRepudiation
                      keyCertSign
                      CRLSign
                      ================END=================================


                      Я понимаю о чем вы говорите. И тесты есть, но этот тест мне больше по душе

                        0
                        Я читал ваш код и видел часть, которая генерирует этот результат. Это практически заготовка для нормального теста. Проблема в том, что этот тест понятен только вам, ибо вы знаете, каков должен быть ожидаемый выхлоп. А вот я не знаю, так что для меня, как для человека, которому ваш пакет интересен, результат вашего теста будет нулевым, я же не знаю, правильно вы сертификат распарсили или нет. Плюс не учтены возможные краевые ситуации (если таковые имеются, а они должны быть, судя по обработке except в коде).
                        Но вашу позицию я понял, так что дальнейшие пререкания считаю бессмысленными.
                      0
                      Я просто уверен, что вы в команде никогда не работали. Представьте, если каждый будет писать код в одном проекте так, как ему вздумается? Будет хаос, и люди начнут ненавидеть друг друга. Для этого и придумали соглашения по стилю написания, в питоне это pep8.
                    –3
                    Первое впечатление — «Привет из нулевых».
                    Сомнительная польза, код «как не надо писать на Python», ну и застывший в веках Tcl/Tk.

                    Не надо так!
                      –1
                      Мы же хотим получить доступ к атрибутам квалифицированного сертификата через Python и дать графическую утилиту для их просмотра.

                      Нееее, мы хотим больше знать о x509, а не читать документацию к утилите в стиле «Очень полезная кнопка ». )
                      А уж как получить доступ к атрибутам сертификата как-нибудь сами разберёмся.
                        +1
                        Извините, я в Python новичок (как и в программировании в целом) и тема тестирования для меня еще является тёмной. Поэтому задам нубский вопрос. Например, я написал программу, которая парсит сертификаты. Я смотрю вывод программы и смотрю содержание сертификата, например, с помощью mmc в ОС Windows: вывод программы совпадает с тем, что я вижу в mmc. Это ведь не значит, что программа работает неправильно? Нужны ли так тесты в данном случае?
                          +1
                          я в Python новичок (как и в программировании в целом)

                          Дело наживное. Москва, говорят, не сразу строилась.


                          вывод программы совпадает с тем, что я вижу в ОС.

                          Не верь глазам своим и тем более mmc. Бери в руки ASN1-парсер, парсь сертификат, смотри соответствие rfc (в нашем случае еще и требованиям ТК-26) и делай выводы. А тесты разработчику всегда нужны и он всегда тестит. О потребитель, как правило, доверяется производителю. Это к слову.

                            0
                            Спасибо, буду разбираться в теме тестирования!

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

                          Самое читаемое