Signing PDF using the X509Certificate2 instead PFX file

We need signing PDF file with timestamp. But PdfFileSignature class support only signing with PFX file. For real using is it not possible (security reasons), because users has private key in crypto service provider or on card and they do not want/can export private key to PFX file.



For signing we need two different ways:


  1. use instance of X509Certificate2 similar as used in class PdfDigitalSignatureDetails in Aspose.Words for signing PDF during export to PDF.


  2. for signing in WEB browser use “detached” signature. Signing have three phases:
  • prepare PDF and compute hash for signing on WEB server (in Aspose)
  • signing computed hash on browser (in our Java applet)
  • input PKCS7 formated signature with certficate chain to prepared PDF on server (in Aspose)

Do you plan first or first and second our request implement to Aspose.Pdf? If yes, than when?

Hi there,


Thanks for your inquiry. Aspose.Pdf for .NET supports to sign PDF document with Timestamp server. Please check documentation link for the purpose. Moreover, as currently Aspose.Pdf solution does not support creation of signature objects (PKCS1, PKCS7, etc) with passing X509Certificate2. It applies as input parameter pfx files only. You may try to convert X509Certificate2 object into pfx object using following code snippet. Hopefully it will serve the purpose.

However, If the solution does not work for you then please let us know, we will log your requirements in our issue tracking system for further investigation and implementation.

var cert = new
X509Certificate2(Request.GetClientCertificate());<o:p></o:p>

byte[] data = cert.Export(X509ContentType.Pfx, "password");

File.WriteAllBytes("MyCerts.pfx", data);

Please feel free to contact us for any further assistance.


Best Regards,

Using X509Certificate2.Export is not possible (raise exception), when owner’s private key stored in:

a) Crypto Service Provider (CSP) without attribute “Exportable”

b) Hardware token



Serious application do not use PFX for signing (security reasons), because owner have not private key under control! PFX is primary for transport and backup use.

Hi there,


Thanks for your feedback. We have logged the issue, PDFNEWNET-37412, in our issue tracking system for further investigation and resolution. We will keep you updated about the issue resolution progress via this forum thread.

We are sorry for the inconvenience caused.

Best Regards,

Has this been fixed?

@windsorsolutions

Yes, the ticket was fixed. Now you can use ExternalSignature object that provides X509Certificate2 for signing document. In these examples the Windows certificate store used to get the certificate for signing:

// The System.Security.dll assembly should be added into References

// Signing 1. Using SignatureField
public void Sign_With_SmartCard_1()
{
    const string dataDir = @"c:\";

    File.Copy(dataDir + "blank.pdf", dataDir + "externalSignature1.pdf", true);
    using (FileStream fs = new FileStream(dataDir + "externalSignature1.pdf", FileMode.Open, FileAccess.ReadWrite))
    {
          using (Document doc = new Document(fs))
          {
               SignatureField field1 = new SignatureField(doc.Pages[1], new Rectangle(100, 400, 10, 10));

               // Sign with certificate selection in the windows certificate store
               X509Store store = new X509Store(StoreLocation.CurrentUser);
               store.Open(OpenFlags.ReadOnly);
               // Manually chose the certificate in the store
               X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null, X509SelectionFlag.SingleSelection);

               Aspose.Pdf.Forms.ExternalSignature externalSignature = new Forms.ExternalSignature(sel[0])
               {
                  Authority = "Me",
                  Reason = "Reason",
                  ContactInfo = "Contact"
               };

               field1.PartialName = "sig1";
               doc.Form.Add(field1, 1);
               field1.Sign(externalSignature);
               doc.Save();
         }
    }

    using (PdfFileSignature pdfSign = new PdfFileSignature(dataDir + "externalSignature1.pdf"))
    {
         IList<string> sigNames = pdfSign.GetSignNames();
         for (int index = 0; index <= sigNames.Count - 1; index++)
         {
             if (!pdfSign.VerifySigned(sigNames[index]) || !pdfSign.VerifySignature(sigNames[index])) 
             {
                 throw new ApplicationException("Not verified");  
             }
         }
    }
}
// Signing 2. Using PdfFileSignature
public void Sign_With_SmartCard_2()
{
   const string dataDir = @"c:\";

   Document doc = new Document(dataDir + "blank.pdf");

   using (PdfFileSignature pdfSign = new PdfFileSignature())
   {
         pdfSign.BindPdf(doc);

         //Sign with certificate selection in the windows certificate store
         X509Store store = new X509Store(StoreLocation.CurrentUser);
         store.Open(OpenFlags.ReadOnly);
         //manually chose the certificate in the store
         X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null,  X509SelectionFlag.SingleSelection);

         Aspose.Pdf.Forms.ExternalSignature externalSignature = new Forms.ExternalSignature(sel[0]);
         pdfSign.SignatureAppearance = dataDir + "demo.png";
         pdfSign.Sign(1, "Reason", "Contact", "Location", true, new System.Drawing.Rectangle(100, 100, 200, 200), externalSignature);
         pdfSign.Save(dataDir + "externalSignature2.pdf");
   }

   using (PdfFileSignature pdfSign = new PdfFileSignature(dataDir + "externalSignature1.pdf"))
   {
        IList<string> sigNames = pdfSign.GetSignNames();
        for (int index = 0; index <= sigNames.Count - 1; index++)
        {
             if (!pdfSign.VerifySigned(sigNames[index]) || !pdfSign.VerifySignature(sigNames[index])) 
             {
                 throw new ApplicationException("Not verified");  
             }
        }
    }
}