English Deutsch

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.