Verify a custom digital PDF signature

Manipulate PDF, Security

In the article about create a custom digital PDF signature we explained how to create custom signature handlers. In this article we are going to explain how to verify them using PDFKit.NET.


If you sign a document with a custom signature, following the code in the article that explains how to create a custom digital signature, and open it in Adobe reader, you will see the following message when you click on the signature.


This is to be expected, because Adobe does not know about our custom signature. If you want it to be able to deal with this, you will need to write your own plug-in for Adobe Reader.

This article is not about creating such an Adobe Reader plug-in, but about verifying a custom signature programmatically with PDFKit.NET. As we have seen in the previously mentioned article PDFKit.NET allows you to a define custom signature handler. In this handler you can override the Sign method to provide your own signature, and you can override the Verify method to verify it. It did not however show you how the Verify code will get triggered in PDFKit.NET. This article will show you this.

Please note that the code below has been based on the customSignVerifyAndUpdates sample that is included in the PDFKit.NET distribution.

Usually, verification of "standard" signature fields is very simple in PDFKit.NET. You can call SignatureField.IsSigned to determine whether a signature field has been signed, and a call to SignatureField.Verify() will tell you whether the signature is valid.

When you have fields with custom signatures, this is not enough however, because the standard signature handlers in PDFKit.NET also do not know how to deal with these. In that case, you will need to pass a custom handler to the Verify method, like shown below:

C# code sample

1 foreach (Field field in document.Fields) 2 { 3 // is this a signature field? 4 SignatureField sigField = field as SignatureField; 5 if (null != sigField) 6 { 7 Console.WriteLine("Field '{0}'", sigField.FullName); 8 9 // has it been signed? 10 if (sigField.IsSigned) 11 { 12 // verify, based on our own handler. Note that if you do not pass 13 // the factory, the default handler will throw an exception 14 // indicating that it does not support signature type: 15 // "CustomSignatureHandler / revision 1". 16 17 bool verified = sigField.Verify(new CustomSignatureHandlerFactory(sigField.SignedName)); 18 Console.WriteLine(" -- {0}", verified ? "Verified" : "Not verified"); 19 20 if (verified) 21 { 22 // has the document been modified after signing? 23 bool modified = sigField.DocumentModifiedAfterSigning; 24 25 Console.WriteLine(" -- {0}", 26 modified ? "Modified after signing" : "Not modified after signing"); 27 } 28 } 29 else 30 { 31 Console.WriteLine(" -- Not signed", sigField.FullName); 32 } 33 } 34 }

VB.NET code sample

1 For Each field As Field In document.Fields 2 ' is this a signature field? 3 Dim sigField As SignatureField = TryCast(field, SignatureField) 4 If sigField IsNot Nothing Then 5 Console.WriteLine("Field '{0}'", sigField.FullName) 6 7 ' has it been signed? 8 If sigField.IsSigned Then 9 ' verify, based on our own handler. Note that if you do not pass 10 ' the factory, the default handler will throw an exception 11 ' indicating that it does not support signature type: 12 ' "CustomSignatureHandler / revision 1". 13 14 Dim verified As Boolean = sigField.Verify(New CustomSignatureHandlerFactory(sigField.SignedName)) 15 Console.WriteLine(" -- {0}", If(verified, "Verified", "Not verified")) 16 17 If verified Then 18 ' has the document been modified after signing? 19 Dim modified As Boolean = sigField.DocumentModifiedAfterSigning 20 21 Console.WriteLine(" -- {0}", If(modified, "Modified after signing", "Not modified after signing")) 22 End If 23 Else 24 Console.WriteLine(" -- Not signed", sigField.FullName) 25 End If 26 End If 27 Next

The custom signature handler factory however, should not just return the custom handler that we have defined in KB 000326. It should not only deal with custom signatures, but it must also work for 'ordinary' ones. This means that the factory should inspect the filter and revision of the signature field and return a handler that is appropriate for that particular field. The code below shows this. It only returns our custom handler when the filter and revision are right, otherwise it returns a standard handler.

C# code sample

1 private class CustomSignatureHandlerFactory : ISignatureHandlerFactory 2 { 3 public CustomSignatureHandlerFactory(string name) 4 { 5 _name = name; 6 } 7 8 #region ISignatureHandlerFactory Members 9 10 public SignatureHandler Create(string filter, int revision, string subFilter) 11 { 12 if (filter == "CustomSignatureHandler" && revision == 1) 13 { 14 return new CustomSignatureHandler(_name); 15 } 16 17 return (new StandardSignatureHandlerFactory()).Create(filter, revision, subFilter); 18 } 19 20 #endregion 21 22 private string _name; 23 }

VB.NET code sample

1 Private Class CustomSignatureHandlerFactory 2 Implements ISignatureHandlerFactory 3 Public Sub New(name As String) 4 _name = name 5 End Sub 6 7 #Region "ISignatureHandlerFactory Members" 8 9 Public Function Create(filter As String, revision As Integer, subFilter As String) As SignatureHandler 10 If filter = "CustomSignatureHandler" AndAlso revision = 1 Then 11 Return New CustomSignatureHandler(_name) 12 End If 13 14 Return (New StandardSignatureHandlerFactory()).Create(filter, revision, subFilter) 15 End Function 16 17 #End Region 18 19 Private _name As String 20 End Class

When SignatureField.Verify(new CustomSignatureHandlerFactory(sigField.SignedName)) gets called for a field that has been signed with a custom signature, our own custom signature handler will be used to verify the field. This means that the Verify method of the custom handler will be invoked, and that the result will be passed to SignatureField.Verify(...).

Please note that the result of SignatureField.Verify(...) also determines whether a document has been tampered with. The verify method should return false when the signature digest no longer matches the document.

This must not be confused with a call to SignatureField.DocumentModifiedAfterSigning. The latter does not indicate whether a document has been tampered with. SignatureField.DocumentModifiedAfterSigning indicates whether a document has been been updated in a regular way after signing, by appending an update. If such an update is appended, this will not invalidate the signature for the earlier revision of the document, but PDF readers will signal this, so that it is clear to users that an earlier version was signed, an not the current version.

Note also that if a document has been updated after signing, that PDFKit.NET allows you to obtain the earlier signed version via the SignatureField.SignedUpdate property. So, if a signature is valid - i.e. Verify() returns true -, it is always possible to inspect the version that was signed.