{"id":279,"date":"2020-10-02T14:36:48","date_gmt":"2020-10-02T09:06:48","guid":{"rendered":"http:\/\/madhurendra.com\/?p=279"},"modified":"2021-03-30T00:13:26","modified_gmt":"2021-03-29T18:43:26","slug":"pdf-signing-using-hardware-token-dsc-in-python","status":"publish","type":"post","link":"https:\/\/madhurendra.com\/pdf-signing-using-hardware-token-dsc-in-python\/","title":{"rendered":"PDF Signing using hardware token (DSC) in Python"},"content":{"rendered":"\n

Hardware based tokens are widely used in India to generate signed PDF’s like invoices and agreement. We wrote small Python code to sign the invoices automatically where token was attached to a local server. <\/p>\n\n\n\n

Windows drives are widely available but rare to find linux drivers are listed https:\/\/www.e-mudhra.com\/Repository\/index.html<\/p>\n\n\n\n

You can uncomment to get the token name print(self.pkcs11.getSlotList(tokenPresent=True))<\/code>
print(self.pkcs11.getTokenInfo(1)) <\/code>to get token name, for PROXKey the name \"WD PROXKey\"<\/code> was generated. <\/p>\n\n\n

\n#!\/usr\/bin\/env vpython3\n# *-* coding: utf-8 *-*\nimport sys\nimport datetime\nfrom endesive import pdf, hsm\n\nimport os\nimport sys\n\nif sys.platform == 'win32':\n    dllpath = r'c:\\windows\\system32\\cryptoCertum3PKCS.dll'\nelse:\n    dllpath = '\/usr\/lib\/WatchData\/ProxKey\/lib\/libwdpkcs_SignatureP11.so'\n\nimport PyKCS11 as PK11\n\nclass Signer(hsm.HSM):\n    def certificate(self):\n        #print(self.pkcs11.getSlotList(tokenPresent=True))\n        #print(self.pkcs11.getTokenInfo(1))\n#        print(self.pkcs11.getTokenInfo(2))\n#        print(self.pkcs11.getTokenInfo(3))\n\n\n#        print(self.pkcs11.getSlotInfo(1))\n        self.login("WD PROXKey","12345678") # WF PROXKey is token name.\n        keyid = [0x5e, 0x9a, 0x33, 0x44, 0x8b, 0xc3, 0xa1, 0x35, 0x33, 0xc7, 0xc2, 0x02, 0xf6, 0x9b, 0xde, 0x55, 0xfe, 0x83, 0x7b, 0xde]\n        #keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8]\n        keyid = bytes(keyid)\n        try:\n            pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)])\n            all_attributes = [\n                #PK11.CKA_SUBJECT,\n                PK11.CKA_VALUE,\n                #PK11.CKA_ISSUER,\n                #PK11.CKA_CERTIFICATE_CATEGORY,\n                #PK11.CKA_END_DATE,\n                PK11.CKA_ID,\n            ]\n\n            for pk11object in pk11objects:\n                try:\n                    attributes = self.session.getAttributeValue(pk11object, all_attributes)\n                except PK11.PyKCS11Error as e:\n                    continue\n\n                attrDict = dict(list(zip(all_attributes, attributes)))\n                cert = bytes(attrDict[PK11.CKA_VALUE])\n                #if keyid == bytes(attrDict[PK11.CKA_ID]):\n                return bytes(attrDict[PK11.CKA_ID]), cert\n        finally:\n            self.logout()\n        return None, None\n\n    def sign(self, keyid, data, mech):\n        self.login("WD PROXKey","12345678")\n        try:\n            privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY)])[0]\n            mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper())\n            sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None))\n            return bytes(sig)\n        finally:\n            self.logout()\n\ndef main():\n    date = datetime.datetime.utcnow() - datetime.timedelta(hours=12)\n    date = date.strftime('%Y%m%d%H%M%S+00\\'00\\'')\n    dct = {\n        "sigflags": 3,\n        "sigpage": 0,\n        "sigbutton": True,\n        "contact": "madhurendra@tikaj.com",\n        "location": 'India',\n        "signingdate": date.encode(),\n        "reason": 'Sample sign',\n        "signature": 'Madhurendra Sachan',\n        "signaturebox": (0, 0, 100, 100),\n    }\n    clshsm = Signer(dllpath)\n    fname = 'sample.pdf'\n    datau = open(fname, 'rb').read()\n    datas = pdf.cms.sign(datau, dct,\n        None, None,\n        [],\n        'sha256',\n        clshsm,\n    )\n    fname = fname.replace('.pdf', '-signed.pdf')\n    with open(fname, 'wb') as fp:\n        fp.write(datau)\n        fp.write(datas)\n\n\nmain()\n\n<\/pre><\/div>\n\n\n

<\/p>\n\n\n\n

.dll\/.so path for common tokens<\/h2>\n\n\n\n