Support for PKCS # 11 tokens with GOST cryptography in Python. Part III - The PyKCS11 Wrapper

imageIt's time to tell you how support for Russian cryptography was added to the PyKCS11 project . It all started when I came across a correspondence between the developer of the PyKCS11 project and potential consumers about the possible support of GOST R 34.10-2012 algorithms in it. In this correspondence, the author of PkCS11 said that he is not going to include support for Russian cryptoalgorithms until they are standardized.

He expressed the same idea to me when I asked him to do it. And not just to do it, but sent the appropriate program code:



image



After that, I considered it possible to fork the code into my repository and make the appropriate edits to it. PyKCS11 project with Russian cryptography support is here .



I. Adding support for Russian cryptoalgorithms



So what has been done. I actually followed one of the tips from the author of the PyKCS11 project:

What I can propose you is to create a PyKCS11_GOST.py file with the constant names and functions you want in order to extend PyKCS11 with GOST support.

(I might suggest you create a PyKCS11_GOST.py file with the names of the constants and functions that you want to extend PyKCS11 to support GOST.)



All constants approved by TC-26 for PKCS # 11 have been consolidated into one file pkcs11t_gost.h, placed in the src folder:

//-26
#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xd4321000 
#define NSSCK_VENDOR_PKSC11_RU_TEAM NSSCK_VENDOR_PKCS11_RU_TEAM
#define CK_VENDOR_PKCS11_RU_TEAM_TC26 NSSCK_VENDOR_PKCS11_RU_TEAM
#define CKK_GOSTR3410_512 	0xd4321003UL
#define CKK_KUZNYECHIK 		0xd4321004UL
#define CKK_MAGMA 		0xd4321005UL
#define CKK_GOSTR3410_256 	0xd4321006UL
#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411_TC26_V1 	0xd4321801UL
#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411_2012_256 0xd4321002UL
#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411_2012_512 0xd4321003UL
#define CKM_GOSTR3410_512_KEY_PAIR_GEN		0xd4321005UL
#define CKM_GOSTR3410_512			0xd4321006UL
#define CKM_GOSTR3410_WITH_GOSTR3411		0x00001202
#define CKM_GOSTR3410_WITH_GOSTR3411_12_256	0xd4321008UL
#define CKM_GOSTR3410_WITH_GOSTR3411_12_512	0xd4321009UL
#define CKM_GOSTR3410_12_DERIVE			0xd4321007UL
#define CKM_GOSR3410_2012_VKO_256		0xd4321045UL
#define CKM_GOSR3410_2012_VKO_512		0xd4321046UL
#define CKM_KDF_4357				0xd4321025UL
#define CKM_KDF_GOSTR3411_2012_256		0xd4321026UL
#define CKM_KDF_TREE_GOSTR3411_2012_256		0xd4321044UL
#define CKM_GOSTR3410_PUBLIC_KEY_DERIVE		0xd432100AUL
#define CKM_LISSI_GOSTR3410_PUBLIC_KEY_DERIVE	0xd4321037UL
#define CKM_GOST_GENERIC_SECRET_KEY_GEN		0xd4321049UL
#define CKM_GOST_CIPHER_KEY_GEN			0xd4321048UL
#define CKM_GOST_CIPHER_ECB			0xd4321050UL
#define CKM_GOST_CIPHER_CBC			0xd4321051UL
#define CKM_GOST_CIPHER_CTR			0xd4321052UL
#define CKM_GOST_CIPHER_OFB			0xd4321053UL
#define CKM_GOST_CIPHER_CFB			0xd4321054UL
#define CKM_GOST_CIPHER_OMAC			0xd4321055UL
#define CKM_GOST_CIPHER_KEY_WRAP		0xd4321059UL
#define CKM_GOST_CIPHER_ACPKM_CTR		0xd4321057UL
#define CKM_GOST_CIPHER_ACPKM_OMAC		0xd4321058UL
#define CKM_GOST28147_PKCS8_KEY_WRAP		0xd4321036UL
#define CKM_GOST_CIPHER_PKCS8_KEY_WRAP		0xd432105AUL
#define CKM_GOST28147_CNT			0xd4321825UL
#define CKM_KUZNYECHIK_KEY_GEN			0xd4321019UL
#define CKM_KUZNYECHIK_ECB			0xd432101AUL
#define CKM_KUZNYECHIK_CBC			0xd432101EUL
#define CKM_KUZNYECHIK_CTR			0xd432101BUL
#define CKM_KUZNYECHIK_OFB			0xd432101DUL
#define CKM_KUZNYECHIK_CFB			0xd432101CUL
#define CKM_KUZNYECHIK_OMAC			0xd432101FUL
#define CKM_KUZNYECHIK_KEY_WRAP			0xd4321028UL
#define CKM_KUZNYECHIK_ACPKM_CTR		0xd4321042UL
#define CKM_KUZNYECHIK_ACPKM_OMAC		0xd4321043UL
#define CKM_MAGMA_KEY_GEN			0xd432102AUL
#define CKM_MAGMA_ECB				0xd4321018UL
#define CKM_MAGMA_CBC				0xd4321023UL
#define CKM_MAGMA_CTR				0xd4321020UL
#define CKM_MAGMA_OFB				0xd4321022UL
#define CKM_MAGMA_CFB				0xd4321021UL
#define CKM_MAGMA_OMAC				0xd4321024UL
#define CKM_MAGMA_KEY_WRAP			0xd4321029UL
#define CKM_MAGMA_ACPKM_CTR			0xd4321040UL
#define CKM_MAGMA_ACPKM_OMAC			0xd4321041UL
#define CKM_GOSTR3411_12_256			0xd4321012UL
#define CKM_GOSTR3411_12_512			0xd4321013UL
#define CKM_GOSTR3411_12_256_HMAC		0xd4321014UL
#define CKM_GOSTR3411_12_512_HMAC		0xd4321015UL
#define CKM_PBA_GOSTR3411_WITH_GOSTR3411_HMAC	0xd4321035UL
#define CKM_TLS_GOST_KEY_AND_MAC_DERIVE		0xd4321033UL
#define CKM_TLS_GOST_PRE_MASTER_KEY_GEN		0xd4321031UL
#define CKM_TLS_GOST_MASTER_KEY_DERIVE		0xd4321032UL
#define CKM_TLS_GOST_PRF			0xd4321030UL
#define CKM_TLS_GOST_PRF_2012_256		0xd4321016UL
#define CKM_TLS_GOST_PRF_2012_512		0xd4321017UL
#define CKM_TLS_TREE_GOSTR3411_2012_256		0xd4321047UL
      
      





