Sign document error: Index was out of range

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’

Please Help,

@zboros

Could you please share following details and we’ll look into this scenario:

  • GroupDocs.Signature API version that you are using
  • Digital certificate
  • Sample application with the source file
  • Development environment (.NET or .NET Core etc)

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);
}
}

public DigitalSignature getLocalCertificate() {

List<DigitalSignature> digitalSignatures = DigitalSignature.LoadDigitalSignatures(StoreName.My, StoreLocation.CurrentUser);

foreach (DigitalSignature digitalSignature in digitalSignatures)
{

                foreach (var ext in digitalSignature.Certificate.Extensions)
                {
                    var eku = ext as X509EnhancedKeyUsageExtension;
                    if (eku != null)
                    {

                        foreach (var oid in eku.EnhancedKeyUsages)
                        {
                            string intendedPurposes = oid.FriendlyName;
                            if (intendedPurposes == "Document Signing")
                            {
                                return digitalSignature;
                            }
                        }
                    }


                }
            }

}

Thanks for your help,

@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.

Just wanted to add that this code works fine with Excel (xlsx) files without issues.

1 Like

@zboros

We appreciate the additional details and we’ll consider them during the investigation.

@zboros

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.

1 Like

@zboros

We will persist with the investigation and keep you informed of any progress updates.

@zboros

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”

@zboros

We’ll continue our investigation and notify you as there’s any update.

@zboros

We did some changes in the code and released stage NuGet version of GroupDocs.Signature. Can you please try it. Following are the instructions:

  1. Visual Studio -> Tools -> Options -> Nuget Package Manager -> Package Source. Add new test nuget source with url https://int.nugettest.org/api/v2
  2. 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.
  3. 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.

Thanks,

@zboros

Thanks for the feedback.

We’ll further investigate this scenario.

It happens on the .sign command and don’t have a way to troubleshoot what happens in that part of code. I tried several documents with same result.

@zboros

We will notify you in case of any progress update on this matter.

@zboros

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?

Yes I am using PageNumber=1 in code.

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?

Thanks,

@zboros

Thanks for the confirmation.

We still have to further investigate it.