We are having similar problem with singing PDF and Word documents. We are evaluating with trial license to see if we can use the document signing feature with installed digital certificate on Windows 11. The PDF signed document is generated with the correct signature but the application always crashes at the following command:
SignResult result = signature.Sign(singedFilename, options);
Here is the Error:
GroupDocs.Signature.GroupDocsSignatureException: ‘Sign document error: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index’
Using Groupdocs.Total version 23.8
The certificate is a DOD certificate so I cannot share it, but I tried it with other certificates and the same happens.
Using .Net Framework 4.8
Here is the Code:
public bool signDocument(string filename) {
DigitalSignature sig = getLocalCertificate();
using (Signature signature = new Signature(filename))
{
DigitalSignOptions options = new DigitalSignOptions()
{
Signature = sig,
Left = 1,
Top = 1,
Height = 50,
Width = 200,
PageNumber = 1,
};
// sign document to file
signature.Sign(singedFilename, options);
}
}
@zboros
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.
Issue ID(s): SIGNATURENET-4759
You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.
It is hard to say what is wrong without having the source file and the certificate. We have checked the provided code locally, and it worked.
We may need the problematic certificate. Could you please try to use certificate as .PFX file in such way:
// Create a Signature instance for the "sample.pdf" file
using (Signature signature = new Signature("sample.pdf"))
{
// Define the options for digital signing
DigitalSignOptions options = new DigitalSignOptions("source.pfx")
{
Password = "1234567890" // Specify the password for the PFX file if there's any
};
// Sign the document and save it as "signed.pdf"
SignResult result = signature.Sign("signed.pdf", options);
}
The certificate is a DOD issued certificate which requires a CAC card to use. It does not have an exportable private key, so I cannot save it as a .pfx.
When I digitally sign an excel document using this certificate, I am prompted for the CAC card PIN which is working as expected.
However, when the document is a .pdf or .docx file, I am not prompted for PIN and get the above error. Somehow the certificate is handled differently between document types. Don’t think it’s a certificate issue as it is government issued.
When some local or external certificate storage is in use, it is possible to get digital signatures from it like it is done at method getLocalCertificate().
Every DigitalSignature object has Certificate property which contains X509Certificate2 object. If this X509Certificate2 object has an exportable private key it is suitable for document digital signing. Presents of private key depends on type of a certificate and type of its storage. It might be checked by using digitalSignature.Certificate.HasPrivateKey property.
MS Excel files support digital signing by using X509Certificate2 certificate object with exportable private key.
For PDF and MS Word there is no such possibility, so use this way to get stream with certificate and sign any supported document.
// Get the X509 certificate associated with the digital signature
X509Certificate2 x509 = digitalSignature.Certificate;
// Create a memory stream containing the certificate's raw data
MemoryStream certStream = new MemoryStream(x509.RawData);
// Sign the document using the certificate
using (Signature.Signature signature = new Signature.Signature(filePath))
{
// Configure digital signature options
DigitalSignOptions options = new DigitalSignOptions(certStream)
{
Password = "1234567890", // Set the password for the certificate
};
// Sign the document and save the signed file to the specified file path
signature.Sign(fileOutPath, options);
}
So I tried your example and come to a different error. Even though HasPrivateKey comes back as true I get the following error when signing:
“Sign document error: Specified certificate doesn’t contain private key”
We did some changes in the code and released stage NuGet version of GroupDocs.Signature. Can you please try it. Following are the instructions:
Visual Studio -> Tools -> Options -> Nuget Package Manager -> Package Source. Add new test nuget source with url https://int.nugettest.org/api/v2
If you are using GroupDocs.Total NuGet, to check the fix you should temporarily remove GroupDocs.Total and install GroupDocs.Signature NuGet from the test NuGet source. NuGet version number is 23.9.1-alpha-20231006092517.
The rest code should be same as you tried before
public bool SignDocument(string filename)
{
// Get the local digital signature certificate
DigitalSignature sig = GetLocalCertificate();
using (Signature signature = new Signature(filename))
{
// Define digital signing options
DigitalSignOptions options = new DigitalSignOptions()
{
Signature = sig,
Left = 1,
Top = 1,
Height = 50,
Width = 200,
PageNumber = 1,
};
// Sign the document and save it to a new file
signature.Sign(signedFilename, options);
}
// Return true if signing was successful, otherwise, return false
return true; // Modify this based on your success criteria
}
The fix which we done should add ability to e-sign PDF documents with certificates which don’t have exportable key. As far as Word documents are concerned, we need more time for investigation.
This is definitely in the right direction as this fix does work with PDF signing with CAC (smartcard). However there is one issue. We are prompted for CAC authentication PIN twice every time. If I cancel either one of those, it fails. If I plug my pin in each time than it works fine. Anyway to see why this is happening?
I did try a Word document and you are correct, we’re getting “Sign document error: KeyStore password must exist” error.
We noticed the code you sent, there is a property PageNumber = 1. So it means that signature will be applied to the first page only. Can you please confirm that your latest test code also has PageNumber = 1?
I tested couple other certificates and the one that is prompting for the pin code twice has “Key Usage” (in Certificate Details) with two values “Digital Signature, Non-Repudiation (c0)” where as the others have only one “Digital Signature”. Is this why this certificate prompts twice?