This list includes mechanisms both necessary for the formation and verification of signatures in accordance with (GOST R 34.10-2012) GOST R 34.10-2012, and encryption (GOST R 34.12-2015 and GOST R 34.13-2015 - encryption algorithms Grasshopper and Magma). Naturally, GOST R 34.11-2012 hashing algorithms are also present here.

In order for the GOST constants to be included in the module build process, it is necessary to add an include statement to the pkcs11t_gost.h file to the pkcs11.i file (file for SWIG)

%include "pkcs11t_gost.h"
      
      





in front of the operator

%include "pkcs11lib.h"
      
      





But that is not all. In the getMechanismList method (script PKCS11 / __ init__.py), the output of mechanisms whose code is greater than CKM_VENDOR_DEFINED is blocked (this is exactly what the author of the PyKCS11 project writes about) (0x80000000L). Note that GOST constants for new algorithms fall under this restriction. It is necessary to remove it at least for GOSTs, so we will replace the code of the getMechanismList method with a new one:

    def getMechanismList(self, slot):
        """
        C_GetMechanismList

        :param slot: slot number returned by :func:`getSlotList`
        :type slot: integer
        :return: the list of available mechanisms for a slot
        :rtype: list
        """
        mechanismList = PyKCS11.LowLevel.ckintlist()
        rv = self.lib.C_GetMechanismList(slot, mechanismList)
        if rv != CKR_OK:
            raise PyKCS11Error(rv)
        m = []
