EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Using own crypto class for signing PDF via PDFBlackBox

Posted: 01/13/2014 07:41:13
by Petr Stransky (Standard support level)
Joined: 09/24/2012
Posts: 19

We have our own class for supporting specific crypto HW and we would like to use it in combination with PDFBlackbox to sign PDF files. We are now able to sign PDF files with certificate from PFX and that works fine.
Our class can provide X509 certificate and the low-level sign function. What is the best approach to make PKIBlackbox to use our certificate and call our functions for crypto operations?
Posted: 01/13/2014 07:58:42
by Vsevolod Ievgiienko (Team)

Thank you for contacting us.

The best way is to write your own cryptoprovider based on our TElCustomCryptoProvider class. As you have a source code you can use existing providers (TElBuiltInCryptoProvider, TElPKCS11CryptoProvider etc.) as a reference.
Posted: 01/13/2014 09:35:36
by Petr Stransky (Standard support level)
Joined: 09/24/2012
Posts: 19

I briefly looked into TElPKCS11CryptoProvider and it seems a "little bit" complex. So before looking into it more deeply I just want to confirm that this is the correct way even if I just need 1 certificate object with 1 private key and simple sign operation without any support for multiple objects, key cloning, etc...
Posted: 01/13/2014 10:05:03
by Eugene Mayevski (Team)

Yes, but you don't need to implement all operations - you can implement only what is actually used (that would be a couple of functions).

Also PKCS11 is not the best thing to look at. Check Win32 cryptoprovider, it's simpler.

Sincerely yours
Eugene Mayevski
Posted: 01/13/2014 18:51:20
by Petr Stransky (Standard support level)
Joined: 09/24/2012
Posts: 19

Thanks for your help but I am probably missing something terribly obvious but I am not able to figure out what...
I do the "normal" PDF Signing from PFX like this:
  fElCertStorage := TElMemoryCertStorage.Create(nil);
  ElCert := TElX509Certificate.Create(nil);
  ElPDFPublicKeySecurityHandler1.CertStorage := fElCertStorage;

Basically I create MemoryCertStorage, create new empty certificate object, load it from pfx and add it to cert store. This certstore is used in PDF Security Handler. This works just fine. So I tried to modify this approach with my own CryptoProvider and CryptoKey:

var  cp:TElSlotCryptoProvider;
cp := TElSlotCryptoProvider.Create(nil);
ec := TElX509Certificate.Create(nil);
ec.CryptoProvider := cp;
ec.loadfrombuffer(Addr(xder[1]),length(xder)); //xder is containing the certificate in DER
k := TElSlotCryptoKey.Create(cp);
//and then I put this ec object into newly created memoryCertStore and pass it to the PDF Security Handler.

My classes are defined like this:
  TElSlotCryptoProvider =  class(TElBuiltInCryptoProvider)
   function CloneKey(Key : TElCustomCryptoKey) : TElCustomCryptoKey; override;
   function IsOperationSupported(Operation : integer; Algorithm : integer; Mode : integer; Key : TElCustomCryptoKey; Params : TElCPParameters): boolean; override;

  TElSlotCryptoKey = class(TElCustomCryptoKey)
    function GetIsPublic: boolean; override;
    function GetIsSecret: boolean; override;
    function GetIsExportable: boolean; override;
    function GetIsPersistent: boolean; override;
    function GetIsValid: boolean; override;
    function GetBits : integer; override;
    function GetAlgorithm : integer; override;
    function GetKeyStorage : TElCustomCryptoKeyStorage; override;
    constructor Create(CryptoProvider : TElCustomCryptoProvider); virtual;
    function Clone(Params : TElCPParameters =  nil) : TElCustomCryptoKey; override;
    procedure ClearPublic; override;
    procedure ClearSecret; override;
    function GetKeyProp(const PropID : BufferType; const Default : BufferType =  {$ifdef SB_BUFFERTYPE_IS_BYTEARRAY}nil {$else}'' {$endif} ): BufferType; override;

Most of the methods are only stubs but they do at least return correct values. The issue is that I do not understand how to provide the cryptographic functions (sign). When the certificate is loaded it gets the TElRSAKeyMaterial as its KeyMaterial. When I do debug the whole PDF signing process my CryptoKey class gets called for some information (i.e. key size) but somewhere (and I am not able to find the exact spot) it starts to use the "default" functions and I finally end up in TElMessageProcessor.SignRSA that is completely ignoring my objects... And it of course fails as the default TElRSAPublicKeyCrypto needs private exponent, etc...
I tried to look into Win32 crypto provider but it is still very complex and I do not know where to start.
Am I at least going in the right direction or is there any other way that I do not see?
Posted: 01/14/2014 00:53:10
by Ken Ivanov (Team)

Hello Petr,

Before continuing, let's establish some important facts about your device's interface and the certificates:

1. The device is supposed to contain RSA certificates doesn't it?

2. What exactly functionality (cryptographic functions) does the device expose via its API?

3. Do you intend to only sign PDFs or you need a general signing solution, for other document types in perspective?
Posted: 01/14/2014 04:41:07
by Petr Stransky (Standard support level)
Joined: 09/24/2012
Posts: 19

1. Our existing class provides unified access to all HW we use. The HW contains RSA X509 certificates and private keys (nonextractable).

2. We are able to choose the required certificate via our existing UI so I end up with the required certificate (as der or pem) and its corresponding low-level sign function
function Sign(flen:integer;from:pointer;xto:pointer):integer;

3. I need to sign PDF, basically all I need to do is "hey, here is the certificate and when you need to calculate signature using its private key, call me". I may need to sign other things in future but it is not a priority now.
Posted: 01/14/2014 04:57:37
by Ken Ivanov (Team)


Thank you for the details.

If it's the advanced handler that you are using (TElPDFAdvancedPublicKeySecurityHandler), your task can actually be solved much cheaper than by implementing your own cryptographic provider. The advanced handler can operate in 'external sign' mode, where it passes the document hash out to the user during signing, and expects the user to return the signature back.

What you need to do to bind the handler to your signing engine is the following:

1. Configure the handler just as if you planned to use it in 'normal' way. Add a public copy of your signing certificate to a memory storage object and assign that object to the handler's CertStorage property.

2. Set the handler's RemoteSigningMode to true.

3. Optionally, set the handler's RemoteSigningCertIndex property to the index of the signing certificate in the memory storage (if there's more than one certificate there), so that the handler knew which exactly certificate is the signing one. If there's only one certificate in the storage, you can skip this step.

4. Handle the OnRemoteSign event. In the event handler, pass the provided document hash to your signing engine, and return the calculated signature via the event's SignedHash parameter.

This should do the job for you.

Posted: 01/14/2014 06:31:48
by Petr Stransky (Standard support level)
Joined: 09/24/2012
Posts: 19

Thanks for your suggestion.
I tried the approach with Advanced PDF Security Handler but it fails in
function TElPDFAdvancedPublicKeySecurityHandler.GetEstimatedSignatureSize(AsyncMode: boolean) : integer;

with exception SNoSigningCertificate, clearly because it does verify the private key presence in certificate:
      if Assigned(CertStorage) then
        for I := 0 to CertStorage.Count - 1 do
          if CertStorage.Certificates[I].PrivateKeyExists then
            Index := I;

I tried to specify the RemoteSigningCertIndex := 0; but it did not help.

When I tried the Advanced PDF Security Handler with PFX it worked but I am not quite sure how to set it up to produce the same output as the "simple" handler. Also the size increase of PDF file was cca 100KB instead of 10KB with the "simple" one.
Posted: 01/14/2014 06:47:13
by Ken Ivanov (Team)


Hmm, I wonder why the value of the RemoteSigningMode property is not considered in that code... We will implement the necessary check and publish it in the future SecureBlackbox update.

As a temporary workaround, please try to set the handler's SignatureSizeEstimationStrategy property to psesPredefinedSize, and the PredefinedSignatureSize property to e.g. 16384. This will make the estimation procedure go via a different branch and skip the private key availability requirement.

Document size is a different [quite long] story. Our primary goal is to make the components do the actual signing, and once we are happy with that we'll get back to the size issue (it is solvable).




Topic viewed 2494 times

Number of guests: 1, registered members: 0, in total hidden: 0


Back to top

As of July 15, 2016 EldoS business operates as a division of /n software, inc. For more information, please read the announcement.

Got it!