We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Digital signature from HSW with no exportable private key

Hello,
I'm trying to sign a pdf using a cert on HSW, of course it private key cannot be exported.
I did a research and so many tests but I cannot achieve my target.

I found that in this forum: 
https://www.syncfusion.com/forums/148505/fileformats-pdf-digital-signature-by-smartcard

but when I try it, get the error: "no private key", saving the signed PDF

This is my code:


            //Load the PDF document. 
            var StreamFile = new FileStream(@"\src\test.pdf", FileMode.Open);
            PdfLoadedDocument loadedDocument = new PdfLoadedDocument(StreamFile);

            //Load the existing page. 
            PdfLoadedPage page = loadedDocument.Pages[0] as PdfLoadedPage;

            //Create PDF certificate with X509Certicate2 object. 
            byte[] my509 = Encoding.ASCII.GetBytes(cert.InnerText);  //get my cert, extracted from eToken
            X509Certificate2 Tokencertificate = new X509Certificate2(my509);
            PdfCertificate certificate = new PdfCertificate(Tokencertificate /* x509 certificate retrieved from smartcard */);

            PdfSignature signature = new PdfSignature(loadedDocument, page, certificate, "Sig1");
            signature.Bounds = new RectangleF(0, 0, 200, 100);

            //Save and close the PDF document. 
            loadedDocument.Save(StreamFile);    //here error: 'No private key'
            

            loadedDocument.Close(true);



I hope you can help me.
Regards,
Martin

28 Replies 1 reply marked as answer

MK Moorthy Karunanithi Syncfusion Team November 20, 2020 02:35 PM UTC

Hi Martin, 
We have tried to reproduce the reported exception, but we regret let you know we were unable to reproduce mentioned exception in our end. However, we have created a sample to sign PDF externally using smart card certificate. The sample can be downloaded from the below link,  
Please try the above attached sample with your smart card certificate and let us know the result.  
Regards, 
Moorthy K 



MD Martin de los Rios November 20, 2020 03:43 PM UTC

Hi,
Thanks for answer.

Let me know if this example shoud only be used on windows form / console or, if I can use it on webforms, blazor, mvc ? I guess not...
I wonder can do it with jquery or javascript on client side. is it possible?


GK Gowthamraj Kumar Syncfusion Team November 23, 2020 11:45 AM UTC

Hi Martin,   
 
Thank you for your update. 
 
Yes, the sample which we provided in the previous update will work in WebForms, Blazor, MVC and now we have created the sample in ASP.NET WebForms platform. Please find the sample and download link below,   
 
 
Regards, 
Gowthamraj K 


Marked as answer

MD Martin de los Rios November 26, 2020 06:27 PM UTC

Thank you so so much. Works perfect!

I've one more question:
I cannot handle the exceptions on Signature_ComputeHash
For example, if user click cancel on HSW interface, the following line produce an exception: 

signedCms.ComputeSignature(cmsSigner)

This exception I cannot handle it. 
If I use try catch, exception is handled but method document.save create the pdf anyway. 

I need to stop the process if user cancel.
please any cue?


GK Gowthamraj Kumar Syncfusion Team November 27, 2020 12:34 PM UTC

Hi Martin, 

Thank you for your update. 

Kindly please share more details about the reported issue such as a complete code snippet, modified sample with a dummy user interface to reproduce the issue on our end. So, that it will be helpful for us to analyze and assist you further on this.   

Regards, 
Gowthamraj K 



MD Martin de los Rios November 27, 2020 05:21 PM UTC

