DigitalSignatures

Sample C# code to use Apryse SDK's high-level digital signature API for digitally signing and/or certifying PDF files. Learn more about our UWP SDK and PDF Digital Signature Library.

1//
2// Copyright (c) 2001-2020 by PDFTron Systems Inc. All Rights Reserved.
3//
4
5// Uncomment this line if WinRTBouncyCastle is added as project reference.
6// #define USE_BOUNCYCASTLE
7
8using System;
9using System.Collections.Generic;
10using System.IO;
11using System.Threading.Tasks;
12using System.Runtime.InteropServices.WindowsRuntime;
13using Windows.Foundation;
14
15using pdftron.PDF;
16using pdftron.PDF.Annots;
17using pdftron.SDF;
18
19using Buffer = Windows.Storage.Streams.Buffer;
20using Convert = System.Convert;
21using PDFNetUniversalSamples.ViewModels;
22
23namespace PDFNetSamples
24{
25 public class DigitalSignaturesTest : Sample
26 {
27 public DigitalSignaturesTest() :
28 base("DigitalSignatures", "Demonstrates the basic usage of high-level digital signature API to digitally sign and/or certify PDF documents.")
29 {
30 }
31
32 public override IAsyncAction RunAsync()
33 {
34 return Task.Run(new System.Action(async () => {
35 WriteLine("--------------------------------");
36 WriteLine("Starting DigitalSignatures Test...");
37 WriteLine("--------------------------------\n");
38
39#if !USE_BOUNCYCASTLE
40 WriteLine("No crypto library used. Please try adding WinRTBouncyCastle as project refrence and define USE_BOUNCYCASTLE symbol.");
41 WriteLine("Download Bouncy Castle at: http://w8bouncycastle.codeplex.com/");
42 WriteLine("Sample will use a fake signature to sign the document instead.");
43#endif // USE_BOUNCYCASTLE
44 try
45 {
46 bool error = false;
47
48 //////////////////// TEST 0:
49 /* Create an approval signature field that we can sign after certifying.
50 (Must be done before calling CertifyOnNextSave/SignOnNextSave/WithCustomHandler.) */
51 try
52 {
53 PDFDoc document = new PDFDoc(Path.Combine(InputPath, "tiger.pdf"));
54 DigitalSignatureField approvalSignatureField = document.CreateDigitalSignatureField("PDFTronApprovalSig");
55 SignatureWidget widgetAnnotApproval = SignatureWidget.Create(document, new pdftron.PDF.Rect(300, 300, 500, 200), approvalSignatureField);
56 Page page1 = document.GetPage(1);
57 page1.AnnotPushBack(widgetAnnotApproval);
58 await document.SaveAsync(Path.Combine(OutputPath, "tiger_withApprovalField_output.pdf"), SDFDocSaveOptions.e_remove_unused);
59 await AddFileToOutputList(Path.Combine(OutputPath, "tiger_withApprovalField_output.pdf")).ConfigureAwait(false);
60 }
61 catch (Exception e)
62 {
63 WriteLine(GetExceptionMessage(e));
64 error = true;
65 }
66
67 //////////////////// TEST 1: certify a PDF.
68 try
69 {
70 await CertifyPDF(Path.Combine(InputPath, "tiger_withApprovalField.pdf"),
71 "PDFTronCertificationSig",
72 Path.Combine(InputPath, "pdftron.pfx"),
73 "password",
74 Path.Combine(InputPath, "pdftron.bmp"),
75 Path.Combine(OutputPath, "tiger_withApprovalField_certified_output.pdf"));
76
77 PrintSignaturesInfo(Path.Combine(OutputPath, "tiger_withApprovalField_certified_output.pdf"));
78
79 }
80 catch (Exception e)
81 {
82 WriteLine(GetExceptionMessage(e));
83 error = true;
84 }
85
86 //////////////////// TEST 2: sign a PDF with a certification and an unsigned signature field in it.
87 try
88 {
89 await SignPDF(Path.Combine(InputPath, "tiger_withApprovalField_certified.pdf"),
90 "PDFTronApprovalSig",
91 Path.Combine(InputPath, "pdftron.pfx"),
92 "password",
93 Path.Combine(InputPath, "signature.jpg"),
94 Path.Combine(OutputPath, "tiger_withApprovalField_certified_approved_output.pdf"));
95
96 PrintSignaturesInfo(Path.Combine(OutputPath, "tiger_withApprovalField_certified_approved_output.pdf"));
97 }
98 catch (Exception e)
99 {
100 WriteLine(GetExceptionMessage(e));
101 error = true;
102 }
103
104 //////////////////// TEST 3: Clear a certification from a document that is certified and has two approval signatures.
105 try
106 {
107 await ClearSignature(Path.Combine(InputPath, "tiger_withApprovalField_certified_approved.pdf"),
108 "PDFTronCertificationSig",
109 Path.Combine(OutputPath, "tiger_withApprovalField_certified_approved_certcleared_output.pdf"));
110
111 PrintSignaturesInfo(Path.Combine(OutputPath, "tiger_withApprovalField_certified_approved_certcleared_output.pdf"));
112 }
113 catch (Exception e)
114 {
115 WriteLine(GetExceptionMessage(e));
116 error = true;
117 }
118
119 //////////////////// End of tests. ////////////////////
120
121 if (error)
122 {
123 WriteLine("Tests FAILED!!!\n==========");
124 }
125 else
126 {
127 WriteLine("Tests successful.\n==========");
128 }
129 }
130 catch (Exception e)
131 {
132 WriteLine(GetExceptionMessage(e));
133 }
134
135 WriteLine("\n--------------------------------");
136 WriteLine("Done DigitalSignatures Test.");
137 WriteLine("--------------------------------\n");
138 })).AsAsyncAction();
139 }
140
141 private async Task SignPDF(string inputDocumentPath,
142 string inputApprovalFieldName,
143 string inputPrivateKeyFilePath,
144 string inputKeyFilePassword,
145 string inputAppearanceImagePath,
146 string inputOutPath)
147 {
148 WriteLine("================================================================================");
149 WriteLine("Signing PDF document");
150
151 // Open an existing PDF
152 PDFDoc document = new PDFDoc(inputDocumentPath);
153
154 // Sign the approval signatures.
155 Field foundApprovalField = document.GetField(inputApprovalFieldName);
156 DigitalSignatureField foundApprovalSignatureDigitalSignatureField = new DigitalSignatureField(foundApprovalField);
157 Image image = Image.Create(document.GetSDFDoc(), inputAppearanceImagePath);
158 SignatureWidget foundApprovalSignatureWidget = new SignatureWidget(foundApprovalField.GetSDFObj());
159 foundApprovalSignatureWidget.CreateSignatureAppearance(image);
160
161#if USE_BOUNCYCASTLE
162
163 // Create a new instance of the SignatureHandler.
164 MySignatureHandler signatureHandler = new MySignatureHandler();
165 byte[] signatureData = signatureHandler.CreateSignature();
166 signatureHandler.AppendData(signatureData);
167
168 // Add the SignatureHandler instance to PDFDoc, making sure to keep track of it using the ID returned.
169 var sigHandlerId = document.AddSignatureHandler(signatureHandler);
170 foundApprovalSignatureDigitalSignatureField.SignOnNextSaveWithCustomHandler(sigHandlerId);
171#else
172 foundApprovalSignatureDigitalSignatureField.SignOnNextSave(inputPrivateKeyFilePath, inputKeyFilePassword);
173#endif
174
175 await document.SaveAsync(inputOutPath, SDFDocSaveOptions.e_incremental);
176 WriteLine("Done. Result saved in " + inputOutPath);
177 await AddFileToOutputList(inputOutPath).ConfigureAwait(false);
178 WriteLine("================================================================================");
179 }
180
181 private async Task CertifyPDF(string inputDocumentPath,
182 string inputCertificateFieldName,
183 string inputPrivateKeyFilePath,
184 string inputKeyFilePassword,
185 string inputAppearanceImagePath,
186 string inputOutPath)
187 {
188 WriteLine("================================================================================");
189 WriteLine("Certifying PDF document");
190
191 // Open an existing PDF
192 PDFDoc document = new PDFDoc(inputDocumentPath);
193 WriteLine("PDFDoc has " + (document.HasSignatures() ? "signatures" : "no signatures"));
194
195 Page page1 = document.GetPage(1);
196
197 // Create a random text field that we can lock using the field permissions feature.
198 TextWidget annotation = TextWidget.Create(document, new pdftron.PDF.Rect(50, 550, 350, 600), "asdf_test_field");
199 page1.AnnotPushBack(annotation);
200
201 /* Create new signature form field in the PDFDoc. The name argument is optional;
202 leaving it empty causes it to be auto-generated. However, you may need the name for later.
203 Acrobat doesn't show digsigfield in side panel if it's without a widget. Using a
204 Rect with 0 width and 0 height, or setting the NoPrint/Invisible flags makes it invisible. */
205 DigitalSignatureField certificationSignatureField = document.CreateDigitalSignatureField(inputCertificateFieldName);
206 SignatureWidget widgetAnnot = SignatureWidget.Create(document, new pdftron.PDF.Rect(0, 100, 200, 150), certificationSignatureField);
207 page1.AnnotPushBack(widgetAnnot);
208
209 // (OPTIONAL) Add an appearance.
210
211 // Widget AP from image
212 Image image = Image.Create(document.GetSDFDoc(), inputAppearanceImagePath);
213 widgetAnnot.CreateSignatureAppearance(image);
214 // End of optional appearance-adding code.
215
216 // Add permissions. Lock the random text field.
217 WriteLine("Adding document permissions.");
218 certificationSignatureField.SetDocumentPermissions(DigitalSignatureFieldDocumentPermissions.e_annotating_formfilling_signing_allowed);
219 WriteLine("Adding field permissions.");
220 string[] fieldsToLock = new string[1];
221 fieldsToLock[0] = "asdf_test_field";
222 certificationSignatureField.SetFieldPermissions(DigitalSignatureFieldFieldPermissions.e_include, fieldsToLock);
223
224#if USE_BOUNCYCASTLE
225
226 // Create a new instance of the SignatureHandler.
227 MySignatureHandler signatureHandler = new MySignatureHandler();
228 byte[] signatureData = signatureHandler.CreateSignature();
229 signatureHandler.AppendData(signatureData);
230
231 // Add the SignatureHandler instance to PDFDoc, making sure to keep track of it using the ID returned.
232 var sigHandlerId = document.AddSignatureHandler(signatureHandler);
233 foundApprovalSignatureDigitalSignatureField.SignOnNextSaveWithCustomHandler(sigHandlerId);
234#else
235 certificationSignatureField.CertifyOnNextSave(inputPrivateKeyFilePath, inputKeyFilePassword);
236#endif
237
238 ///// (OPTIONAL) Add more information to the signature dictionary.
239 certificationSignatureField.SetLocation("Vancouver, BC");
240 certificationSignatureField.SetReason("Document certification.");
241 certificationSignatureField.SetContactInfo("www.pdftron.com");
242 ///// End of optional sig info code.
243
244 // Save the PDFDoc. Once the method below is called, PDFNetC will also sign the document using the information provided.
245 await document.SaveAsync(inputOutPath, 0);
246 WriteLine("Done. Result saved in " + inputOutPath);
247 await AddFileToOutputList(inputOutPath).ConfigureAwait(false);
248 WriteLine("================================================================================");
249 }
250
251 private void PrintSignaturesInfo(string inputDocumentPath)
252 {
253 try
254 {
255 WriteLine("================================================================================");
256 WriteLine("Reading and printing digital signature information");
257
258 PDFDoc document = new PDFDoc(inputDocumentPath);
259
260 if (!document.HasSignatures())
261 {
262 WriteLine("Doc has no signatures.");
263 WriteLine("================================================================================");
264 return;
265 }
266 else
267 {
268 WriteLine("Doc has signatures.");
269 }
270
271
272 for (FieldIterator fieldIterator = document.GetFieldIterator(); fieldIterator.HasNext(); fieldIterator.Next())
273 {
274 if (fieldIterator.Current().IsLockedByDigitalSignature())
275 {
276 WriteLine("==========\nField locked by a digital signature");
277 }
278 else
279 {
280 WriteLine("==========\nField not locked by a digital signature");
281 }
282
283 WriteLine("Field name: " + fieldIterator.Current().GetName());
284 WriteLine("==========");
285 }
286
287 WriteLine("====================\nNow iterating over digital signatures only.\n====================");
288
289 DigitalSignatureFieldIterator digitalSignatureFieldIterator = document.GetDigitalSignatureFieldIterator();
290 for (; digitalSignatureFieldIterator.HasNext(); digitalSignatureFieldIterator.Next())
291 {
292 WriteLine("==========");
293 WriteLine("Field name of digital signature: " + new Field(digitalSignatureFieldIterator.Current().GetSDFObj()).GetName());
294
295 DigitalSignatureField digitalSignatureField = digitalSignatureFieldIterator.Current();
296 if (!digitalSignatureField.HasCryptographicSignature())
297 {
298 WriteLine("Either digital signature field lacks a digital signature dictionary, " +
299 "or digital signature dictionary lacks a cryptographic Contents entry. " +
300 "Digital signature field is not presently considered signed.\n" +
301 "==========");
302 continue;
303 }
304
305 int certificateCount = Convert.ToInt32(digitalSignatureField.GetCertCount());
306 WriteLine("Cert count: " + certificateCount);
307 for (int i = 0; i < certificateCount; ++i)
308 {
309 byte[] certificateByteArray = digitalSignatureField.GetCert(Convert.ToUInt32(i));
310 WriteLine("Cert #" + i + " size: " + certificateByteArray.Length);
311 }
312
313 DigitalSignatureFieldSubFilterType subFilter = digitalSignatureField.GetSubFilter();
314
315 WriteLine("Subfilter type: " + Convert.ToInt32(subFilter));
316
317 if (subFilter != DigitalSignatureFieldSubFilterType.e_ETSI_RFC3161)
318 {
319 WriteLine("Signature's signer: " + digitalSignatureField.GetSignatureName());
320
321 Date signingTime = digitalSignatureField.GetSigningTime();
322 if (signingTime.IsValid())
323 {
324 WriteLine("Signing day: " + Convert.ToInt32(signingTime.day));
325 }
326
327 WriteLine("Location: " + digitalSignatureField.GetLocation());
328 WriteLine("Reason: " + digitalSignatureField.GetReason());
329 WriteLine("Contact info: " + digitalSignatureField.GetContactInfo());
330 }
331 else
332 {
333 WriteLine("SubFilter == e_ETSI_RFC3161 (DocTimeStamp; no signing info)\n");
334 }
335
336 WriteLine(((digitalSignatureField.HasVisibleAppearance()) ? "Visible" : "Not visible"));
337
338 DigitalSignatureFieldDocumentPermissions digitalSignatureDocumentPermissions = digitalSignatureField.GetDocumentPermissions();
339
340 var lockedFields = digitalSignatureField.GetLockedFields();
341 if (lockedFields != null)
342 {
343 foreach (string fieldName in lockedFields)
344 {
345 WriteLine("This digital signature locks a field named: " + fieldName);
346 }
347 }
348
349 switch (digitalSignatureDocumentPermissions)
350 {
351 case DigitalSignatureFieldDocumentPermissions.e_no_changes_allowed:
352 WriteLine("No changes to the document can be made without invalidating this digital signature.");
353 break;
354 case DigitalSignatureFieldDocumentPermissions.e_formfilling_signing_allowed:
355 WriteLine("Page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.");
356 break;
357 case DigitalSignatureFieldDocumentPermissions.e_annotating_formfilling_signing_allowed:
358 WriteLine("Annotating, page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.");
359 break;
360 case DigitalSignatureFieldDocumentPermissions.e_unrestricted:
361 WriteLine("Document not restricted by this digital signature.");
362 break;
363 default:
364 throw new Exception("Unrecognized digital signature document permission level.");
365 }
366 WriteLine("==========");
367 }
368
369 WriteLine("================================================================================");
370 }
371 catch (Exception e)
372 {
373 WriteLine(GetExceptionMessage(e));
374 }
375 }
376
377 private async Task ClearSignature(string inputDocumentPath,
378 string inputDigitalSignatureFieldName,
379 string inputOutPath)
380 {
381 WriteLine("================================================================================");
382 WriteLine("Clearing certification signature");
383
384 PDFDoc document = new PDFDoc(inputDocumentPath);
385
386 DigitalSignatureField digitalSignatureField = new DigitalSignatureField(document.GetField(inputDigitalSignatureFieldName));
387
388 WriteLine("Clearing signature: " + inputDigitalSignatureFieldName);
389 digitalSignatureField.ClearSignature();
390
391 if (!digitalSignatureField.HasCryptographicSignature())
392 {
393 WriteLine("Cryptographic signature cleared properly.");
394 }
395
396 // Save incrementally so as to not invalidate other signatures from previous saves.
397 await document.SaveAsync(inputOutPath, SDFDocSaveOptions.e_incremental);
398 WriteLine("Done. Result saved in " + inputOutPath);
399 await AddFileToOutputList(inputOutPath).ConfigureAwait(false);
400 WriteLine("================================================================================");
401 }
402 }
403
404 class MySignatureHandler : ISignatureHandler
405 {
406 private List<byte> m_data = null;
407
408 public MySignatureHandler()
409 {
410 m_data = new List<byte>();
411 }
412
413 public void AppendData(byte[] data)
414 {
415 m_data.AddRange(data);
416 }
417
418 public byte[] CreateSignature()
419 {
420#if USE_BOUNCYCASTLE
421 var ms = new MemoryStream(Convert.FromBase64String(m_pkcs12));
422 var p12Store = new Org.BouncyCastle.Pkcs.Pkcs12Store(ms, "password".ToCharArray());
423 String mainAlias = String.Empty;
424 foreach (var alias in p12Store.Aliases) {
425 mainAlias = alias.ToString();
426 break;
427 }
428 var akp = p12Store.GetKey(mainAlias).Key;
429 var x509Cert = p12Store.GetCertificate(mainAlias).Certificate;
430 var certs = new ArrayList();
431 certs.Add(x509Cert);
432 var certStore = Org.BouncyCastle.X509.Store.X509StoreFactory.Create("CERTIFICATE/Collection", new Org.BouncyCastle.X509.Store.X509CollectionStoreParameters(certs));
433
434 var sigGen = new Org.BouncyCastle.Cms.CmsSignedDataGenerator();
435 sigGen.AddSigner(akp, x509Cert, Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id);
436 sigGen.AddCertificates(certStore);
437 var data = new Org.BouncyCastle.Cms.CmsProcessableByteArray(m_data.ToArray());
438 var signedData = sigGen.Generate(data, false);
439 return (signedData.ContentInfo.GetDerEncoded());
440#else // USE_BOUNCYCASTLE
441 return (new byte[] { 0x00, 0x00, 0x00, 0x00 });
442#endif // USE_BOUNCYCASTLE
443 }
444
445 public String GetName()
446 {
447 return "Adobe.PPKLite";
448 }
449
450 public bool Reset()
451 {
452 m_data.Clear();
453 return (true);
454 }
455
456#if USE_BOUNCYCASTLE
457 private readonly String m_pkcs12 = @"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";
458#endif // USE_BOUNCYCASTLE
459 }
460}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales