How to externally sign a document
There are two possibilities to sign a document outside of PyFintech: locally on the client side or remotely over the network.
External signature locally on the client
You have to override the method _sign_external
by subclassing EbicsUser
:
from fintech.ebics import EbicsUser
class EbicsUserExtSign(EbicsUser):
def _sign_external(self, data, prehashed):
# Do all the stuff that is required to sign the data
# depending on the user's key version (A005 or A006).
# For example by using a PKCS11 library.
# "prehashed" is a flag that indicates if data is already
# prehashed (as is the case with methods of the distributed
# signature). The return value must be the base64 encoded
# signature.
return base64.encode(create_signature(data, prehashed))
You can use a PKCS#11 library to sign the document. If the user's key version is A005, the signature algorithm to use is CKM_SHA256_RSA_PKCS. With key version A006 you have to use CKM_SHA256_RSA_PKCS_PSS. If the data to sign is already prehashed, you need to use CKM_RSA_PKCS and CKM_RSA_PKCS_PSS respectively.
External signature remotely over the network
To sign a document remotely is a bit more complex. In this example we are subclassing EbicsUser
as follows:
from hashlib import sha256
from fintech.ebics import EbicsUser
class EbicsUserExtSign(EbicsUser):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._signatures = {}
def add_signature(self, document, signature, prehashed=False):
"""
Method to collect signatures to be used in
"_sign_external" when uploading the document.
"""
if prehashed:
hash = document
else:
data = self._prepare_to_sign(document)
hash = sha256(data).digest()
self._signatures[hash] = signature
def _sign_external(self, data, prehashed):
if prehashed:
hash = data
else:
hash = sha256(data).digest()
return self._signatures.pop(hash)
First you have to get the prepared data of the document you want to sign. An EbicsUser
instance has a method called _prepare_to_sign
which normalizes the data depending on the user's key version:
user = EbicsUserExtSign(...) data = user._prepare_to_sign(document)
Now you can send the normalized data to the client where it must be signed with the appropriate signature algorithm mentioned above.
When you've got back the signature, you are able to do the upload:
user = EbicsUserExtSign(...) user.add_signature(document, returned_signature_base64_encoded) client = EbicsClient(...) order_id = client.FUL('file.type', document)
Browser based signature process (3SKey)
The client needs to install SConnect. It provides a PKCS#11 Javascript interface which must be used to sign the data.