Ok, it is the same you send me as example, with some adjust.
Here it is

    public partial class _Default : Page
    {

        protected void Page_Load(object sender, EventArgs e)
        {

            if (!IsPostBack) { 
            ListBox1.DataSource = RecuperarCertificados();
            ListBox1.DataTextField = "subject";
            ListBox1.DataBind();
            }

        }


        private X509Certificate2Collection RecuperarCertificados()
        {
            X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
            X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
            return collection;
        }


        protected void OnButtonClicked(object sender, EventArgs e)
        {
            string docPath = Server.MapPath("/App_Data/Barcode.pdf");
            PdfLoadedDocument document = new PdfLoadedDocument(docPath);

            //Create a revision 2 signature with loaded digital ID.
            PdfSignature signature = new PdfSignature(document, document.Pages[0], null, "DigitalSignature");
            signature.ComputeHash += Signature_ComputeHash;

            //Open the document in browser after saving it
            document.Save("MiOutput.pdf", HttpContext.Current.Response, HttpReadType.Save);

            document.Close(true);
        }

        private void Signature_ComputeHash(object sender, PdfSignatureEventArgs ars)
        {
            //Get the document bytes.
            byte[] documentBytes = ars.Data;

            SignedCms signedCms = new SignedCms(new ContentInfo(documentBytes), detached: true);

            X509Certificate2Collection collection = RecuperarCertificados();

            //load your smart card certificate
            X509Certificate2 certificate = new X509Certificate2(collection[ListBox1.SelectedIndex]);
            CmsSigner cmsSigner = new CmsSigner(certificate);
            //Set the digest algorithm SHA256.
            cmsSigner.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
            signedCms.ComputeSignature(cmsSigner);
            //Embed the encoded digital signature to the PDF document.
            ars.SignedData = signedCms.Encode();
        }
    }


I'm attaching for you the running use case and error.
I need to handle error like this (user cancelled on HSW operation, or fails reading cert, or so), but I can't handle it with try catch.
If I use Try catch, excception is catched but pdf is created anyway.
look at attach please


Attachment: syncfusionPDF1_1cd33092.zip


GK Gowthamraj Kumar Syncfusion Team November 30, 2020 12:34 PM UTC

Hi Martin, 

Thank you for sharing the details   
  
When we sign the PDF document from an external digital signature using a smart card certificate, it triggers the Signature_ComputeHash event at the document.Save() call. We are saving the signed hash into the PDF document. If the user cancel the process, the document will be created with an invalid signature. This is our actual behavior of digital signature.   
  
Please refer to this below link for more information,   
 
Please let us know if you need any further assistance with this.  

Regards, 
Gowthamraj K 



MD Martin de los Rios August 19, 2021 04:08 PM UTC

Hello,

I'm here again with one more issue:

This code works ok on my development environment. 

When I try to run my web app on production server, I cannot reach cert on my client HSM, never ask me for PIN.

Please tell me if I need to pay attention to something on the production environment to works.

regards

Martin



GK Gowthamraj Kumar Syncfusion Team August 20, 2021 01:03 PM UTC

Hi Martin, 
 
Thank you for your update.

 
We request you to share the simple sample, certificates details, production environment details (OS, bit version, culture settings) to check the issue on our end. However, we can have web meeting to look into the issue directly on your production server and provide the solution earlier. Please let us know your availability for web meeting, we will make every effort to have this scheduled on a time of your convenience. 
 
Note: We are working in IST hours.

Once you confirmed your availability, we can create a new incident and share the meeting invites.
 
 
Regards, 
Gowthamraj K 



MD Martin de los Rios August 20, 2021 08:41 PM UTC

Thanks for your promptly answer,

