0

I am setting up a verifier which makes it possible to check the validity of signature.

The signature I do is based on DSS level LT so revocation checking is built into the document.

The problem that I encounter now is at the level of the verifier that I developed in iText. It allows the verification of the validity of the signature but of the information of the revocation. IText according to my research allows to verify this information in the signature itself based on: pkcs7.getCrl().

However, the DSS signature incorporates the revocation information into the dictionaries.

Below is the code I use to verify the signature:

import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfString;
import com.itextpdf.text.pdf.security.PdfPKCS7;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class TestCheck {

    public static String pdf_file = "CURRENT_SIGNATURE.pdf";

    public static final boolean verifySignature(PdfReader pdfReader)
            throws GeneralSecurityException, IOException {
        
        boolean valid = false;
        AcroFields acroFields = pdfReader.getAcroFields();
        
        
        PdfDictionary sigDict = acroFields.getSignatureDictionary("Signature1"); 
        System.out.println(sigDict);
        PdfString contents = sigDict.getAsString(PdfName.CONTENTS);

        
        List<String> signatureNames = acroFields.getSignatureNames();
        if (!signatureNames.isEmpty()) {
            for (String name : signatureNames) {
//                if (acroFields.signatureCoversWholeDocument(name)) {
                    PdfPKCS7 pkcs7 = acroFields.verifySignature(name);
                    valid = pkcs7.verify();
                    String reason = pkcs7.getReason();
                    Calendar signedAt = pkcs7.getSignDate();
                    X509Certificate signingCertificate = pkcs7.getSigningCertificate();
                    Principal issuerDN = signingCertificate.getIssuerDN();
                    Principal subjectDN = signingCertificate.getSubjectDN();
                    System.out.println("valid = "+valid);
                    //System.out.println("date = "+signedAt.getTime());
                    ////System.out.println("reason = "+reason);
                    //System.out.println("issuer = "+issuerDN);
                    //System.out.println("subject = "+subjectDN);
                    System.out.println("CRL : " + pkcs7.getCRLs());
                    break;
                }
           // }
        }
        return valid;
    }

    public static void main(String[] args) throws Exception {

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        
        InputStream is = new FileInputStream(new File(pdf_file));
        PdfReader reader = new PdfReader(is);
        
        
        boolean ok = verifySignature(reader);
        System.out.println("Ver : "+ ok);
    }
}
Med
  • 9
  • 2

1 Answers1

0

Initially I wanted to simply point to the LtvVerifier class provided both by iText 5 and iText 7. Testing with that class, though, it turned out to not be applicable to the current PAdES BASELINE profiles but instead has been designed for an older PAdES-LTV profile (see ETSI TS 102 778-4 section 4 "Profile for PAdES-LTV").

If I understand your question correctly, though, you already know how to evaluate CRLs and OCSP responses. Thus, it would suffice if you learned how to extract the revocation information from the DSS dictionaries.

Your example code apparently uses iText 5.x, so I used the current iText 5.5.14-SNAPSHOT. A bit older versions should be usable with the same code, too.

PdfReader pdfReader = new PdfReader(...);

PdfDictionary dss = pdfReader.getCatalog().getAsDict(PdfName.DSS);
if (dss == null)
    System.out.println("No DSS in PDF");
else {
    PdfArray crlarray = dss.getAsArray(PdfName.CRLS);
    if (crlarray == null || crlarray.size() == 0)
        System.out.println("No CRLs in DSS");
    else {
        System.out.println("CRLs:");
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        for (int i = 0; i < crlarray.size(); i++) {
            PRStream stream = (PRStream) crlarray.getAsStream(i);
            X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(PdfReader.getStreamBytes(stream)));

            System.out.printf("  '%s' update %s\n", crl.getIssuerX500Principal(), crl.getThisUpdate());
        }
    }

    PdfArray ocsparray = dss.getAsArray(PdfName.OCSPS);
    if (ocsparray == null || ocsparray.size() == 0)
        System.out.println("\nNo OCSP responses in DSS");
    else {
        System.out.println("\nOCSP Responses:");
        for (int i = 0; i < ocsparray.size(); i++) {
            PRStream stream = (PRStream) ocsparray.getAsStream(i);
            OCSPResp ocspResponse = new OCSPResp(PdfReader.getStreamBytes(stream));
            if (ocspResponse.getStatus() == 0) {
                try {
                    BasicOCSPResp basicOCSPResp = (BasicOCSPResp) ocspResponse.getResponseObject();
                    System.out.printf("  '%s' update %s\n", basicOCSPResp.getResponderId(), basicOCSPResp.getProducedAt());
                } catch (OCSPException e) {
                    throw new GeneralSecurityException(e);
                }
            }
        }
    }
}

(VerifyLtv test testExtractRevocationInformationCURRENT_SIGNATURE)

Instead of printing information to System.out you can of course collect the CRLs and OCSP responses and process them as you used to.

Also, you can of course check both the revocation data you retrieve from the PdfPKCS7 object and the data from the DSS. Adobe Acrobat also uses both during verification.

mkl
  • 90,588
  • 15
  • 125
  • 265
  • Great, it works very well. I'm really, really grateful to you, not just today but since I joined the signing world. – Mehdi Feb 15 '22 at 12:57
  • la dernière question c'est est ce que c'est possible de faire la même chose avec DSS (verificateur DSS) ??? – Mehdi Feb 15 '22 at 12:58
  • *"est ce que c'est possible de faire la même chose avec DSS (verificateur DSS) ???"* - If I recall correctly, you can request inclusion of all the used binaries (certificates, revocation information, signatures, timestamps) in the diagnostic data report. Thus, it also should be possible to retrieve them directly. – mkl Feb 15 '22 at 14:31
  • yes I understood, do you have this same example in C# its to complete an old checker that I had developed in C# ? Thanks a lot – Mehdi Feb 17 '22 at 19:45
  • I have not ported that to iTextSharp yet, so no, I don't have "this same example in C#". Nonetheless it should be easy to port. For iText it's mainly the capitalization of method names (and here or there a getter/setter pairs replaced by a property). – mkl Feb 18 '22 at 10:43
  • and if i just want to ensure revocation check without timestamp like the example you can download via this link : https://www.grosfichiers.com/iG9gnb7RWKU – Mehdi Apr 18 '22 at 13:37