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.
Windows drives are widely available but rare to find linux drivers are listed https://www.e-mudhra.com/Repository/index.html
You can uncomment to get the token name print(self.pkcs11.getSlotList(tokenPresent=True))
print(self.pkcs11.getTokenInfo(1))
to get token name, for PROXKey the name "WD PROXKey"
was generated.
#!/usr/bin/env vpython3
# *-* coding: utf-8 *-*
import sys
import datetime
from endesive import pdf, hsm
import os
import sys
if sys.platform == 'win32':
dllpath = r'c:\windows\system32\cryptoCertum3PKCS.dll'
else:
dllpath = '/usr/lib/WatchData/ProxKey/lib/libwdpkcs_SignatureP11.so'
import PyKCS11 as PK11
class Signer(hsm.HSM):
def certificate(self):
#print(self.pkcs11.getSlotList(tokenPresent=True))
#print(self.pkcs11.getTokenInfo(1))
# print(self.pkcs11.getTokenInfo(2))
# print(self.pkcs11.getTokenInfo(3))
# print(self.pkcs11.getSlotInfo(1))
self.login("WD PROXKey","12345678") # WF PROXKey is token name.
keyid = [0x5e, 0x9a, 0x33, 0x44, 0x8b, 0xc3, 0xa1, 0x35, 0x33, 0xc7, 0xc2, 0x02, 0xf6, 0x9b, 0xde, 0x55, 0xfe, 0x83, 0x7b, 0xde]
#keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8]
keyid = bytes(keyid)
try:
pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)])
all_attributes = [
#PK11.CKA_SUBJECT,
PK11.CKA_VALUE,
#PK11.CKA_ISSUER,
#PK11.CKA_CERTIFICATE_CATEGORY,
#PK11.CKA_END_DATE,
PK11.CKA_ID,
]
for pk11object in pk11objects:
try:
attributes = self.session.getAttributeValue(pk11object, all_attributes)
except PK11.PyKCS11Error as e:
continue
attrDict = dict(list(zip(all_attributes, attributes)))
cert = bytes(attrDict[PK11.CKA_VALUE])
#if keyid == bytes(attrDict[PK11.CKA_ID]):
return bytes(attrDict[PK11.CKA_ID]), cert
finally:
self.logout()
return None, None
def sign(self, keyid, data, mech):
self.login("WD PROXKey","12345678")
try:
privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY)])[0]
mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper())
sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None))
return bytes(sig)
finally:
self.logout()
def main():
date = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
date = date.strftime('%Y%m%d%H%M%S+00\'00\'')
dct = {
"sigflags": 3,
"sigpage": 0,
"sigbutton": True,
"contact": "[email protected]",
"location": 'India',
"signingdate": date.encode(),
"reason": 'Sample sign',
"signature": 'Madhurendra Sachan',
"signaturebox": (0, 0, 100, 100),
}
clshsm = Signer(dllpath)
fname = 'sample.pdf'
datau = open(fname, 'rb').read()
datas = pdf.cms.sign(datau, dct,
None, None,
[],
'sha256',
clshsm,
)
fname = fname.replace('.pdf', '-signed.pdf')
with open(fname, 'wb') as fp:
fp.write(datau)
fp.write(datas)
main()
.dll/.so path for common tokens
- For Windows the file will be in Windows\SysWOW64″ or “WINDOWS\system32” or “WINNT\system32”
- For Linux machine the file will be in /usr/local/lib/ or /usr/lib/
Hardware Token Type | Library file (Windows) | Library file (Linux) |
---|---|---|
SafeSign | aetpkss1.dll | aetpkss1.so |
eMudhra | eMudhra\eMudhra CSPV1.0\wdpkcs.dll | 1. WatchData/eMudhra_3.4.3/lib/libpkcs11wrapper.so 2. WatchData/eMudhra_3.4.3/lib/libwdpkcs_eMudhra_343.so |
Trust Key | 1. TRUST KEY\TRUST KEY CSP V1.0\wdpkcs.dll 2. C:\Windows\System32\TRUSTKEYP11_ND_v34.dll | 1. WatchData/TRUSTKEY/lib/libpkcs11wrapper.so 2. WatchData/TRUSTKEY/lib/libwdpkcs_TRUSTKEY.so |
Belgium eID MiddleWare | beidpkcs11.dll | beidpkcs11.so |
Gemalto Cryptocard Token | libgtop11dotnet.dll | libgtop11dotnet.so |
EPass | eps2003csp11.dll | |
Aladdin eToken | eTPKCS11.dll | |
Safenet iKey | dkck201.dll | |
Starkey | aetpkss1.dll | |
Watchdata PROXkey | SignatureP11.dll | WatchData/ProxKey/lib/libwdpkcs_SignatureP11.so |
15 comments
Skip to comment form
thank you very much!! great job!!
Madhurendra, thank you very much for this blog post!
I have got a eToken 5110 with a globalsign AATL certificate to sign pdf. How can I find out the hex values of my private Key?
Thanks a lot!
Andreas
Hi Andreas,
Thank you for going through the blog, I am glad it helped you.
You can use
bytes(attrDict[PK11.CKA_ID])
for value, if you want you can match it.Madhurendra, thank you very much for this blog post!
I have got a eToken 5110 with a globalsign AATL certificate to sign pdf. How can I find out the hex values of my private KeyID?
It’s the value of line 27
Thanks a lot!
Andreas
Hello Madhurendra,
I need some similar work to be done for my company. Could you mail me, to discuss more.
Hi, Madhurendra
I am trying to use your application but I am stuck with an error message I have not been able to interpret.
Here is the output:
Traceback (most recent call last):
File “assinapdf.py”, line 103, in
main()
File “assinapdf.py”, line 91, in main
datas = pdf.cms.sign(datau, dct,
File “/home/fernando/.local/lib/python3.8/site-packages/endesive/pdf/cms.py”, line 955, in sign
return cls.sign( File “/home/fernando/.local/lib/python3.8/site-packages/endesive/pdf/cms.py”, line 653, in sign
contents = signer.sign( File “/home/fernando/.local/lib/python3.8/site-packages/endesive/signer.py”, line 86, in sign
keyid, cert = hsm.certificate()
File “assinapdf.py”, line 39, in certificate pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)])
AttributeError: ‘NoneType’ object has no attribute ‘findObjects’
Any hints on where I should look for the problem?
I think your token is not connected, possibly driver or DLL is incorrect.
Hi, Madhurendra
I have some problem when using your great py script.
If i open signed doc in adobe reader i see error in sign:
Signature validity is UNKNOWN.
The signer’s identity is unknown because it has expired or is not yet valid.
Can you help me to fix this?
I have same problem with me.
Hi, Madhurendra
It is a very nice post. However I am not able to resolve this error.
Traceback (most recent call last):
File “C:/Users/durge/OneDrive/D_Folders/AutoDX/digsign1.py”, line 81, in
signpdf()
File “C:/Users/durge/OneDrive/D_Folders/AutoDX/digsign1.py”, line 72, in signpdf
datas = pdf.cms.sign(datau, dct, None,None ,[],’sha256′,clshsm,)
File “C:\Users\durge\anaconda3\lib\site-packages\endesive\pdf\cms.py”, line 965, in sign
return cls.sign(
File “C:\Users\durge\anaconda3\lib\site-packages\endesive\pdf\cms.py”, line 655, in sign
contents = signer.sign(
File “C:\Users\durge\anaconda3\lib\site-packages\endesive\signer.py”, line 202, in sign
signed_value_signature = hsm.sign(keyid, tosign, hashalgo)
File “C:/Users/durge/OneDrive/D_Folders/AutoDX/digsign1.py”, line 35, in sign
privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY)])[0]
AttributeError: ‘NoneType’ object has no attribute ‘findObjects’
signature is placed in the bottom left of the page, i want to place it on bottom right side of the page
is there a way to check if a file does not have digital signature, and sign only if it does not have a digital signature?
please make gui also for this code
I successfully signed the pdf on my PC (I have epass2003) token, but when I tried on with another token on a different PC (the same token epass2003), I faced an error that the signature was invalid.
Also when I try to sign the pdf manually through acrobat, it works fine and the signature is valid.
Your help is very much appreciated!!
Hi Madhurendra, where we can get the DLL, shall I ask to DSC USB provider or will it be installed when we plugin the USB and install the driver?