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.

using (FileStream sourceFile = new FileStream(@"..\..\form.pdf", FileMode.Open, FileAccess.Read))
{
    // open the form
    Document document = new Document(sourceFile);

    // file out the data fields
    TextField projectNr = document.Fields["projectNumber"] as TextField;
    projectNr.Value = "FF-235";
         
    TextField sName = document.Fields["studentName"] as TextField;
    sName.Value = "Bob Stapleton";
         
    TextField sDate = document.Fields["studentDate"] as TextField;
    sDate.Value = "April 18, 2007";

    // retrieve the signature field
    SignatureField sigField = document.Fields["studentSignature"] as SignatureField;
         
    // open certicate store.
    Pkcs12Store store = null;
    using (FileStream storeFile = new FileStream(@"..\..\BobStapleton.pfx", FileMode.Open, FileAccess.Read))
    {
    store = new Pkcs12Store(storeFile, "studentpassword");
    }
         
    // let the factory decide which type should be used.
    SignatureHandler handler = StandardSignatureHandler.Create(store);

    // associate the handler with the signature field
    sigField.SignatureHandler = handler;

    // set optional info.
    sigField.ContactInfo = "+31 (0)77 4748677";
    sigField.Location = "The Netherlands";
    sigField.Reason = "I hereby declare!";

    // save the signed document - while saving, the handler 
    // will be called to sign the saved content
    using (FileStream outFile = new FileStream(@"..\..\signedByStudent.pdf", FileMode.Create, FileAccess.ReadWrite))
    {
    document.Write(outFile);
    }
}

// -----------------------------------------------------
// TEACHER FILLS OUT FINAL FIELDS AND SIGNS THE DOCUMENT
// -----------------------------------------------------

using (FileStream sourceFile = new FileStream(@"..\..\signedByStudent.pdf", FileMode.Open, FileAccess.Read))
{
    // open the form
    Document document = new Document(sourceFile);

    // file out the data fields

    TextField tName = document.Fields["teacherName"] as TextField;
    tName.Value = "Max Boulton";

    TextField tDate = document.Fields["teacherDate"] as TextField;
    tDate.Value = "April 18, 2007";

    // retrieve the signature field
    SignatureField sigField = document.Fields["teacherSignature"] as SignatureField;

    // open certicate store.
    Pkcs12Store store = null;
    using (FileStream storeFile = new FileStream(@"..\..\MaxBoulton.pfx", FileMode.Open, FileAccess.Read))
    {
    store = new Pkcs12Store(storeFile, "teacherpassword");
    }

    // let the factory decide which type should be used.
    SignatureHandler handler = StandardSignatureHandler.Create(store);

    // associate the handler with the signature field
    sigField.SignatureHandler = handler;

    // set optional info.
    sigField.ContactInfo = "+31 (0)77 4748677";
    sigField.Location = "The Netherlands";
    sigField.Reason = "I hereby declare!";

    // save the signed document - while saving, the handler 
    // will be called to sign the saved content
    using (FileStream outFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Create, FileAccess.ReadWrite))
    {
    document.Write(outFile, DocumentWriteMode.AppendUpdate);
    }
}

// ----------------------------------------------------
// ENUMERATE UPDATES IN DOCUMENT THAS BEEN SIGNED TWICE
// ----------------------------------------------------

using (FileStream sourceFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read))
{
    // open the form
    Document document = new Document(sourceFile);

    // count the number of updates
    //Console.WriteLine( "This document has {0} updates.", document.Updates.Count );
         
    // save each update as a new PDF document
    foreach (Update update in document.Updates)
    {
    string name = string.Format( @"..\..\signedByTeacher_{0}.pdf", update.Index );
    using (FileStream updateFile = new FileStream(name, FileMode.Create, FileAccess.Write))
    {
        update.Write(updateFile);
    }
    }
}

