How to sign and verify updates to a PDF document

Digital signatures, Security
7/17/2015

This code sample shows how you can sign PDF documents and how to handle updates to form data

C# code sample

1 using (FileStream sourceFile = new FileStream(@"..\..\form.pdf", FileMode.Open, FileAccess.Read)) 2 { 3 // open the form 4 Document document = new Document(sourceFile); 5 6 // file out the data fields 7 TextField projectNr = document.Fields["projectNumber"] as TextField; 8 projectNr.Value = "FF-235"; 9 10 TextField sName = document.Fields["studentName"] as TextField; 11 sName.Value = "Bob Stapleton"; 12 13 TextField sDate = document.Fields["studentDate"] as TextField; 14 sDate.Value = "April 18, 2007"; 15 16 // retrieve the signature field 17 SignatureField sigField = document.Fields["studentSignature"] as SignatureField; 18 19 // open certicate store. 20 Pkcs12Store store = null; 21 using (FileStream storeFile = new FileStream(@"..\..\BobStapleton.pfx", FileMode.Open, FileAccess.Read)) 22 { 23 store = new Pkcs12Store(storeFile, "studentpassword"); 24 } 25 26 // let the factory decide which type should be used. 27 SignatureHandler handler = StandardSignatureHandler.Create(store); 28 29 // associate the handler with the signature field 30 sigField.SignatureHandler = handler; 31 32 // set optional info. 33 sigField.ContactInfo = "+31 (0)77 4748677"; 34 sigField.Location = "The Netherlands"; 35 sigField.Reason = "I hereby declare!"; 36 37 // save the signed document - while saving, the handler 38 // will be called to sign the saved content 39 using (FileStream outFile = new FileStream(@"..\..\signedByStudent.pdf", FileMode.Create, FileAccess.ReadWrite)) 40 { 41 document.Write(outFile); 42 } 43 } 44 45 // ----------------------------------------------------- 46 // TEACHER FILLS OUT FINAL FIELDS AND SIGNS THE DOCUMENT 47 // ----------------------------------------------------- 48 49 using (FileStream sourceFile = new FileStream(@"..\..\signedByStudent.pdf", FileMode.Open, FileAccess.Read)) 50 { 51 // open the form 52 Document document = new Document(sourceFile); 53 54 // file out the data fields 55 56 TextField tName = document.Fields["teacherName"] as TextField; 57 tName.Value = "Max Boulton"; 58 59 TextField tDate = document.Fields["teacherDate"] as TextField; 60 tDate.Value = "April 18, 2007"; 61 62 // retrieve the signature field 63 SignatureField sigField = document.Fields["teacherSignature"] as SignatureField; 64 65 // open certicate store. 66 Pkcs12Store store = null; 67 using (FileStream storeFile = new FileStream(@"..\..\MaxBoulton.pfx", FileMode.Open, FileAccess.Read)) 68 { 69 store = new Pkcs12Store(storeFile, "teacherpassword"); 70 } 71 72 // let the factory decide which type should be used. 73 SignatureHandler handler = StandardSignatureHandler.Create(store); 74 75 // associate the handler with the signature field 76 sigField.SignatureHandler = handler; 77 78 // set optional info. 79 sigField.ContactInfo = "+31 (0)77 4748677"; 80 sigField.Location = "The Netherlands"; 81 sigField.Reason = "I hereby declare!"; 82 83 // save the signed document - while saving, the handler 84 // will be called to sign the saved content 85 using (FileStream outFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Create, FileAccess.ReadWrite)) 86 { 87 document.Write(outFile, DocumentWriteMode.AppendUpdate); 88 } 89 } 90 91 // ---------------------------------------------------- 92 // ENUMERATE UPDATES IN DOCUMENT THAS BEEN SIGNED TWICE 93 // ---------------------------------------------------- 94 95 using (FileStream sourceFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)) 96 { 97 // open the form 98 Document document = new Document(sourceFile); 99 100 // count the number of updates 101 //Console.WriteLine( "This document has {0} updates.", document.Updates.Count ); 102 103 // save each update as a new PDF document 104 foreach (Update update in document.Updates) 105 { 106 string name = string.Format( @"..\..\signedByTeacher_{0}.pdf", update.Index ); 107 using (FileStream updateFile = new FileStream(name, FileMode.Create, FileAccess.Write)) 108 { 109 update.Write(updateFile); 110 } 111 } 112 } 113 114 // ----------------------------------------------------------- 115 // ENUMERATE SIGNATURE FIELDS AND SAVE SIGNED UPDATE PER FIELD 116 // ----------------------------------------------------------- 117 118 using (FileStream sourceFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)) 119 { 120 // open the form 121 Document document = new Document(sourceFile); 122 123 foreach (Field field in document.Fields) 124 { 125 // is this a signature field? 126 SignatureField sigField = field as SignatureField; 127 if (null != sigField) 128 { 129 // has it been signed? 130 if (sigField.IsSigned) 131 { 132 // save the update and name it after the field 133 string name = string.Format(@"..\..\{0}.pdf", sigField.FullName); 134 using (FileStream updateFile = new FileStream(name, FileMode.Create, FileAccess.Write)) 135 { 136 sigField.SignedUpdate.Write(updateFile); 137 } 138 } 139 } 140 } 141 } 142 143 // ---------------------------------- 144 // DUMP STATE OF EACH SIGNATURE FIELD 145 // ---------------------------------- 146 147 using (FileStream inFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)) 148 { 149 // open form 150 Document document = new Document(inFile); 151 152 foreach (Field field in document.Fields) 153 { 154 // is this a signature field? 155 SignatureField sigField = field as SignatureField; 156 if (null != sigField) 157 { 158 Console.WriteLine("Field '{0}'", sigField.FullName); 159 160 // has it been signed? 161 if (sigField.IsSigned) 162 { 163 // verify, based on the default handlers. 164 bool verified = sigField.Verify(); 165 Console.WriteLine(" -- {0}", verified ? "Verified" : "Not verified"); 166 167 if (verified) 168 { 169 // has the document been modified after signing? 170 bool modified = sigField.DocumentModifiedAfterSigning; 171 Console.WriteLine(" -- {0}", modified ? "Modified after signing" : "Not modified after signing"); 172 } 173 } 174 else 175 { 176 Console.WriteLine(" -- Not signed", sigField.FullName); 177 } 178 } 179 } 180 }

VB.NET code sample

1 ' ------------------------------------------- 2 ' STUDENT FILLS OUT FIELDS AND SIGNS DOCUMENT 3 ' ------------------------------------------- 4 5 Using sourceFile As New FileStream("..\..\form.pdf", FileMode.Open, FileAccess.Read) 6 ' open the form 7 Dim document As New Document(sourceFile) 8 9 ' file out the data fields 10 Dim projectNr As TextField = TryCast(document.Fields("projectNumber"), TextField) 11 projectNr.Value = "FF-235" 12 13 Dim sName As TextField = TryCast(document.Fields("studentName"), TextField) 14 sName.Value = "Bob Stapleton" 15 16 Dim sDate As TextField = TryCast(document.Fields("studentDate"), TextField) 17 sDate.Value = "April 18, 2007" 18 19 ' retrieve the signature field 20 Dim sigField As SignatureField = TryCast(document.Fields("studentSignature"), SignatureField) 21 22 ' open certicate store. 23 Dim store As Pkcs12Store = Nothing 24 Using storeFile As New FileStream("..\..\BobStapleton.pfx", FileMode.Open, FileAccess.Read) 25 store = New Pkcs12Store(storeFile, "studentpassword") 26 End Using 27 28 ' let the factory decide which type should be used. 29 Dim handler As SignatureHandler = StandardSignatureHandler.Create(store) 30 31 ' associate the handler with the signature field 32 sigField.SignatureHandler = handler 33 34 ' set optional info. 35 sigField.ContactInfo = "+31 (0)77 4748677" 36 sigField.Location = "The Netherlands" 37 sigField.Reason = "I hereby declare!" 38 39 ' save the signed document - while saving, the handler 40 ' will be called to sign the saved content 41 Using outFile As New FileStream("..\..\signedByStudent.pdf", FileMode.Create, FileAccess.ReadWrite) 42 document.Write(outFile) 43 End Using 44 End Using 45 46 ' ----------------------------------------------------- 47 ' TEACHER FILLS OUT FINAL FIELDS AND SIGNS THE DOCUMENT 48 ' ----------------------------------------------------- 49 50 Using sourceFile As New FileStream("..\..\signedByStudent.pdf", FileMode.Open, FileAccess.Read) 51 ' open the form 52 Dim document As New Document(sourceFile) 53 54 ' file out the data fields 55 56 Dim tName As TextField = TryCast(document.Fields("teacherName"), TextField) 57 tName.Value = "Max Boulton" 58 59 Dim tDate As TextField = TryCast(document.Fields("teacherDate"), TextField) 60 tDate.Value = "April 18, 2007" 61 62 ' retrieve the signature field 63 Dim sigField As SignatureField = TryCast(document.Fields("teacherSignature"), SignatureField) 64 65 ' open certicate store. 66 Dim store As Pkcs12Store = Nothing 67 Using storeFile As New FileStream("..\..\MaxBoulton.pfx", FileMode.Open, FileAccess.Read) 68 store = New Pkcs12Store(storeFile, "teacherpassword") 69 End Using 70 71 ' let the factory decide which type should be used. 72 Dim handler As SignatureHandler = StandardSignatureHandler.Create(store) 73 74 ' associate the handler with the signature field 75 sigField.SignatureHandler = handler 76 77 ' set optional info. 78 sigField.ContactInfo = "+31 (0)77 4748677" 79 sigField.Location = "The Netherlands" 80 sigField.Reason = "I hereby declare!" 81 82 ' save the signed document - while saving, the handler 83 ' will be called to sign the saved content 84 Using outFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Create, FileAccess.ReadWrite) 85 document.Write(outFile, DocumentWriteMode.AppendUpdate) 86 End Using 87 End Using 88 89 ' ---------------------------------------------------- 90 ' ENUMERATE UPDATES IN DOCUMENT THAS BEEN SIGNED TWICE 91 ' ---------------------------------------------------- 92 93 Using sourceFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read) 94 ' open the form 95 Dim document As New Document(sourceFile) 96 97 ' count the number of updates 98 'Console.WriteLine( "This document has {0} updates.", document.Updates.Count ); 99 100 ' save each update as a new PDF document 101 For Each update As Update In document.Updates 102 Dim name As String = String.Format("..\..\signedByTeacher_{0}.pdf", update.Index) 103 Using updateFile As New FileStream(name, FileMode.Create, FileAccess.Write) 104 update.Write(updateFile) 105 End Using 106 Next 107 End Using 108 109 ' ----------------------------------------------------------- 110 ' ENUMERATE SIGNATURE FIELDS AND SAVE SIGNED UPDATE PER FIELD 111 ' ----------------------------------------------------------- 112 113 Using sourceFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read) 114 ' open the form 115 Dim document As New Document(sourceFile) 116 117 For Each field As Field In document.Fields 118 ' is this a signature field? 119 Dim sigField As SignatureField = TryCast(field, SignatureField) 120 If sigField IsNot Nothing Then 121 ' has it been signed? 122 If sigField.IsSigned Then 123 ' save the update and name it after the field 124 Dim name As String = String.Format("..\..\{0}.pdf", sigField.FullName) 125 Using updateFile As New FileStream(name, FileMode.Create, FileAccess.Write) 126 sigField.SignedUpdate.Write(updateFile) 127 End Using 128 End If 129 End If 130 Next 131 End Using 132 133 ' ---------------------------------- 134 ' DUMP STATE OF EACH SIGNATURE FIELD 135 ' ---------------------------------- 136 137 Using inFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read) 138 ' open form 139 Dim document As New Document(inFile) 140 141 For Each field As Field In document.Fields 142 ' is this a signature field? 143 Dim sigField As SignatureField = TryCast(field, SignatureField) 144 If sigField IsNot Nothing Then 145 Console.WriteLine("Field '{0}'", sigField.FullName) 146 147 ' has it been signed? 148 If sigField.IsSigned Then 149 ' verify, based on the default handlers. 150 Dim verified As Boolean = sigField.Verify() 151 Console.WriteLine(" -- {0}", IIf(verified, "Verified", "Not verified")) 152 153 If verified Then 154 ' has the document been modified after signing? 155 Dim modified As Boolean = sigField.DocumentModifiedAfterSigning 156 Console.WriteLine(" -- {0}", IIf(modified, "Modified after signing", "Not modified after signing")) 157 End If 158 Else 159 Console.WriteLine(" -- Not signed", sigField.FullName) 160 End If 161 End If 162 Next 163 End Using