Hi Pawel,
Please try again with this NuGet package:
Install-Package GemBox.Pdf -Version 2025.7.103
Note that this is a hidden (unlisted) version. To install it, you’ll need to run the above command on the NuGet Package Manager Console (Tools → NuGet Package Manager → Package Manager Console).
Also, try running the following:
using System;
using System.IO;
using System.Linq;
using System.Threading;
using GemBox.Pdf;
using GemBox.Pdf.Forms;
using GemBox.Pdf.Security;
static class Program
{
static void Main()
{
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (!Directory.Exists(Path.Combine(desktop, "SignedFiles")))
Directory.CreateDirectory(Path.Combine(desktop, "SignedFiles"));
// Extract GemBoxPkcs11SoftwareModule from ZIP archive and setup environment variable with path to configuration file.
// Required only for SoftHSM device used in this example. Not required for yours PKCS#11/Cryptoki device.
var pkcs11SoftwareModuleDirectory = "GemBoxPkcs11SoftwareModule";
if (!Directory.Exists(pkcs11SoftwareModuleDirectory))
System.IO.Compression.ZipFile.ExtractToDirectory(Path.Combine(desktop, "GemBoxPkcs11SoftwareModule.zip"), pkcs11SoftwareModuleDirectory);
Environment.SetEnvironmentVariable("SOFTHSM2_CONF", Path.Combine(pkcs11SoftwareModuleDirectory, "softhsm2.conf"));
var errors = SignConcurrent(
20,
Path.Combine(desktop, "Reading.pdf"),
Path.Combine(desktop, "SignedFiles"),
"File",
Path.Combine(pkcs11SoftwareModuleDirectory, IntPtr.Size == 8 ? "softhsm2-x64.dll" : "softhsm2.dll"),
"GemBoxECDsaToken",
"GemBoxECDsaPin",
"GemBoxECDsa521",
"GemBoxECDsa");
if (errors == null)
Console.WriteLine("No errors!");
else
Console.WriteLine("There were errors while doing concurrent signing.");
}
private static Exception[]? SignConcurrent(int signerCount, string inputPdfPath, string outputPdfDirectory, string outputPdfFilePrefix, string libraryPath, string tokenLabel, string pin, string digitalIdSubjectCommonName, string? intermediateCASubjectCommonName = null)
{
ConcurrentSigner[] signers;
using (var pkcs11Module = new PdfPkcs11Module(libraryPath))
{
var token = pkcs11Module.Tokens.Single(t => t.TokenLabel == tokenLabel);
token.Login(pin);
signers = Enumerable.Range(0, signerCount).Select(i => new ConcurrentSigner(inputPdfPath, Path.Combine(outputPdfDirectory, outputPdfFilePrefix + i + ".pdf"), digitalIdSubjectCommonName, token, intermediateCASubjectCommonName)).ToArray();
Array.ForEach(signers, s => s.Prepare());
var threads = Array.ConvertAll(signers, s => new Thread(s.Sign) { IsBackground = true });
Array.ForEach(threads, t => t.Start());
Array.ForEach(threads, t => t.Join());
token.Logout();
}
var errors = Array.ConvertAll(signers, s => s.Error);
return Array.TrueForAll(errors, e => e == null) ? null : errors;
}
class ConcurrentSigner
{
private readonly string inPath, outPath, digitalIdSubjectCommonName;
private readonly PdfPkcs11Token globalToken;
private readonly string? intermediateCASubjectCommonName;
private PdfDocument document;
public Exception? Error { get; private set; }
public ConcurrentSigner(string inPath, string outPath, string digitalIdSubjectCommonName, PdfPkcs11Token globalToken, string? intermediateCASubjectCommonName = null)
{
this.inPath = inPath;
this.outPath = outPath;
this.digitalIdSubjectCommonName = digitalIdSubjectCommonName;
this.globalToken = globalToken;
this.intermediateCASubjectCommonName = intermediateCASubjectCommonName;
}
public void Prepare()
{
this.document = PdfDocument.Load(this.inPath, new PdfLoadOptions() { ReadOnly = true });
}
public void Sign()
{
// Finish signing of a PDF file.
using (this.document)
using (var token = this.globalToken.Clone())
try
{
// Add a visible signature field to the first page of the PDF document.
var signatureField = this.document.Form.Fields.AddSignature(this.document.Pages[0], 300, 500, 250, 50);
// Get a digital ID from PKCS#11/Cryptoki device token.
var digitalId = token.DigitalIds.Single(id => id.Certificate.SubjectCommonName == digitalIdSubjectCommonName);
// Create a PDF signer that will create the digital signature.
var signer = new PdfSigner(digitalId);
if (this.intermediateCASubjectCommonName is not null)
{
// Adobe Acrobat Reader currently doesn't download certificate chain
// so we will also embed certificate of intermediate Certificate Authority in the signature.
// (see https://community.adobe.com/t5/acrobat/signature-validation-using-aia-extension-not-enabled-by-default/td-p/10729647)
var intermediateCA = token.DigitalIds.Single(id => id.Certificate.SubjectCommonName == this.intermediateCASubjectCommonName).Certificate;
signer.ValidationInfo = new PdfSignatureValidationInfo(new PdfCertificate[] { intermediateCA }, null, null);
}
// Initiate signing of a PDF file with the specified signer.
signatureField.Sign(signer);
this.document.Save(this.outPath);
this.Error = null;
Console.WriteLine($"Signed '{this.outPath}'.");
}
catch (Exception ex)
{
this.Error = ex;
Console.WriteLine($"Error while signing '{this.outPath}'.");
}
this.document = null;
}
}
}
Does this solve your issue?
Regards,
Mario