// -----------------------------------------------------------
// ENUMERATE SIGNATURE FIELDS AND SAVE SIGNED UPDATE PER FIELD
// -----------------------------------------------------------

using (FileStream sourceFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read))
{
    // open the form
    Document document = new Document(sourceFile);

    foreach (Field field in document.Fields)
    {
    // is this a signature field?
    SignatureField sigField = field as SignatureField;
    if (null != sigField)
    {
        // has it been signed?
        if (sigField.IsSigned)
        {
            // save the update and name it after the field
            string name = string.Format(@"..\..\{0}.pdf", sigField.FullName);
            using (FileStream updateFile = new FileStream(name, FileMode.Create, FileAccess.Write))
            {
                sigField.SignedUpdate.Write(updateFile);
            }
        }
    }
    }
}

// ----------------------------------
// DUMP STATE OF EACH SIGNATURE FIELD
// ----------------------------------

using (FileStream inFile = new FileStream(@"..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read))
{
    // open form
    Document document = new Document(inFile);

    foreach (Field field in document.Fields)
    {
    // is this a signature field?
    SignatureField sigField = field as SignatureField;
    if (null != sigField)
    {
        Console.WriteLine("Field '{0}'", sigField.FullName);

        // has it been signed?
        if (sigField.IsSigned)
        {
            // verify, based on the default handlers.
            bool verified = sigField.Verify();
            Console.WriteLine("  -- {0}", verified ? "Verified" : "Not verified");

            if (verified)
            {
                // has the document been modified after signing?
                bool modified = sigField.DocumentModifiedAfterSigning;
                Console.WriteLine("  -- {0}", modified ? "Modified after signing" : "Not modified after signing");
            }
        }
        else
        {
            Console.WriteLine("  -- Not signed", sigField.FullName);
        }
    }
    }
}
' -------------------------------------------
' STUDENT FILLS OUT FIELDS AND SIGNS DOCUMENT
' -------------------------------------------

Using sourceFile As New FileStream("..\..\form.pdf", FileMode.Open, FileAccess.Read)
    ' open the form
    Dim document As New Document(sourceFile)

    ' file out the data fields
    Dim projectNr As TextField = TryCast(document.Fields("projectNumber"), TextField)
    projectNr.Value = "FF-235"

    Dim sName As TextField = TryCast(document.Fields("studentName"), TextField)
    sName.Value = "Bob Stapleton"

    Dim sDate As TextField = TryCast(document.Fields("studentDate"), TextField)
    sDate.Value = "April 18, 2007"

    ' retrieve the signature field
    Dim sigField As SignatureField = TryCast(document.Fields("studentSignature"), SignatureField)

    ' open certicate store.
    Dim store As Pkcs12Store = Nothing
    Using storeFile As New FileStream("..\..\BobStapleton.pfx", FileMode.Open, FileAccess.Read)
        store = New Pkcs12Store(storeFile, "studentpassword")
    End Using

    ' let the factory decide which type should be used.
    Dim handler As SignatureHandler = StandardSignatureHandler.Create(store)

    ' associate the handler with the signature field
    sigField.SignatureHandler = handler

    ' set optional info.
    sigField.ContactInfo = "+31 (0)77 4748677"
    sigField.Location = "The Netherlands"
    sigField.Reason = "I hereby declare!"

    ' save the signed document - while saving, the handler 
    ' will be called to sign the saved content
    Using outFile As New FileStream("..\..\signedByStudent.pdf", FileMode.Create, FileAccess.ReadWrite)
        document.Write(outFile)
    End Using
End Using

' -----------------------------------------------------
' TEACHER FILLS OUT FINAL FIELDS AND SIGNS THE DOCUMENT
' -----------------------------------------------------

Using sourceFile As New FileStream("..\..\signedByStudent.pdf", FileMode.Open, FileAccess.Read)
    ' open the form
    Dim document As New Document(sourceFile)

    ' file out the data fields

    Dim tName As TextField = TryCast(document.Fields("teacherName"), TextField)
    tName.Value = "Max Boulton"

    Dim tDate As TextField = TryCast(document.Fields("teacherDate"), TextField)
    tDate.Value = "April 18, 2007"

    ' retrieve the signature field
    Dim sigField As SignatureField = TryCast(document.Fields("teacherSignature"), SignatureField)

    ' open certicate store.
    Dim store As Pkcs12Store = Nothing
    Using storeFile As New FileStream("..\..\MaxBoulton.pfx", FileMode.Open, FileAccess.Read)
        store = New Pkcs12Store(storeFile, "teacherpassword")
    End Using

    ' let the factory decide which type should be used.
    Dim handler As SignatureHandler = StandardSignatureHandler.Create(store)

    ' associate the handler with the signature field
    sigField.SignatureHandler = handler

    ' set optional info.
    sigField.ContactInfo = "+31 (0)77 4748677"
    sigField.Location = "The Netherlands"
    sigField.Reason = "I hereby declare!"

    ' save the signed document - while saving, the handler 
    ' will be called to sign the saved content
    Using outFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Create, FileAccess.ReadWrite)
        document.Write(outFile, DocumentWriteMode.AppendUpdate)
    End Using
End Using

' ----------------------------------------------------
' ENUMERATE UPDATES IN DOCUMENT THAS BEEN SIGNED TWICE
' ----------------------------------------------------

Using sourceFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)
    ' open the form
    Dim document As New Document(sourceFile)

    ' count the number of updates
    'Console.WriteLine( "This document has {0} updates.", document.Updates.Count );

    ' save each update as a new PDF document
    For Each update As Update In document.Updates
        Dim name As String = String.Format("..\..\signedByTeacher_{0}.pdf", update.Index)
        Using updateFile As New FileStream(name, FileMode.Create, FileAccess.Write)
            update.Write(updateFile)
        End Using
    Next