#  
#define NSSCK_VENDOR_PKCS11_RU_TEAM 0xd4321000 
        for x in range(len(mechanismList)):
            mechanism = mechanismList[x]
            if mechanism >= CKM_VENDOR_DEFINED:
                if mechanism >= CKM_VENDOR_DEFINED and mechanism < 0xd4321000:
                    k = 'CKM_VENDOR_DEFINED_0x%X' % (mechanism - CKM_VENDOR_DEFINED)
                    CKM[k] = mechanism
                    CKM[mechanism] = k
            m.append(CKM[mechanism])
        return m
#ORIGINAL
#        for x in range(len(mechanismList)):
#            mechanism = mechanismList[x]
#            if mechanism >= CKM_VENDOR_DEFINED:
#                k = 'CKM_VENDOR_DEFINED_0x%X' % (mechanism - CKM_VENDOR_DEFINED)
#                CKM[k] = mechanism
#                CKM[mechanism] = k
#            m.append(CKM[mechanism])
#        return m
      
      







Note also that although the module includes all the mechanisms that are defined in the include files pkcs11t.h and pkcs11t_gost.h for pkcs11 v.2.40, not all of these mechanisms can be implemented. The problem is that some of them require a specific parameter structure. This applies in particular to the CKM_RSA_PKCS_OAEP mechanism, which requires parameters in the form of a CK_RSA_PKCS_OAEP_PARAMS structure, and to the CKM_PKCS5_PBKD2 mechanism, which expects parameters in the form of a CK_PKCS5_PBKD2_PARAMS structure. There are other mechanisms as well. But since the author has implemented separate structures for individual mechanisms (for the same CKM_RSA_PKCS_OAEP), it will not be difficult to implement support for parameter structures for other mechanisms. So, if anyone needs to work with a PKCS # 12 container,then you will have to implement support for the CK_PKCS5_PBKD2_PARAMS structure.

All this refers to rather complex cryptographic mechanisms.

But everything that concerns hashing, the formation of verification of an electronic signature, and finally, encryption, everything works great. But first you need to put together a project.



II. Building a PyKCS11 wrapper with GOST support



It is no different from building the native PkCS11 wrapper, except that you need to get the source code here .

Next, follow the instructions for building and installing the PyKCS11 package.

Testing requires a token with Russian cryptography support. Here we mean GOST R 34.10-2012 and GOST R 34.11-2012. It can be either a hardware token, for example RuTokenECP-2.0, or software or cloud tokens.

You can install a software token or access a cloud token using the cryptoarmpkcs utility.

You can download the cryptoarmpkcs utility here.




After starting the utility, you need to go to the "Create tokens"



image



tab : On the tab you can find instructions for obtaining and installing tokens.



III. Testing Russian algorithms



For testing, you can use the scripts that are in the testGost folder:

  • ckm_kuznyechik_cbc.py
  • ckm_gostr3411_12_256.py
  • ckm_gostr3410_with_gostr3411_12_256.py
  • ckm_gostr3410_512.py


For testing, the initial data were taken both from the corresponding GOSTs and from the recommendations of TK-26.

The following mechanisms are tested in these scripts:

1. Generation of key pairs:

  • CKM_GOSTR3410_512_KEY_PAIR_GEN (GOST R 34.10-2012 with a key length of 1024 bits)
  • CKM_GOSTR3410_KEY_PAIR_GEN (GOST R 34.10-2012 with 512 bit key length)


2. Formation and verification of an electronic signature:

  • CKM_GOSTR3410
  • CKM_GOSTR3410_512
  • CKM_GOSTR3410_WITH_GOSTR3411_12_256


3. Hashing:

  • CKM_GOSTR3411_12_256


4. Encryption / decryption

  • CKM_KUZNYECHIK_CBC




Generating key pairs allows the token holder to obtain a private key with which he can sign, for example, a certificate request. A request for a certificate can be sent to a certification center and a certificate can be issued there. The owner of the certificate can import it to the token where the private key is stored. The token owner now has a personal certificate with a private key that he can use to sign documents.

Well, if he needs a special security mode, then he can encrypt the document using one of the algorithms, namely Magma or Grasshopper. All this, of course, if the token itself supports these mechanisms, the PyKCS11 package is just an intermediary.

This concludes our story related to the support of tokens with Russian cryptography in Python.



All Articles