Before web meeting, that will be great (I'm in GMT-3), I can expose info that you request.

Regards availability, no problem at all. Any light time (GMT-3)  is ok


Server: Azure VM Windows 2016

Culture settings: OS (english), WebApp (Spanish)

Syncfusion version: 19.2.0.56

Code:

Snippet
Public Function TokenDisponibleparaFirma() As Boolean
    Dim document As PdfDocument = New PdfDocument()
    document.Pages.Add()
    Dim signature As PdfSignature = New PdfSignature(document, document.Pages(0), Nothing"DigitalSignature")
    AddHandler signature.ComputeHash, AddressOf Signature_ComputeHash
 
    Dim stream As MemoryStream = New MemoryStream()
    document.Save(stream)
    document.Close(True)
    Return DigitalSignatureSuccess
End Function
Snippet
Private Function RecuperarCertificadoArgentino() As X509Certificate2
    Dim FirmaDigitalEmisorArgentino As String = "Autoridad Certificante de Firma Digital"
    Dim certEncontrado As X509Certificate2 = Nothing
    Dim store As X509Store = New X509Store("MY", StoreLocation.CurrentUser)
    store.Open(OpenFlags.[ReadOnly] Or OpenFlags.OpenExistingOnly)
 
    For Each cert As X509Certificate2 In store.Certificates
        If Mid(cert.Issuer, 439= FirmaDigitalEmisorArgentino Then
            certEncontrado = cert
            Exit For
        End If
    Next
    Return certEncontrado
End Function
Snippet
Private Sub Signature_ComputeHash(ByVal sender As ObjectByVal ars As PdfSignatureEventArgs)
    Dim documentBytes As Byte() = ars.Data
    Dim signedCms As SignedCms = New SignedCms(New ContentInfo(documentBytes), detached:=True)
    Try
        Dim Certificado As X509Certificate2 = RecuperarCertificadoArgentino()
        If Certificado Is Nothing Then
            DigitalSignatureSuccess = False
            DigitalSignatureResultMessage = "No se encuentra un token con certificado válido.<br /><br />Debe contar con Token, certificado válido e instalar el software del token.<br />" & MensajeDescargaDriver()
            Exit Sub
        End If
 
        DigitalSignatureSuccess = True
        DigitalSignatureResultMessage = Certificado.Thumbprint
        DigitalSignatureValidTo = Certificado.GetExpirationDateString
        Dim cmsSigner As CmsSigner = New CmsSigner(Certificado)
        cmsSigner.DigestAlgorithm = New Oid("2.16.840.1.101.3.4.2.1")
        signedCms.ComputeSignature(cmsSigner)
        ars.SignedData = signedCms.Encode()
    Catch ex As Exception
        DigitalSignatureSuccess = False
        DigitalSignatureResultMessage = "error: " + ex.Message
 
        If DigitalSignatureResultMessage = "error: El conjunto de claves no está definido" Then DigitalSignatureResultMessage = MensajeDescargaDriver()
    End Try
End Sub


GK Gowthamraj Kumar Syncfusion Team August 23, 2021 12:00 PM UTC

Hi Martin, 
 
Thank you for your update. 
 
Currently, we are trying to reproduce the reported issue in same environment on our end and we will update the further details on August 25th 2021.  
 
Note: For an Azure platform, we have to mention where and how to get the private key of certificate using KeyStorageFlags. 
Dim x509 As X509Certificate2 = New X509Certificate2("cert", "password123", X509KeyStorageFlags.MachineKeySet Or X509KeyStorageFlags.PersistKeySet Or X509KeyStorageFlags.Exportable) 
 
Please refer the below link to know more about the KeyStorageFlags.   
    
Regards, 
Gowthamraj K 



MD Martin de los Rios August 23, 2021 01:18 PM UTC

UPDATE

Hello, I just run you posted sample in this thread.

Here the code for your reference:

Snippet
namespace PDFSample
{
    public partial class _Default : Page
    {
 
        protected void Page_Load(object sender, EventArgs e)
        {
            LoadCerts();
        }
 
 
        protected void OnButtonClicked(object sender, EventArgs e)
        {
            string docPath = Server.MapPath("/App_Data/Barcode.pdf");
            PdfLoadedDocument document = new PdfLoadedDocument(docPath);
 
            //Create a revision 2 signature with loaded digital ID.
            PdfSignature signature = new PdfSignature(document, document.Pages[0], null"DigitalSignature");
            signature.ComputeHash += Signature_ComputeHash;
 
            //Open the document in browser after saving it
            document.Save("Output.pdf", HttpContext.Current.Response, HttpReadType.Save);
 
            document.Close(true);
        }
 
        private void Signature_ComputeHash(object sender, PdfSignatureEventArgs ars)
        {
            //Get the document bytes.
            byte[] documentBytes = ars.Data;
 
            SignedCms signedCms = new SignedCms(new ContentInfo(documentBytes), detached: true);
            X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
            X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
            //load your smart card certificate
 
            X509Certificate2 certificate = new X509Certificate2(collection[1]);
            CmsSigner cmsSigner = new CmsSigner(certificate);
            //Set the digest algorithm SHA256.
            cmsSigner.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
            signedCms.ComputeSignature(cmsSigner);
            //Embed the encoded digital signature to the PDF document.
            ars.SignedData = signedCms.Encode();
        }
 
 
        protected void LoadCerts()
        {
            X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
            X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
 
            foreach (var c in collection)
            {
                X509Certificate2 certificate = new X509Certificate2(c);
                ListBox1.Items.Add(new ListItem(c.Issuer.ToString()));
            }
                
 
 
        }
 
        protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
 
        }
    }
}


If I debug this code on my Visual Studio with HSM connected, it recovers cert on it and shows them in listbox.

If I publish and deploy it to my server, when I browse it from my machine with HSM connected, no one cert showed in listbox, no one cert is read from server



MD Martin de los Rios August 23, 2021 02:11 PM UTC

UPDATE 2

listing all certs on all stores with this:

Snippet
protected void allcerts()
{
    foreach (StoreLocation storeLocation in (StoreLocation[])
   Enum.GetValues(typeof(StoreLocation)))
    {
        string tt = "";
        foreach (StoreName storeName in (StoreName[])
            Enum.GetValues(typeof(StoreName)))
        {
            X509Store store = new X509Store(storeName, storeLocation);
            try
            {
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
 
                foreach (var c in collection)
                {
                    X509Certificate2 certificate = new X509Certificate2(c);
                    tt = store.Name + " - " + store.Location + ": " + c.Issuer;
                    ListBox2.Items.Add(new ListItem(tt));
                }
 
            }
            catch (CryptographicException)
            {
                tt = "No - " + store.Name + " - " + store.Location;
            }
        }
        ListBox2.Items.Add(new ListItem(tt));
    }
}


running it on visual studio, it gets my cert on hsm in "My - Current user" store

running it on server, it lists no one cert from "My - Current user" store






GK Gowthamraj Kumar Syncfusion Team August 24, 2021 02:29 PM UTC

Hi Martin, 
 
Thank you for your update.

 
We suspect the reported issue may occurs due to the current user does have enough permission to access the certificate from server machine with HSM connected. Kindly check the HSM have enough permission to import certificates to server? Also please mark the certificate as exportable while installing in your machine.  
 
Please refer the below screenshot for change the certificate to exportable,  
   
 
Also run the application with “Run as Administrator” and let us know the result.

 
Regards, 
Gowthamraj K 



MD Martin de los Rios August 24, 2021 09:16 PM UTC

thanks for answer.

I'm not sure to understand you.

Let me overview the issue:

- This is a NET framework 4.8 Web App, running on IIS.

- Web App is accessible via browser from client Windows PC.

- Client connect his HSM (USB token with embedded cert) on his Windows PC, cert is accessible via SafeNet Authentication Client software.

- Cert in HSM is not exportable, it is impossible to extract from the device.

- Obviously it is not on server, it is on client computer. 


Regards your answer:

- What user may access to what location store/cert?

- HSM not allow export certs at all. How is suppose to do that?


Kind regards,

Martin



GK Gowthamraj Kumar Syncfusion Team August 25, 2021 02:31 PM UTC

Hi Martin, 
 
Thank you for your update.

 
Currently, we are analyzing this on our end and we will update the further details on August 27th 2021.   

Regards,
 
Gowthamraj K 



GK Gowthamraj Kumar Syncfusion Team August 27, 2021 01:43 PM UTC

Hi Martin, 
 
Thank you for your patience.


 
On our further analysis, it is not possible to retrieve the list of certificates from “My Current user” of the client machine. When we host the application in server, the local certificates will not be retrieve in client browsers. To overcome this, we are suggested to create a utility tool like running the application in client machine, so that we get the list of certificates.    
 
Regards, 
Gowthamraj K 



MD Martin de los Rios August 27, 2021 03:47 PM UTC

Thanks for answer.

Let me say that I am quite upset and disagree with the development of this thread.

From the beginning, yourself have made it clear that this was possible (read above). 

Now it happens that it is not possible to do it?

Syncfusion ensures that this component works with HSM in a webapp, which seems not to be true ...


Please, how can we solve this?

What solution do you propose? I create an app on the client, how would it be?

I have researched and there are other solutions that capture the cert via javascript, do you think it is possible to do something like this, thus completing your product and really doing what Syncfusion say it does?

Please, I await a slightly more satisfactory answer.

Kind regards,

Martin



GK Gowthamraj Kumar Syncfusion Team August 30, 2021 12:49 PM UTC

Hi Martin,

Thank you for your update.

We use “X509Store” to get the certificate from HSM connected in that machine. We cannot access the client certificate store from server using “X509Store” API. This is the default behavior of “X509Store” API. We suggest you to sign the PDF document in client side using console or Win forms application with the same code or you can upload your secret key in azure vault and you can sign the PDF document

Please refer the documentation for more information.
https://www.syncfusion.com/kb/11601/how-to-sign-pdf-document-using-azure-key-vault  

Regards,
Gowthamraj K


MD Martin de los Rios August 30, 2021 07:56 PM UTC

Thanks for update.

I understand. 

You should understand too, Syncfusion signing from web solution is completely unusable. It has no sense...

Your proposed solution exporting cert to Azure Key Vault is interesting but remember that it's impossible export or extract cert from HSM hardware token. Nobody can get pfx or p12 file from it. Due that design limitation it cannot be stated like a solution.

Certainly so sad because I worked hard to implement it and after deploy it, discover that doesn't work.

I expected a little more.

Martin



MD Martin de los Rios August 30, 2021 08:57 PM UTC

Can I sign PDF using syncfusion on javascript or blazor?



MK Moorthy Karunanithi Syncfusion Team August 31, 2021 02:18 PM UTC

  
Hi Martin, 
 
Thanks for the update, 
 
As we said earlier, We have sign the PDF document using the X509Store and it has been retrieved the certificate from the web application server side and it fails on retrieving the certificate from the client side. Due to this we are not able to sign the document on the client (WASM). So our library is supported on the web application (server side). 
 
Regards, 
Moorthy K 



MD Martin de los Rios January 11, 2022 03:01 PM UTC

Hi guys. I'm back to check updates on the component.
Please, may you tell me if still it's not possible to sign with HSM on browser client for a .net web app? (WASM) on the client side.

Regards



GK Gowthamraj Kumar Syncfusion Team January 12, 2022 10:46 AM UTC

Hi Martin,  
  
Thanks for the update, 
 
As we said earlier, The progress fails on retrieving the certificate from the client-side. This is the reason, we are not able to sign the document on the client (WASM). Our syncfusion library is supported on the web application (server-side). It is not possible to sign PDF with WASM on the client-side using HSM. 
 
Regards, 
Gowthamraj K 



RI Razvan Iacobescu March 30, 2023 11:39 AM UTC

Hi, regarding the conversation above I wanna ask if I can sign the pdf document using Blazor server. 

Scenario: User access our blazor app at www.ourapp.com and inserting the usb and select a part of pdf and a pop appears where he can enter the pin code.

So with this in mind I wanna ask if the user can select a rectangle on the pdf (using syncfusion pdf preview server) where the signature will appear.


Thank you!



IJ Irfana Jaffer Sadhik Syncfusion Team March 31, 2023 04:15 PM UTC

Yes, we can sign the pdf document on blazor server. We have attached the sample for your reference.

Sample:https://www.syncfusion.com/downloads/support/directtrac/general/ze/ServerSideApplication-432711007

Please find the below link for invisible signing the PDF document using the Blazor PdfViewer component:

https://blazor.syncfusion.com/demos/pdf-viewer/invisible-digital-signature?theme=fluent


Please note that the act of signing a PDF document with a USB token or a Windows certificate store is limited to server-oriented applications due to the need to access locally installed Windows certificates. If you attempt to sign a document using a USB token installed on your own machine while hosting an application on the web, this will not be successful. Instead, a deferred signing procedure is recommended in this scenario. This involves locally signing the PDF document and sending the resulting hash to the server to be applied to the PDF document.


Kindly refer to the below link for more information,

https://help.syncfusion.com/file-formats/pdf/working-with-digitalsignature#deferred-signing-in-pdf-document





RI Razvan Iacobescu April 12, 2023 04:08 PM UTC

Thank you! We have manage to create a windows application that sign the document and send it to the web.

My question is how can I add a button to the "SfPdfViewerServer" Toolbar with a label "My signature", and when the user click on it it will be able to draw a rectangle on a pdf page and after that an event will fired like "mouseup", and retrieve the x,y,w,h of the rectangle.

We have created something custom but in this context does not work.


Thank you!



IJ Irfana Jaffer Sadhik Syncfusion Team replied to Razvan Iacobescu April 13, 2023 05:55 AM UTC

We have branched a new forum for the last reported query,

please follow up on this forum id- https://forumassist.syncfusion.com/181771   for further updates.


Loader.
Live Chat Icon For mobile
Up arrow icon