End Using

' -----------------------------------------------------------
' ENUMERATE SIGNATURE FIELDS AND SAVE SIGNED UPDATE PER FIELD
' -----------------------------------------------------------

Using sourceFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)
    ' open the form
    Dim document As New Document(sourceFile)

    For Each field As Field In document.Fields
        ' is this a signature field?
        Dim sigField As SignatureField = TryCast(field, SignatureField)
        If sigField IsNot Nothing Then
            ' has it been signed?
            If sigField.IsSigned Then
                ' save the update and name it after the field
                Dim name As String = String.Format("..\..\{0}.pdf", sigField.FullName)
                Using updateFile As New FileStream(name, FileMode.Create, FileAccess.Write)
                    sigField.SignedUpdate.Write(updateFile)
                End Using
            End If
        End If
    Next
End Using

' ----------------------------------
' DUMP STATE OF EACH SIGNATURE FIELD
' ----------------------------------

Using inFile As New FileStream("..\..\signedByTeacher.pdf", FileMode.Open, FileAccess.Read)
    ' open form
    Dim document As New Document(inFile)

    For Each field As Field In document.Fields
        ' is this a signature field?
        Dim sigField As SignatureField = TryCast(field, SignatureField)
        If sigField IsNot Nothing Then
            Console.WriteLine("Field '{0}'", sigField.FullName)

            ' has it been signed?
            If sigField.IsSigned Then
                ' verify, based on the default handlers.
                Dim verified As Boolean = sigField.Verify()
                Console.WriteLine("  -- {0}", IIf(verified, "Verified", "Not verified"))

                If verified Then
                    ' has the document been modified after signing?
                    Dim modified As Boolean = sigField.DocumentModifiedAfterSigning
                    Console.WriteLine("  -- {0}", IIf(modified, "Modified after signing", "Not modified after signing"))
                End If
            Else
                Console.WriteLine("  -- Not signed", sigField.FullName)
            End If
        End If
    Next
End Using