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 Xamarin SDK and PDF Digital Signature Library.

1//
2// Copyright (c) 2001-2021 by PDFTron Systems Inc. All Rights Reserved.
3//
4
5//----------------------------------------------------------------------------------------------------------------------
6// This sample demonstrates the basic usage of the high-level digital signatures API in PDFNet.
7//
8// The following steps reflect typical intended usage of the digital signatures API:
9//
10// 0. Start with a PDF with or without form fields in it that one would like to lock (or, one can add a field, see (1)).
11//
12// 1. EITHER:
13// (a) Call doc.CreateDigitalSignatureField, optionally providing a name. You receive a DigitalSignatureField.
14// -OR-
15// (b) If you didn't just create the digital signature field that you want to sign/certify, find the existing one within the
16// document by using PDFDoc.DigitalSignatureFieldIterator or by using PDFDoc.GetField to get it by its fully qualified name.
17//
18// 2. Create a signature widget annotation, and pass the DigitalSignatureField that you just created or found.
19// If you want it to be visible, provide a Rect argument with a non-zero width or height, and don't set the
20// NoView and Hidden flags. [Optionally, add an appearance to the annotation when you wish to sign/certify.]
21//
22// [3. (OPTIONAL) Add digital signature restrictions to the document using the field modification permissions (SetFieldPermissions)
23// or document modification permissions functions (SetDocumentPermissions) of DigitalSignatureField. These features disallow
24// certain types of changes to be made to the document without invalidating the cryptographic digital signature once it
25// is signed.]
26//
27// 4. Call either CertifyOnNextSave or SignOnNextSave. There are three overloads for each one (six total):
28// a. Taking a PKCS #12 keyfile path and its password
29// b. Taking a buffer containing a PKCS #12 private keyfile and its password
30// c. Taking a unique identifier of a signature handler registered with the PDFDoc. This overload is to be used
31// in the following fashion:
32// i) Extend and implement a new SignatureHandler. The SignatureHandler will be used to add or
33// validate/check a digital signature.
34// ii) Create an instance of the implemented SignatureHandler and register it with PDFDoc with
35// pdfdoc.AddSignatureHandler(). The method returns a SignatureHandlerId.
36// iii) Call SignOnNextSaveWithCustomHandler/CertifyOnNextSaveWithCustomHandler with the SignatureHandlerId.
37// NOTE: It is only possible to sign/certify one signature per call to the Save function.
38//
39// 5. Call pdfdoc.Save(). This will also create the digital signature dictionary and write a cryptographic signature to it.
40// IMPORTANT: If there are already signed/certified digital signature(s) in the document, you must save incrementally
41// so as to not invalidate the other signature(s).
42//
43// Additional processing can be done before document is signed. For example, UseSignatureHandler() returns an instance
44// of SDF dictionary which represents the signature dictionary (or the /V entry of the form field). This can be used to
45// add additional information to the signature dictionary (e.g. Name, Reason, Location, etc.).
46//
47// Although the steps above describes extending the SignatureHandler class, this sample demonstrates the use of
48// StdSignatureHandler (a built-in SignatureHandler in PDFNet) to sign a PDF file.
49//----------------------------------------------------------------------------------------------------------------------
50
51// In order to use .NET Framework's Cryptography library, define "USE_DOTNET_CRYPTO" and then add System.Security to
52// references list.
53
54using System;
55using System.Collections.Generic;
56using System.IO;
57
58using pdftron;
59using pdftron.Common;
60using pdftron.PDF;
61using pdftron.PDF.Annots;
62using pdftron.SDF;
63using pdftron.Crypto;
64
65using NUnit.Framework;
66
67namespace MiscellaneousSamples
68{
69 //////////////////// Here follows an example of how to implement a custom signature handler. //////////
70 ////////// End of the DotNetCryptoSignatureHandler custom handler code. ////////////////////
71
72 [TestFixture]
73 public class DigitalSignaturesTest
74 {
75 const string input_path = "TestFiles/";
76
77 static bool VerifySimple (string in_docpath, string in_public_key_file_path)
78 {
79 using (PDFDoc doc = new PDFDoc(in_docpath))
80 {
81 Console.WriteLine("==========");
82 VerificationOptions opts = new VerificationOptions(VerificationOptions.SignatureVerificationSecurityLevel.e_compatibility_and_archiving);
83
84 // Add trust root to store of trusted certificates contained in VerificationOptions.
85 opts.AddTrustedCertificate(in_public_key_file_path,
86 (ushort)(VerificationOptions.CertificateTrustFlag.e_default_trust | VerificationOptions.CertificateTrustFlag.e_certification_trust));
87
88 PDFDoc.SignaturesVerificationStatus result = doc.VerifySignedDigitalSignatures(opts);
89 switch (result)
90 {
91 case PDFDoc.SignaturesVerificationStatus.e_unsigned:
92 Console.WriteLine("Document has no signed signature fields.");
93 return false;
94 /* e_failure == bad doc status, digest status, or permissions status
95 (i.e. does not include trust issues, because those are flaky due to being network/config-related) */
96 case PDFDoc.SignaturesVerificationStatus.e_failure:
97 Console.WriteLine("Hard failure in verification on at least one signature.");
98 return false;
99 case PDFDoc.SignaturesVerificationStatus.e_untrusted:
100 Console.WriteLine("Could not verify trust for at least one signature.");
101 return false;
102 case PDFDoc.SignaturesVerificationStatus.e_unsupported:
103 /* If necessary, call GetUnsupportedFeatures on VerificationResult to check which
104 unsupported features were encountered (requires verification using 'detailed' APIs) */
105 Console.WriteLine("At least one signature contains unsupported features.");
106 return false;
107 // unsigned sigs skipped; parts of document may be unsigned (check GetByteRanges on signed sigs to find out)
108 case PDFDoc.SignaturesVerificationStatus.e_verified:
109 Console.WriteLine("All signed signatures in document verified.");
110 return true;
111 default:
112 throw new Exception("unrecognized document verification status");
113 }
114 }
115 }
116
117 static bool VerifyAllAndPrint(string in_docpath, string in_public_key_file_path)
118 {
119 using (PDFDoc doc = new PDFDoc(in_docpath))
120 {
121 Console.WriteLine("==========");
122 VerificationOptions opts = new VerificationOptions(VerificationOptions.SignatureVerificationSecurityLevel.e_compatibility_and_archiving);
123
124 // Add trust root to store of trusted certificates contained in VerificationOptions.
125 opts.AddTrustedCertificate(in_public_key_file_path,
126 (ushort) (VerificationOptions.CertificateTrustFlag.e_default_trust | VerificationOptions.CertificateTrustFlag.e_certification_trust));
127
128 // Iterate over the signatures and verify all of them.
129 DigitalSignatureFieldIterator digsig_fitr = doc.GetDigitalSignatureFieldIterator();
130 bool verification_status = true;
131 for (; digsig_fitr.HasNext(); digsig_fitr.Next())
132 {
133 DigitalSignatureField curr = digsig_fitr.Current();
134 VerificationResult result = curr.Verify(opts);
135 if (result.GetVerificationStatus())
136 {
137 Console.Write("Signature verified, ");
138 }
139 else
140 {
141 Console.Write("Signature verification failed, ");
142 verification_status = false;
143 }
144 Console.WriteLine("objnum: {0}", curr.GetSDFObj().GetObjNum());
145
146 switch (result.GetDigestAlgorithm())
147 {
148 case DigestAlgorithm.Type.e_sha1:
149 Console.WriteLine("Digest algorithm: SHA-1");
150 break;
151 case DigestAlgorithm.Type.e_sha256:
152 Console.WriteLine("Digest algorithm: SHA-256");
153 break;
154 case DigestAlgorithm.Type.e_sha384:
155 Console.WriteLine("Digest algorithm: SHA-384");
156 break;
157 case DigestAlgorithm.Type.e_sha512:
158 Console.WriteLine("Digest algorithm: SHA-512");
159 break;
160 case DigestAlgorithm.Type.e_ripemd160:
161 Console.WriteLine("Digest algorithm: RIPEMD-160");
162 break;
163 case DigestAlgorithm.Type.e_unknown_digest_algorithm:
164 Console.WriteLine("Digest algorithm: unknown");
165 break;
166 default:
167 throw new Exception("unrecognized digest algorithm");
168 }
169 Console.WriteLine("Detailed verification result: \n\t{0}\n\t{1}\n\t{2}\n\t{3}",
170 result.GetDocumentStatusAsString(),
171 result.GetDigestStatusAsString(),
172 result.GetTrustStatusAsString(),
173 result.GetPermissionsStatusAsString());
174
175
176 DisallowedChange[] changes = result.GetDisallowedChanges();
177 foreach (DisallowedChange it2 in changes)
178 {
179 Console.WriteLine("\tDisallowed change: {0}, objnum: {1}", it2.GetTypeAsString(), it2.GetObjNum());
180 }
181
182 // Get and print all the detailed trust-related results, if they are available.
183 if (result.HasTrustVerificationResult())
184 {
185 TrustVerificationResult trust_verification_result = result.GetTrustVerificationResult();
186 Console.WriteLine(trust_verification_result.WasSuccessful() ? "Trust verified." : "Trust not verifiable.");
187 Console.WriteLine(trust_verification_result.GetResultString());
188
189 long time_of_verification = trust_verification_result.GetTimeOfTrustVerification();
190 switch (trust_verification_result.GetTimeOfTrustVerificationEnum())
191 {
192 case VerificationOptions.TimeMode.e_current:
193 Console.WriteLine("Trust verification attempted with respect to current time (as epoch time): {0}", time_of_verification);
194 break;
195 case VerificationOptions.TimeMode.e_signing:
196 Console.WriteLine("Trust verification attempted with respect to signing time (as epoch time): {0}", time_of_verification);
197 break;
198 case VerificationOptions.TimeMode.e_timestamp:
199 Console.WriteLine("Trust verification attempted with respect to secure embedded timestamp (as epoch time): {0}", time_of_verification);
200 break;
201 default:
202 throw new Exception("unrecognized time enum value");
203 }
204
205 if (trust_verification_result.GetCertPath().Length == 0)
206 {
207 Console.WriteLine("Could not print certificate path.");
208 }
209 else
210 {
211 Console.WriteLine("Certificate path:");
212 X509Certificate[] cert_path = trust_verification_result.GetCertPath();
213 for (int j = 0; j < cert_path.Length; j++)
214 {
215 Console.WriteLine("\tCertificate:");
216 X509Certificate full_cert = cert_path[j];
217 Console.WriteLine("\t\tIssuer names:");
218 X501AttributeTypeAndValue[] issuer_dn = full_cert.GetIssuerField().GetAllAttributesAndValues();
219 for (int i = 0; i < issuer_dn.Length; i++)
220 {
221 Console.WriteLine("\t\t\t" + issuer_dn[i].GetStringValue());
222 }
223 Console.WriteLine("\t\tSubject names:");
224 X501AttributeTypeAndValue[] subject_dn = full_cert.GetSubjectField().GetAllAttributesAndValues();
225 for (int i = 0; i < subject_dn.Length; i++)
226 {
227 Console.WriteLine("\t\t\t" + subject_dn[i].GetStringValue());
228 }
229 Console.WriteLine("\t\tExtensions:");
230 for (int i = 0; i < full_cert.GetExtensions().Length; i++)
231 {
232 Console.WriteLine("\t\t\t" + full_cert.GetExtensions()[i].ToString());
233 }
234 }
235 }
236 }
237 else
238 {
239 Console.WriteLine("No detailed trust verification result available.");
240 }
241
242 string[] unsupported_features = result.GetUnsupportedFeatures();
243 if (unsupported_features.Length > 0)
244 {
245 Console.WriteLine("Unsupported features:");
246
247 for (int i = 0; i < unsupported_features.Length; i++)
248 {
249 Console.WriteLine("\t" + unsupported_features[i]);
250 }
251 }
252 Console.WriteLine("==========");
253 }
254
255 return verification_status;
256 }
257 }
258
259 static void CertifyPDF(string in_docpath,
260 string in_cert_field_name,
261 string in_private_key_file_path,
262 string in_keyfile_password,
263 string in_appearance_image_path,
264 string in_outpath)
265 {
266 Console.Out.WriteLine("================================================================================");
267 Console.Out.WriteLine("Certifying PDF document");
268
269 // Open an existing PDF
270 using (PDFDoc doc = new PDFDoc(in_docpath))
271 {
272 Console.Out.WriteLine("PDFDoc has " + (doc.HasSignatures() ? "signatures" : "no signatures"));
273
274 Page page1 = doc.GetPage(1);
275
276 // Create a text field that we can lock using the field permissions feature.
277 TextWidget annot1 = TextWidget.Create(doc, new Rect(143, 440, 350, 460), "asdf_test_field");
278 page1.AnnotPushBack(annot1);
279
280 /* Create a new signature form field in the PDFDoc. The name argument is optional;
281 leaving it empty causes it to be auto-generated. However, you may need the name for later.
282 Acrobat doesn't show digsigfield in side panel if it's without a widget. Using a
283 Rect with 0 width and 0 height, or setting the NoPrint/Invisible flags makes it invisible. */
284 DigitalSignatureField certification_sig_field = doc.CreateDigitalSignatureField(in_cert_field_name);
285 SignatureWidget widgetAnnot = SignatureWidget.Create(doc, new Rect(143, 287, 219, 306), certification_sig_field);
286 page1.AnnotPushBack(widgetAnnot);
287
288 // (OPTIONAL) Add an appearance to the signature field.
289 Image img = Image.Create(doc, in_appearance_image_path);
290 widgetAnnot.CreateSignatureAppearance(img);
291
292 // Prepare the document locking permission level. It will be applied upon document certification.
293 Console.Out.WriteLine("Adding document permissions.");
294 certification_sig_field.SetDocumentPermissions(DigitalSignatureField.DocumentPermissions.e_annotating_formfilling_signing_allowed);
295
296 // Prepare to lock the text field that we created earlier.
297 Console.Out.WriteLine("Adding field permissions.");
298 string[] fields_to_lock = new string[1];
299 fields_to_lock[0] = "asdf_test_field";
300 certification_sig_field.SetFieldPermissions(DigitalSignatureField.FieldPermissions.e_include, fields_to_lock);
301
302 certification_sig_field.CertifyOnNextSave(in_private_key_file_path, in_keyfile_password);
303
304 // (OPTIONAL) Add more information to the signature dictionary.
305 certification_sig_field.SetLocation("Vancouver, BC");
306 certification_sig_field.SetReason("Document certification.");
307 certification_sig_field.SetContactInfo("www.pdftron.com");
308
309 // Save the PDFDoc. Once the method below is called, PDFNet will also sign the document using the information provided.
310 doc.Save(in_outpath, 0);
311 }
312
313 Console.Out.WriteLine("================================================================================");
314 }
315
316 static void SignPDF(string in_docpath,
317 string in_approval_field_name,
318 string in_private_key_file_path,
319 string in_keyfile_password,
320 string in_appearance_img_path,
321 string in_outpath)
322 {
323 Console.Out.WriteLine("================================================================================");
324 Console.Out.WriteLine("Signing PDF document");
325
326 // Open an existing PDF
327 using (PDFDoc doc = new PDFDoc(in_docpath))
328 {
329 // Retrieve the unsigned approval signature field.
330 Field found_approval_field = doc.GetField(in_approval_field_name);
331 DigitalSignatureField found_approval_signature_digsig_field = new DigitalSignatureField(found_approval_field);
332
333 // (OPTIONAL) Add an appearance to the signature field.
334 Image img = Image.Create(doc, in_appearance_img_path);
335 SignatureWidget found_approval_signature_widget = new SignatureWidget(found_approval_field.GetSDFObj());
336 found_approval_signature_widget.CreateSignatureAppearance(img);
337
338 // Prepare the signature and signature handler for signing.
339 found_approval_signature_digsig_field.SignOnNextSave(in_private_key_file_path, in_keyfile_password);
340
341 // The actual approval signing will be done during the following incremental save operation.
342 doc.Save(in_outpath, SDFDoc.SaveOptions.e_incremental);
343 }
344 Console.Out.WriteLine("================================================================================");
345 }
346
347 static void ClearSignature(string in_docpath,
348 string in_digsig_field_name,
349 string in_outpath)
350 {
351 Console.Out.WriteLine("================================================================================");
352 Console.Out.WriteLine("Clearing certification signature");
353
354 using (PDFDoc doc = new PDFDoc(in_docpath))
355 {
356 DigitalSignatureField digsig = new DigitalSignatureField(doc.GetField(in_digsig_field_name));
357
358 Console.Out.WriteLine("Clearing signature: " + in_digsig_field_name);
359 digsig.ClearSignature();
360
361 if (!digsig.HasCryptographicSignature())
362 {
363 Console.Out.WriteLine("Cryptographic signature cleared properly.");
364 }
365
366 // Save incrementally so as to not invalidate other signatures from previous saves.
367 doc.Save(in_outpath, SDFDoc.SaveOptions.e_incremental);
368 }
369
370 Console.Out.WriteLine("================================================================================");
371 }
372
373 static void PrintSignaturesInfo(string in_docpath)
374 {
375 Console.Out.WriteLine("================================================================================");
376 Console.Out.WriteLine("Reading and printing digital signature information");
377
378 using (PDFDoc doc = new PDFDoc(in_docpath))
379 {
380 if (!doc.HasSignatures())
381 {
382 Console.Out.WriteLine("Doc has no signatures.");
383 Console.Out.WriteLine("================================================================================");
384 return;
385 }
386 else
387 {
388 Console.Out.WriteLine("Doc has signatures.");
389 }
390
391
392 for (FieldIterator fitr = doc.GetFieldIterator(); fitr.HasNext(); fitr.Next())
393 {
394 if (fitr.Current().IsLockedByDigitalSignature())
395 {
396 Console.Out.WriteLine("==========\nField locked by a digital signature");
397 }
398 else
399 {
400 Console.Out.WriteLine("==========\nField not locked by a digital signature");
401 }
402
403 Console.Out.WriteLine("Field name: " + fitr.Current().GetName());
404 Console.Out.WriteLine("==========");
405 }
406
407 Console.Out.WriteLine("====================\nNow iterating over digital signatures only.\n====================");
408
409 DigitalSignatureFieldIterator digsig_fitr = doc.GetDigitalSignatureFieldIterator();
410 for (; digsig_fitr.HasNext(); digsig_fitr.Next())
411 {
412 Console.Out.WriteLine("==========");
413 Console.Out.WriteLine("Field name of digital signature: " + new Field(digsig_fitr.Current().GetSDFObj()).GetName());
414
415 DigitalSignatureField digsigfield = digsig_fitr.Current();
416 if (!digsigfield.HasCryptographicSignature())
417 {
418 Console.Out.WriteLine("Either digital signature field lacks a digital signature dictionary, " +
419 "or digital signature dictionary lacks a cryptographic Contents entry. " +
420 "Digital signature field is not presently considered signed.\n" +
421 "==========");
422 continue;
423 }
424
425 int cert_count = digsigfield.GetCertCount();
426 Console.Out.WriteLine("Cert count: " + cert_count);
427 for (int i = 0; i < cert_count; ++i)
428 {
429 byte[] cert = digsigfield.GetCert(i);
430 Console.Out.WriteLine("Cert #" + i + " size: " + cert.Length);
431 }
432
433 DigitalSignatureField.SubFilterType subfilter = digsigfield.GetSubFilter();
434
435 Console.Out.WriteLine("Subfilter type: " + (int)subfilter);
436
437 if (subfilter != DigitalSignatureField.SubFilterType.e_ETSI_RFC3161)
438 {
439 Console.Out.WriteLine("Signature's signer: " + digsigfield.GetSignatureName());
440
441 Date signing_time = digsigfield.GetSigningTime();
442 if (signing_time.IsValid())
443 {
444 Console.Out.WriteLine("Signing time is valid.");
445 }
446
447 Console.Out.WriteLine("Location: " + digsigfield.GetLocation());
448 Console.Out.WriteLine("Reason: " + digsigfield.GetReason());
449 Console.Out.WriteLine("Contact info: " + digsigfield.GetContactInfo());
450 }
451 else
452 {
453 Console.Out.WriteLine("SubFilter == e_ETSI_RFC3161 (DocTimeStamp; no signing info)\n");
454 }
455
456 Console.Out.WriteLine(((digsigfield.HasVisibleAppearance()) ? "Visible" : "Not visible"));
457
458 DigitalSignatureField.DocumentPermissions digsig_doc_perms = digsigfield.GetDocumentPermissions();
459 string[] locked_fields = digsigfield.GetLockedFields();
460 foreach (string field_name in locked_fields)
461 {
462 Console.Out.WriteLine("This digital signature locks a field named: " + field_name);
463 }
464
465 switch (digsig_doc_perms)
466 {
467 case DigitalSignatureField.DocumentPermissions.e_no_changes_allowed:
468 Console.Out.WriteLine("No changes to the document can be made without invalidating this digital signature.");
469 break;
470 case DigitalSignatureField.DocumentPermissions.e_formfilling_signing_allowed:
471 Console.Out.WriteLine("Page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.");
472 break;
473 case DigitalSignatureField.DocumentPermissions.e_annotating_formfilling_signing_allowed:
474 Console.Out.WriteLine("Annotating, page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.");
475 break;
476 case DigitalSignatureField.DocumentPermissions.e_unrestricted:
477 Console.Out.WriteLine("Document not restricted by this digital signature.");
478 break;
479 default:
480 throw new Exception("Unrecognized digital signature document permission level.");
481 }
482 Console.Out.WriteLine("==========");
483 }
484 }
485
486 Console.Out.WriteLine("================================================================================");
487 }
488 static bool TimestampAndEnableLTV(string in_docpath,
489 string in_trusted_cert_path,
490 string in_appearance_img_path,
491 string in_outpath)
492 {
493 using (PDFDoc doc = new PDFDoc(in_docpath))
494 {
495 DigitalSignatureField doctimestamp_signature_field = doc.CreateDigitalSignatureField();
496 TimestampingConfiguration tst_config = new TimestampingConfiguration("http://rfc3161timestamp.globalsign.com/advanced");
497 VerificationOptions opts = new VerificationOptions(VerificationOptions.SignatureVerificationSecurityLevel.e_compatibility_and_archiving);
498 /* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to
499 the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
500 response to be verifiable during DocTimeStamp signing. It is also necessary in the context of this
501 function to do this for the later LTV section, because one needs to be able to verify the DocTimeStamp
502 in order to enable LTV for it, and we re-use the VerificationOptions opts object in that part. */
503 opts.AddTrustedCertificate(in_trusted_cert_path);
504 /* By default, we only check online for revocation of certificates using the newer and lighter
505 OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However,
506 it may be necessary to enable online CRL revocation checking in order to verify some timestamps
507 (i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
508 opts.EnableOnlineCRLRevocationChecking(true);
509
510 SignatureWidget widgetAnnot = SignatureWidget.Create(doc, new Rect(0, 100, 200, 150), doctimestamp_signature_field);
511 doc.GetPage(1).AnnotPushBack(widgetAnnot);
512 Obj widgetObj = widgetAnnot.GetSDFObj();
513
514 // (OPTIONAL) Add an appearance to the signature field.
515 Image img = Image.Create(doc, in_appearance_img_path);
516 widgetAnnot.CreateSignatureAppearance(img);
517
518 Console.WriteLine("Testing timestamping configuration.");
519 TimestampingResult config_result = tst_config.TestConfiguration(opts);
520 if (config_result.GetStatus())
521 {
522 Console.WriteLine("Success: timestamping configuration usable. Attempting to timestamp.");
523 }
524 else
525 {
526 // Print details of timestamping failure.
527 Console.WriteLine(config_result.GetString());
528 if (config_result.HasResponseVerificationResult())
529 {
530 EmbeddedTimestampVerificationResult tst_result = config_result.GetResponseVerificationResult();
531 Console.WriteLine("CMS digest status: {0}\n", tst_result.GetCMSDigestStatusAsString());
532 Console.WriteLine("Message digest status:{0}\n", tst_result.GetMessageImprintDigestStatusAsString());
533 Console.WriteLine("Trust status: {0}\n", tst_result.GetTrustStatusAsString());
534 }
535 return false;
536 }
537
538 doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts);
539
540 // Save/signing throws if timestamping fails.
541 doc.Save(in_outpath, SDFDoc.SaveOptions.e_incremental);
542
543 Console.WriteLine("Timestamping successful. Adding LTV information for DocTimeStamp signature.");
544
545 // Add LTV information for timestamp signature to document.
546 VerificationResult timestamp_verification_result = doctimestamp_signature_field.Verify(opts);
547 if (!doctimestamp_signature_field.EnableLTVOfflineVerification(timestamp_verification_result))
548 {
549 Console.WriteLine("Could not enable LTV for DocTimeStamp.");
550 return false;
551 }
552 doc.Save(in_outpath, SDFDoc.SaveOptions.e_incremental);
553 Console.WriteLine("Added LTV information for DocTimeStamp signature successfully.");
554
555 return true;
556 }
557 }
558
559
560 /// <summary>
561 /// The main entry point for the application.
562 /// </summary>
563 [Test]
564 public static void Sample()
565 {
566 // Initialize PDFNetC
567
568 bool result = true;
569
570 //////////////////// TEST 0:
571 /* Create an approval signature field that we can sign after certifying.
572 (Must be done before calling CertifyOnNextSave/SignOnNextSave/WithCustomHandler.) */
573 try
574 {
575 using (PDFDoc doc = new PDFDoc(Utils.GetAssetTempFile(input_path + "waiver.pdf")))
576 {
577 DigitalSignatureField approval_signature_field = doc.CreateDigitalSignatureField("PDFTronApprovalSig");
578 SignatureWidget widgetAnnotApproval = SignatureWidget.Create(doc, new Rect(300, 287, 376, 306), approval_signature_field);
579 Page page1 = doc.GetPage(1);
580 page1.AnnotPushBack(widgetAnnotApproval);
581 doc.Save(Utils.CreateExternalFile("waiver_withApprovalField_output.pdf"), SDFDoc.SaveOptions.e_remove_unused);
582 }
583 }
584 catch (Exception e)
585 {
586 Console.Error.WriteLine(e);
587 Assert.True(false);
588 result = false;
589 }
590
591 //////////////////// TEST 1: certify a PDF.
592 try
593 {
594 CertifyPDF(Utils.GetAssetTempFile(input_path + "waiver_withApprovalField.pdf"),
595 "PDFTronCertificationSig",
596 Utils.GetAssetTempFile(input_path + "pdftron.pfx"),
597 "password",
598 Utils.GetAssetTempFile(input_path + "pdftron.bmp"),
599 Utils.CreateExternalFile("waiver_withApprovalField_certified_output.pdf"));
600 PrintSignaturesInfo(Utils.CreateExternalFile("waiver_withApprovalField_certified_output.pdf"));
601 }
602 catch (Exception e)
603 {
604 Console.Error.WriteLine(e);
605 Assert.True(false);
606 result = false;
607 }
608
609 //////////////////// TEST 2: approval-sign an existing, unsigned signature field in a PDF that already has a certified signature field.
610 try
611 {
612 SignPDF(Utils.GetAssetTempFile(input_path + "waiver_withApprovalField_certified.pdf"),
613 "PDFTronApprovalSig",
614 Utils.GetAssetTempFile(input_path + "pdftron.pfx"),
615 "password",
616 Utils.GetAssetTempFile(input_path + "signature.jpg"),
617 Utils.CreateExternalFile("waiver_withApprovalField_certified_approved_output.pdf"));
618 PrintSignaturesInfo(Utils.CreateExternalFile("waiver_withApprovalField_certified_approved_output.pdf"));
619 }
620 catch (Exception e)
621 {
622 Console.Error.WriteLine(e);
623 Assert.True(false);
624 result = false;
625 }
626
627 //////////////////// TEST 3: Clear a certification from a document that is certified and has an approval signature.
628 try
629 {
630 ClearSignature(Utils.GetAssetTempFile(input_path + "waiver_withApprovalField_certified_approved.pdf"),
631 "PDFTronCertificationSig",
632 Utils.CreateExternalFile("waiver_withApprovalField_certified_approved_certcleared_output.pdf"));
633 PrintSignaturesInfo(Utils.CreateExternalFile("waiver_withApprovalField_certified_approved_certcleared_output.pdf"));
634 }
635 catch (Exception e)
636 {
637 Console.Error.WriteLine(e);
638 Assert.True(false);
639 result = false;
640 }
641
642 //////////////////// TEST 4: Verify a document's digital signatures.
643 try
644 {
645 if (!VerifyAllAndPrint(Utils.GetAssetTempFile(input_path + "waiver_withApprovalField_certified_approved.pdf"),
646 Utils.GetAssetTempFile(input_path + "pdftron.cer")))
647 {
648 result = false;
649 }
650 }
651 catch (Exception e)
652 {
653 Console.Error.WriteLine(e);
654 Assert.True(false);
655 result = false;
656 }
657 //////////////////// TEST 5: Verify a document's digital signatures in a simple fashion using the document API.
658 try
659 {
660 if (!VerifySimple(Utils.GetAssetTempFile(input_path + "waiver_withApprovalField_certified_approved.pdf"),
661 Utils.GetAssetTempFile(input_path + "pdftron.cer")))
662 {
663 result = false;
664 }
665 }
666 catch (Exception e)
667 {
668 Console.Error.WriteLine(e);
669 Assert.True(false);
670 result = false;
671 }
672
673 //////////////////// TEST 6: Timestamp a document, then add Long Term Validation (LTV) information for the DocTimeStamp.
674 //try
675 //{
676 // if (!TimestampAndEnableLTV(Utils.GetAssetTempFile(input_path + "waiver.pdf"),
677 // Utils.GetAssetTempFile(input_path + "GlobalSignRootForTST.cer"),
678 // Utils.GetAssetTempFile(input_path + "signature.jpg"),
679 // Utils.CreateExternalFile("waiver_DocTimeStamp_LTV.pdf")))
680 // {
681 // result = false;
682 // }
683 //}
684 //catch (Exception e)
685 //{
686 // Console.Error.WriteLine(e);
687 Assert.True(false);
688 // result = false;
689 //}
690
691 //////////////////// End of tests. ////////////////////
692 if (result)
693 {
694 Console.Out.WriteLine("Tests successful.\n==========");
695 }
696 else
697 {
698 Console.Out.WriteLine("Tests FAILED!!!\n==========");
699 }
700 }
701 }
702}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales