Type Default Value Read Only Description

[Visual Basic]
null No A delegate called to perform custom signing of the PDF.




A delegate called to perform a custom signing of the PDF content digest and signed attributes.

The definition of the SigningDelegate delegate is as follows.


delegate byte[] SigningDelegate(byte[] data);;

The type of data passed to your delegate is determined by the data type you specify when you call the Sign method. The default type is DataType.Pkcs9Digest which is what will be used if you do not specify a type.

For DataType.Pkcs9Digest the data is an ASN.1 encoded PKCS9 digest of the PDF content which includes the digest of the document data with additional attributes required according to any desired CompliancePades level that you have specified. For DataType.RawDigest the data is the raw digest of the document data.

In either case ABCpdf will create the digest using the algorithm specified by the Oid passed to the Signature.Sign method. Where the Sign method overload does not take an Oid the default algorithm of SHA256 will be used.

For best results the CustomSigner should return the raw signature of this data such as that returned by RSACryptoServiceProvider.SignData (.NET 4) or RSACng.SignData (.NET 5). This ensures that ABCpdf can add any additional unsigned attributes required for PAdES compliance.

If ABCpdf detects that the data returned is already in PKCS7 CMS format it will embed that data into the document as is, with no further processing. This is sometimes needed to accommodate certain third-party signing solutions. In this case any desired compliance will be dependent upon your solution provider.

The best way to determine the type of data your signing provider returns, is to paste the byte array as a hexadecimal string into a decoder such as the LAPO ASN.1 JavaScript Decoder. If it can be decoded it is already in PKCS7 format. If it cannot then it is most likely the raw signature of the digest.

When writing code against your signing provider it is prudent to Validate the document to ensure you are providing correct data. See the example below for details.




The following example shows how an external delegate might be used.


using (Doc doc = new Doc()) {   doc.Read(Server.MapPath("mypics/pic.jpg"));   Signature sig = (Signature)doc.Form.Fields["Signature1"];   sig.CustomSigner = ExternalSigner;   sig.Reason = "Test External Signing";   // Just use public certificate from file - i.e. do not obtain from registry   X509Certificate2 cert = new X509Certificate2(Server.MapPath("GlobalSign.cer"));   sig.Sign(cert, true, new Oid(CryptoConfig.MapNameToOID("SHA512")), X509IncludeOption.EndCertOnly);   // here we commit and validate to ensure the data is correct   sig.Commit();   sig = (Signature)doc.Form.Fields["Signature1"]; // signature must be re-retrieved after a Commit/Save   if(!sig.Validate())     throw new Exception("Signing failed!");   doc.Save(Server.MapPath("SignedDoc.pdf")); }

The code above uses the following External Signer.


byte[] ExternalSigner(byte[] data) {   string serial = "10 20 30 10 40 10 40 50 60 10 20 30"; // needs value   SecureString password = new SecureString(); // needs value   X509Certificate2 cert = null;   X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   try {     store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.MaxAllowed);     cert = store.Certificates.Find(X509FindType.FindBySerialNumber, serial, false)[0];   }   finally {     store.Close();   }   if (cert.PrivateKey is RSACryptoServiceProvider == false)     throw new Exception("Unsupported key type.");   RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;   CspParameters cspParams = new CspParameters(1, rsa.CspKeyContainerInfo.ProviderName,     rsa.CspKeyContainerInfo.UniqueKeyContainerName) {     KeyPassword = password,     Flags = CspProviderFlags.NoPrompt   };   RSACryptoServiceProvider service = new RSACryptoServiceProvider(cspParams);   return service.SignData(data, CryptoConfig.MapNameToOID("SHA512")); }