Signing a signed PDF preserving the validity of the original signature

PDF TIFF SVG JPG C# VB
SignIncremental.cs
  1. //
  2. // This code is part of Document Solutions for PDF demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System;
  6. using System.IO;
  7. using System.Drawing;
  8. using GrapeCity.Documents.Pdf;
  9. using GrapeCity.Documents.Pdf.AcroForms;
  10. using GrapeCity.Documents.Text;
  11. using System.Security.Cryptography.X509Certificates;
  12.  
  13. namespace DsPdfWeb.Demos
  14. {
  15. // This sample generates and signs a PDF (using code that is similar to SignDoc sample),
  16. // and then signs the generated PDF with a second signature without invalidating the original
  17. // signature, by using incremental update (default when using the Sign() method).
  18. public class SignIncremental
  19. {
  20. public int CreatePDF(Stream stream)
  21. {
  22. var doc = new GcPdfDocument();
  23. // Load a signed document (we use code similar to the SignDoc sample):
  24. doc.Load(CreateAndSignPdf());
  25. // Init a second certificate:
  26. var pfxPath = Path.Combine("Resources", "Misc", "JohnDoe.pfx");
  27. var cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "secret",
  28. X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
  29. var sp2 = new SignatureProperties()
  30. {
  31. SignatureBuilder = new Pkcs7SignatureBuilder()
  32. {
  33. CertificateChain = new X509Certificate2[] { cert }
  34. },
  35. Location = "DsPdfWeb Demo Browser",
  36. SignerName = "DsPdfWeb",
  37. SigningDateTime = Common.Util.TimeNow(),
  38. };
  39. // Find the 2nd (not yet filled) signature field:
  40. var sfld2 = doc.AcroForm.Fields["SecondSignature"] as SignatureField;
  41. // Connect the signature field and signature props:
  42. sp2.SignatureField = sfld2 ?? throw new Exception("Unexpected: could not find 'SecondSignature' field");
  43. // Sign and save the document:
  44. doc.Sign(sp2, stream);
  45.  
  46. // Rewind the stream to read the document just created
  47. // into another GcPdfDocument and verify all signatures:
  48. stream.Seek(0, SeekOrigin.Begin);
  49. var doc2 = new GcPdfDocument();
  50. doc2.Load(stream);
  51. foreach (var fld in doc2.AcroForm.Fields)
  52. if (fld is SignatureField sfld)
  53. if (!sfld.Value.VerifySignatureValue())
  54. throw new Exception($"Failed to verify signature for field {sfld.Name}");
  55.  
  56. // Done (the generated and signed document has already been saved to 'stream').
  57. return doc.Pages.Count;
  58. }
  59.  
  60. // This method is almost exactly the same as the SignDoc sample,
  61. // but adds a second signature field (does not sign it though):
  62. private Stream CreateAndSignPdf()
  63. {
  64. var doc = new GcPdfDocument();
  65. var page = doc.NewPage();
  66. var tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 14 };
  67. page.Graphics.DrawString("Hello, World!\n" +
  68. "Signed TWICE by DsPdfWeb SignIncremental sample.",
  69. tf, new PointF(72, 72));
  70.  
  71. // Init a test certificate:
  72. var pfxPath = Path.Combine("Resources", "Misc", "DsPdfTest.pfx");
  73. var cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq",
  74. X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
  75. var sp = new SignatureProperties()
  76. {
  77. SignatureBuilder = new Pkcs7SignatureBuilder()
  78. {
  79. CertificateChain = new X509Certificate2[] { cert }
  80. },
  81. Location = "DsPdfWeb Demo Browser",
  82. SignerName = "DsPdfWeb",
  83. SigningDateTime = Common.Util.TimeNow(),
  84. };
  85.  
  86. // Init a signature field to hold the signature:
  87. var sf = new SignatureField();
  88. sf.Widget.Rect = new RectangleF(72, 72 * 2, 72 * 4, 36);
  89. sf.Widget.Page = page;
  90. sf.Widget.BackColor = Color.LightSeaGreen;
  91. // Add the signature field to the document:
  92. doc.AcroForm.Fields.Add(sf);
  93. // Connect the signature field and signature props:
  94. sp.SignatureField = sf;
  95.  
  96. // Add a second signature field:
  97. var sf2 = new SignatureField() { Name = "SecondSignature" };
  98. sf2.Widget.Rect = new RectangleF(72, 72 * 3, 72 * 4, 36);
  99. sf2.Widget.Page = page;
  100. sf2.Widget.BackColor = Color.LightYellow;
  101. // Add the signature field to the document:
  102. doc.AcroForm.Fields.Add(sf2);
  103.  
  104. var ms = new MemoryStream();
  105. doc.Sign(sp, ms);
  106. return ms;
  107. }
  108. }
  109. }
  110.