If contractual information is sent as a PDF documents you must check that the data really was sent by the person they claim to be. Certificates allow this. A certificate confirms the authenticity of personal or corporate data. It confirms your signature when you “sign” the content of a document in a special formular field.
PDFUnit provides many tags for signatures and certificates:
<!-- Tags to test signatures: --> <hasNumberOfSignatures /> <isSigned /> <hasSignature name=".." (required) > <coveringWholeDocument /> (optional) <withNumberOfRevisions /> (optional) <withReason /> (optional) <withRevision /> (optional) <withCertificate /> (optional) <withSigningDate /> (optional) <withSigningName /> (optional) </hasSignature> <hasSignature name=".." (required) > <withCertificate (optional) > <validForCurrentDate /> (optional) <validFor /> (optional) <validFrom /> (optional) <validUntil /> (optional) <havingSubjectField name=".." value=".." /> </withCertificate> </hasSignature> <hasSignatures> <matchingXPath /> (optional) <matchingXML /> (optional) </hasSignatures>
When executing the test, PDFUnit only reads the properties of the PDF document. There is no access to remote systems. Thus PDFUnit does not check whether a certificate has been revoked.
A “signed” PDF must not be confused with a “certified” PDF. A “certified” PDF guarantees the compliance with certain properties which are needed to process a document in further workflow steps. Such properties are summarized in “profiles”. Tests for certified PDF documents are described in chapter 3.5: “Certified PDF”.
The simpest test is to check whether a document is actually signed:
<testcase name="isSigned"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <isSigned /> </assertThat> </testcase>
A document may contain multiple signatures, for example when more than one person has signed it. Thus the next tests check to the number and names of the certificates:
<testcase name="hasNumberOfSignatures"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasNumberOfSignatures>1</hasNumberOfSignatures> </assertThat> </testcase>
<testcase name="hasSignature"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2" /> </assertThat> </testcase>
Sometimes you need to know that a given date lies within the validity period of a certificate:
<testcase name="hasSignatureValidForCurrentDate"> <assertThat testDocument="signed/find_document.pdf"> <hasSignature name="Signature2"> <withCertificate> <validForCurrentDate /> </withCertificate> </hasSignature> </assertThat> </testcase>
<testcase name="hasSignatureWithSigningDate_DATE"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <withSigningDate date="2009-07-16" pattern="yyyy-MM-dd" /> </hasSignature> </assertThat> </testcase>
Another test is to ensure that a certificate is valid within a time period:
<testcase name="hasSignature_FirstAndLastDate"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <withCertificate> <validFrom date="20060822" pattern="yyyyMMdd" /> <validUntil date="20090904" pattern="yyyyMMdd" /> </withCertificate> </hasSignature> </assertThat> </testcase>
The next examples show how various details of a signature can be tested using specific tags:
<testcase name="hasSignature_CoveringWholeDocument"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <coveringWholeDocument /> </hasSignature> </assertThat> </testcase>
<testcase name="hasSignature_WithSigningName"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <withSigningName name="John B Harris"/> </hasSignature> </assertThat> </testcase>
<testcase name="hasSignature_WithRevision"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <withRevision nr="1" /> </hasSignature> </assertThat> </testcase>
<testcase name="hasSignature_WithNumberOfRevisions"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <withNumberOfRevisions nr="1" /> </hasSignature> </assertThat> </testcase>
<testcase name="hasSignature_WithReason"> <assertThat testDocument="signed/sampleSignedPDFDocument.pdf"> <hasSignature name="Signature2"> <withReason>I am the author of this document</withReason> </hasSignature> </assertThat> </testcase>
You can check other signature and certificate data using XPath.
Any data of a signature can be verified using XPath expressions.
You can see the signature data as an XML stucture when you extract it
with the utility program ExtractSignaturesInfo
.
The following image shows a small part of the file:
|
The corresponding image created by Adobe Reader® shows the same information:
|
The signature information of a document can be compared in its entirety with an XML file:
<testcase name="hasSignatures_MatchingXML"> <assertThat testDocument="signed/helloWorld_sign.pdf"> <hasSignatures> <matchingXML file="signed/helloWorld_sign.xml" /> </hasSignatures> </assertThat> </testcase>
When parts of the XML are the test goal, a matching XPath expression
has to be found. The following example checks that the first certificate
contains one OU
tag with an expected value:
<testcase name="hasSignatures_MatchingXPath_OneOfManyOU"> <assertThat testDocument="signed/helloWorld_sign.pdf"> <hasSignatures> <matchingXPath expr="//certificate[1]/subject[OU='Digital ID Class 1 - Netscape']" /> </hasSignatures> </assertThat> </testcase>
Useful hint: Eclipse provides the “XPath-View” to work with XPath expressions.
Of course, a single signature can be checked for multiple properties:
<testcase name="differentAspectsAroundSignature"> <assertThat testDocument="signed/helloWorld_sign.pdf"> <isSigned /> <hasSignature name="sign_rbl" > <withSigningName name="Raymond Berthou" /> <withSigningDate date="2007-10-14T09:09:12+0200" pattern="yyyy-MM-dd'T'HH:mm:ssZ" /> <withRevision nr="1" /> <withCertificate> <havingSubjectField name="O" value="VeriSign, Inc." /> </withCertificate> </hasSignature> </assertThat> </testcase>
But think of a better name for this test. It would be better to split it into several tests with specific names.