3.23.  Signatures and Certificates

Overview

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”.

Existence of Signatures

The simpest test is to check whether a document is actually signed:

<testcase name="isSigned">
  <assertThat testDocument="signed/sampleSignedPDFDocument.pdf">
    <isSigned />
  </assertThat>
</testcase>

Names and Numbers of Signatures

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>

Validity Date

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" /> 1
    </hasSignature>
  </assertThat>
</testcase>

1

The attribute pattern=".." declares that dates are compared using year-month-day.

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>

Revision, Reason, Sign-Name

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.

Compare Signatures using XML/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.

Multiple Invocation

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.