/**
  * Switches to the previous revision.
  *
  * @throws IOException
  * @throws GeneralSecurityException
  */
 public void switchToPreviousRevision() throws IOException, GeneralSecurityException {
   LOGGER.info("Switching to previous revision.");
   latestRevision = false;
   dss = reader.getCatalog().getAsDict(PdfName.DSS);
   Calendar cal = pkcs7.getTimeStampDate();
   if (cal == null) cal = pkcs7.getSignDate();
   // TODO: get date from signature
   signDate = cal.getTime();
   List<String> names = fields.getSignatureNames();
   if (names.size() > 1) {
     signatureName = names.get(names.size() - 2);
     reader = new PdfReader(fields.extractRevision(signatureName));
     this.fields = reader.getAcroFields();
     names = fields.getSignatureNames();
     signatureName = names.get(names.size() - 1);
     pkcs7 = coversWholeDocument();
     LOGGER.info(
         String.format(
             "Checking %ssignature %s",
             pkcs7.isTsp() ? "document-level timestamp " : "", signatureName));
   } else {
     LOGGER.info("No signatures in revision");
     pkcs7 = null;
   }
 }
 /**
  * Checks if the signature covers the whole document and throws an exception if the document was
  * altered
  *
  * @return a PdfPKCS7 object
  * @throws GeneralSecurityException
  */
 protected PdfPKCS7 coversWholeDocument() throws GeneralSecurityException {
   PdfPKCS7 pkcs7 = fields.verifySignature(signatureName);
   if (fields.signatureCoversWholeDocument(signatureName)) {
     LOGGER.info("The timestamp covers whole document.");
   } else {
     throw new VerificationException(null, "Signature doesn't cover whole document.");
   }
   if (pkcs7.verify()) {
     LOGGER.info("The signed document has not been modified.");
     return pkcs7;
   } else {
     throw new VerificationException(
         null, "The document was altered after the final signature was applied.");
   }
 }
 /**
  * Verifies a document level timestamp.
  *
  * @throws GeneralSecurityException
  * @throws IOException
  */
 public List<VerificationOK> verifySignature() throws GeneralSecurityException, IOException {
   LOGGER.info("Verifying signature.");
   List<VerificationOK> result = new ArrayList<VerificationOK>();
   // Get the certificate chain
   Certificate[] chain = pkcs7.getSignCertificateChain();
   verifyChain(chain);
   // how many certificates in the chain do we need to check?
   int total = 1;
   if (CertificateOption.WHOLE_CHAIN.equals(option)) {
     total = chain.length;
   }
   // loop over the certificates
   X509Certificate signCert;
   X509Certificate issuerCert;
   for (int i = 0; i < total; ) {
     // the certificate to check
     signCert = (X509Certificate) chain[i++];
     // its issuer
     issuerCert = null;
     if (i < chain.length) issuerCert = (X509Certificate) chain[i];
     // now lets verify the certificate
     LOGGER.info(signCert.getSubjectDN().getName());
     List<VerificationOK> list = verify(signCert, issuerCert, signDate);
     if (list.size() == 0) {
       try {
         signCert.verify(signCert.getPublicKey());
         if (latestRevision && chain.length > 1) {
           list.add(
               new VerificationOK(
                   signCert, this.getClass(), "Root certificate in final revision"));
         }
         if (list.size() == 0 && verifyRootCertificate) {
           throw new GeneralSecurityException();
         } else if (chain.length > 1)
           list.add(
               new VerificationOK(
                   signCert, this.getClass(), "Root certificate passed without checking"));
       } catch (GeneralSecurityException e) {
         throw new VerificationException(
             signCert, "Couldn't verify with CRL or OCSP or trusted anchor");
       }
     }
     result.addAll(list);
   }
   // go to the previous revision
   switchToPreviousRevision();
   return result;
 }
 /**
  * Checks the certificates in a certificate chain: are they valid on a specific date, and do they
  * chain up correctly?
  *
  * @param chain
  * @throws GeneralSecurityException
  */
 public void verifyChain(Certificate[] chain) throws GeneralSecurityException {
   // Loop over the certificates in the chain
   for (int i = 0; i < chain.length; i++) {
     X509Certificate cert = (X509Certificate) chain[i];
     // check if the certificate was/is valid
     cert.checkValidity(signDate);
     // check if the previous certificate was issued by this certificate
     if (i > 0) chain[i - 1].verify(chain[i].getPublicKey());
   }
   LOGGER.info("All certificates are valid on " + signDate.toString());
 }
 /**
  * Creates a VerificationData object for a PdfReader
  *
  * @param reader a reader for the document we want to verify.
  * @throws GeneralSecurityException
  */
 public LtvVerifier(PdfReader reader) throws GeneralSecurityException {
   super(null);
   this.reader = reader;
   this.fields = reader.getAcroFields();
   List<String> names = fields.getSignatureNames();
   signatureName = names.get(names.size() - 1);
   this.signDate = new Date();
   pkcs7 = coversWholeDocument();
   LOGGER.info(
       String.format(
           "Checking %ssignature %s",
           pkcs7.isTsp() ? "document-level timestamp " : "", signatureName));
 }
 /**
  * Parses content read from a java.io.Reader object.
  *
  * @param reader the content
  * @throws IOException
  */
 public void parse(final Reader reader) throws IOException {
   LOGGER.info(
       "Please note, there is a more extended version of the HTMLWorker available in the iText XMLWorker");
   SimpleXMLParser.parse(this, null, reader, true);
 }