I am trying to add multiple digital signature in a single PDF file.
It was successful but the time the program added a new signature, old ones is now detected by Adobe reader as invalid.
What I did is just call the Signer.Sign() method to do the multiple signing, I do not know if this is the right way to do.
See image for example PDF Signature output
Below is my code
public class Signer
{
private readonly string source;
private readonly string destination;
private readonly Certificate certificate;
public Signer(string source, string destination, Certificate certificate)
{
this.source = source;
this.destination = destination;
this.certificate = certificate;
}
public void Sign(Signature signature, string hashAlgorithm, PdfSigner.CryptoStandard signatureType)
{
PdfReader reader = new(source);
PdfSigner signer = new(reader, new FileStream(this.destination, FileMode.Create), new StampingProperties());
PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
appearance.SetPageNumber(signature.PageNumber)
.SetPageRect(signature.Bounds)
.SetContact(signature.Contact)
.SetLocation(signature.Location)
.SetReason(signature.Reason)
.SetSignatureGraphic(signature.Image)
.SetRenderingMode(signature.RenderMode);
signer.SetFieldName(signature.FieldName);
IExternalSignature pks = new PrivateKeySignature(certificate.Key, hashAlgorithm);
signer.SignDetached(pks, certificate.Chain, null, null, null, 0, signatureType);
reader.Close();
}
public class Certificate
{
private readonly X509Certificate[] chain;
private readonly ICipherParameters key;
public X509Certificate[] Chain
{
get { return chain; }
}
public ICipherParameters Key
{
get { return key; }
}
public Certificate(string keystore, string password)
{
Pkcs12Store pk12 = new(new FileStream(keystore, FileMode.Open, FileAccess.Read), password.ToCharArray());
string? alias = null;
foreach (object a in pk12.Aliases)
{
alias = ((string)a);
if (pk12.IsKeyEntry(alias))
{
break;
}
}
key = pk12.GetKey(alias).Key;
X509CertificateEntry[] ce = pk12.GetCertificateChain(alias);
chain = new X509Certificate[ce.Length];
for (int k = 0; k < ce.Length; k)
{
chain[k] = ce[k].Certificate;
}
}
}
public class Signature
{
private readonly string fieldName;
private readonly int pageNumber;
public string FieldName {
get { return fieldName; }
}
public int PageNumber {
get { return pageNumber; }
}
public string Contact { get; set; } = String.Empty;
public string Reason { get; set; } = String.Empty;
public string Location { get; set; } = String.Empty;
public RenderingMode RenderMode { get; set; } = RenderingMode.GRAPHIC;
public Rectangle? Bounds { get; set; }
public ImageData? Image { get; set; }
public Signature(string fieldName, int pageNumber)
{
this.fieldName = fieldName;
this.pageNumber = pageNumber;
}
}
}
Implementation
public static void Sign()
{
string source = "V06.pdf";
string destination1 = "V06.signed1.pdf";
string destination2 = "V06.signed2.pdf";
Certificate certificate = new("121550.p12", "password");
Signer sign1 = new(source, destination1, certificate);
Signature signature1 = new("Sign1", 1)
{
RenderMode = RenderingMode.GRAPHIC,
Contact = "000000",
Location = "PH",
Reason = "Valid",
Bounds = new Rectangle(70, 148, 100, 35),
Image = ImageDataFactory.Create("Untitled.png")
};
sign1.Sign(signature1, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS);
Signer sign2 = new(destination1, destination2, certificate);
Signature signature2 = new("Sign2", 1)
{
RenderMode = RenderingMode.GRAPHIC,
Contact = "000000",
Location = "PH",
Reason = "OK",
Bounds = new Rectangle(170, 148, 100, 35),
Image = ImageDataFactory.Create("Untitled.png")
};
sign2.Sign(signature2, DigestAlgorithms.SHA256, PdfSigner.CryptoStandard.CMS);
}
CodePudding user response:
If you are using iText 7, I guess you should try using UseAppendMode()
PdfSigner signer = new PdfSigner(reader, new FileStream(dest, FileMode.Create), tmp, new StampingProperties().UseAppendMode());
Please refer to https://stackoverflow.com/a/64386351/6235557