📜 ⬆️ ⬇️

Disassemble and review qualified certificates using Python / Tkinter

Qualified certificates quickly became an integral part of everyday life. And more and more people want to see this "beast" from the inside. This is on the one hand. On the other hand, more and more applications are being developed that use information from these certificates. And these are not only the attributes of the TIN or OGRN of the owner or publisher of the certificate. This may be information about which cryptographic provider used by the certificate holder (subjectSignTool attribute) to generate the private key or based on what certified funds the Certification Authority (CA) was created, which issued this or that certificate. And if you write a program that will analyze the issued certificates, you can collect interesting statistics on what SKZI use certificate holders and based on what (though it is less interesting) certified (or uncertified) means deployed CA (attribute issuerSignTools):



In the open spaces of Habr, a successful attempt was made to disassemble a qualified certificate. Unfortunately, the analysis has only concerned the receipt of the TIN, OGRN and SNILS attributes that are part of the distinguished name DN (Distinguished Name). Although why unfortunately? The author had a specific task and it was solved. We want to access the attributes of a qualified certificate through Python and provide a graphical utility to view them.

To access the certificate attributes, we will use the fsb795 package. The package is available for both Pytho2 and Python3, both for Linux and for Windows. To install it, just run the traditional command:
')
# 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]# 

The fsb795 package requires the pyasn1 and pyasn1-modules packages. Therefore, if they are not installed, an attempt will be made to install them.

For python3, this command looks like this:

 # python -m pip install fsb795 ... # 

You can also download the python3 and python2 installation packages and install them locally.
The package name, by analogy with modules from the pyasn1-modules package, for example, rfc2459, etc., indicates that it is designed to work with certificates that meet the requirements of the Order of the Federal Security Service of the Russian Federation of December 27, 2011 No. 795 "On Approval requirements for the form of a qualified certificate ... ".

Access to the certificate in the fsb795 package is implemented through the Certificate class:

 # -*- 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__": . . . 

To create an object instance for a specific certificate, it suffices to execute the following statement:

 $ 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(</  >) >> 

As a parameter when creating an instance of a class, a certificate is specified, which can be either in a PEM or DER format file or be a string in PEM format.

After creation, each instance has four attributes: pyver, formatCert, cert_full, and cert.
By the attribute pyver, you can check how the certificate was parsed. If pyver is an empty string, then the file or string does not contain a certificate. Otherwise, the pyver attribute contains a version of the python language:

 >>> 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 >>> 

The formatCert attribute upon successful creation of an instance of the Certificate class contains the format of the file / string with the certificate. It can be PEM or DER. Why this attribute is needed will become clear below.

The fsb795 package was created using the pyasn1 package. So, it remains to examine two attributes. The cert attribute stores the tbs-certificate, ready for use with the pyasn1 package. The other attribute cert_full stores the entire decoded certificate with rfc2459 inclusive. Let's show how you can get the public key algorithm, having the cert attribute and the connected package pyasn1:

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

In the end, it will be possible to assess the capabilities of the fsb795 package in obtaining information on the public key of a qualified certificate.

When an instance of the Certificate class is successfully created, we have at our disposal methods that make it easy to obtain the necessary data from the certificate. All information about the public key, we can get as follows:

 >>> 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 >>> 

Currently, the Certificate class contains the following methods:


In the spoiler is a test case, which clearly demonstrates the work of these methods.

Test test795.py to test the fsb795 package
 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=================================') 


To run a test sample, just run the command:

 $python test795.py 

With the fsb795 package at its disposal, it was natural to write in python a self-contained, platform-independent graphical utility for viewing qualified certificates. Tkinter package is used as graphic support:



The viewCertFL63 utility has three tabs. On the "About the certificate" tab, among other things, the current time is displayed. We will return to it below. To select a certificate, just click the "Select" button:



Pay attention to the button (those who work on Windows will not see this button), it allows you to hide so-called invisible files / directories (hidden). In order for this button to appear it is enough to execute the following commands:

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

Very useful button. So, after selecting a certificate, the “About certificate” tab will look like:



What is remarkable here is that if during the viewing of the certificate its validity period expires, then on the icon in the upper left corner the seal will break into two halves. Everyone can see this by moving the clock on the computer for one year ahead.
On the Details tab, you can view in detail the characteristics of the selected attribute of a qualified certificate:



And finally, the third tab "Text". This tab displays the contents of the entire certificate:



To view the certificate, you can use not only Python (the “Python” button), then the openssl and pp utilities from Network Serurity Services (NSS). If someone does not have these utilities, then the first can be obtained by collecting openssl with the support of Russian cryptography. As for the second utility, you can look here :



We mentioned above about the formatCert attribute of the Certificate class of the fsb795 package. So the value of this attribute we need to specify the format of the file with the certificate when you run this or that utility. For example, calling the pp utility with a PEM file format looks like this:

 $pp –tc –u –a –i < > 

The “-a” parameter indicates the format of the PEM file. For DER format it is not specified.
The parameter “–inform” for openssl is set in the same way.
The “Utility” button is used to indicate the path to the openssl or pp utilities.
ViewCertFL63 utilities distributions are here .
The distribution kit was made using the pyinstaller package:

 $python pyinstaller.py --noconsole -F viewCertFL63.py 

Source: https://habr.com/ru/post/421107/


All Articles