Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo


Validation questions

  • Hello!

    I have few questions regarding to pdf validation, especially class VerifierLogic, method verify(String, byte). Application version is 1.1.1

    1. In line 109. when calling PdfPKCS7.verifyCertificates method - why don't you use Collection of CRLs (pk.getCRLs())? Now, CRL list is not considered at all. Am I right?
    2. In same line you use signDate (pk.getSignDate()). Why don't you use Timestamp token (pk.getTimeStampDate()) if there is one?
    3. Revocation against OCSP url is not implemented as I can see. pk.isRevocationValid() will do the job. Am I right?

    Thanks for great tool you gave to the community!

  • Josef Cacek
    Josef Cacek

    Hello Aleksandar,
    thank you for the reporting the issues (and sharing the expected state).
    I've commited the implementation to the CVS. Your points 1 and 2 were simply fixed. The 3rd point is not so straight forward so I've only added 2 additional boolean fields to SignatureVerification class (which holds the result):

    • ocspPresent
    • ocspValid
      What do you think, is this change sufficient? (If not could you please share the patch?)
  • Thanks Josef for your quick response!

    Code changes that you commited are sufficient (IMHO).

    Regarding to pdf verification there are some more things that need to be done (IMHO, again):

    1. Timestamp verification -class org.bouncycastle.tsp.TimeStampToken can do the job…
    2. Checking if there is certification level set on some revision. E.g. one person signs document and sets certification level to "no changes allowed". Later second person signs document again. That way first signuture becomes invalid (because second person changed the document).

    I think that with this two things implemented, pdf verification will become complete. What do you think?


  • Josef Cacek
    Josef Cacek

    The TSA certificate is validated too now.
    The 2nd point is harder and I have to skip it. (But the volunteers are always welcomed. :-) )

  • Thanks again for your quick response!

    Regarding to certification level in revisions here is my solution:



    class I would add new field:

    int certificationLevel

    (setter and getter, of course).



    class, in

    verify(String, byte[])

    method, inside iteration (e.g. in 133. line), I would add following:

    InputStream revision = extractRevision(aFileName, aPassword, name);
    try {
        final PdfReader revisionReader = new PdfReader(revision);
    } finally {
        if(revision != null){

    So, when validating pdf, all revisions but last must have certification level equal to



    That leads me to another question… How to determine last signature? Can we rely that


    method of


    class returns signature names in chronological order (same order they have been added to pdf)? Or we have to compare signature dates?

  • And one more thing regarding to code I've just posted.
    I measured time needed for validating document and extracting information with and without revision extracting. For document with 5 revisions, process lasted 200ms longer but without revision extracting. For documents with less revisions that difference is smaller…
    So, IMHO, that difference is not so important…

  • Josef Cacek
    Josef Cacek

    Thanks for the solution, Aleksandar!
    I've overseen the PdfReader's method getCertificationLevel and I though it has to be extracted manually (DocMDP) from each signature.
    The ordering should be OK - I've changed implementation of AcroFields.getSignatureNames() a little bit, so it should return the signatures in the right order.
    The for loop in VerifierLogic goes from the newest to the oldest signature:

    final List<String> tmpNames = tmpAcroFields.getSignatureNames();
    for (int i = tmpNames.size() - 1; i >= 0; i--) {
       // impl

    and that's what we want (IMHO).

  • Great!

    I think that everything for full validation is now here. I would suggest one more thing: Summary and user-friendly message for validation.

    E.g. (tmpVerif is instance of SignatureVerification)
    If some of the revisions is modified (tmpVerif.isModified()) - ERROR, "Document is altered and can not be trusted!"
    If last signature doesn't cover all document (tmpVerif.isWholeDocument()) - ERROR, "Document has unsigned content!"
    Do we trust to all certificates (tmpVerif.getFails()) - WARNING, "Some of the certificates are not trusted!" (or tmpVerif.getFails())
    If some of the previous revision has certification level (tmpVerif.getCertificationLevel()) different but NOT_CERTIFIED - ERROR,  "There have been changes made to this document that invalidate the signature"
    If there is no Timestamp token (tmpVerif.isTsTokenPresent()) - WARNING, "Signature date/time are from the clock on the signer's computer"
    If Timestamp token can't be verified (tmpVerif.getTsTokenValidationResult()) - WARNING, "Signature is timestamped but the timestamp could not be verified"
    If OCSP is present but not valid (tmpVerif.isOcspPresent() and tmpVerif.isOcspValid()) - ERROR, "OCSP is not valid"
    And finally if there is no warnings/errors - INFO, "Document is valid"

    This list is not final - probably there are some scenarios…
    For messages, maybe we should look at Adobe Reader's messages (some of the above are from Reader).

    What do you think?

  • Josef Cacek
    Josef Cacek

    I think, our new team member could have a look. :-)
    Aleksandar, welcome!

  • For the sake of this thread I'll describe what I've implemented:

    1) SignatureVerification class gets new field - signCertTrustedAndValid - true if signing certificate is directly trusted (regarding to chosen KeyStore) and valid (it's not expired and doesn't appear in CRL).
    2) VerifierLogic gets two new static methods - getValidationCodes(VerificationResult) and getValidationCode(SignatureVerification, boolean). Later method checks properties of signature and returns status code (defined in SignatureVerification) that describes state of certificate (there 3 types of states - error, warning and info).

  • Josef Cacek
    Josef Cacek

    Thanks for the improvements, Aleksandar. What about to return some non-zero exit code if a validation fails?

  • Josef Cacek
    Josef Cacek

    Thanks for the new code Aleksandar.
    I've refactored it a litle. Moved the code related to validationCode directly to SignatureVerification class and also added fail-fast command line argument to Verifier.java. (Validation code is now int instead of Integer).
    I didn't test the changes yet. So maybe I've overseen something.