Search code examples
pdfadobedigital-signaturebouncycastlepdfbox

why I have 1 Miscellaneus Change - if I add Document Security Store


I have signed document. and I want to add DSS to my document.

        Security.addProvider(new BouncyCastleProvider());

        File signedDocument = new File("/signed.pdf");
        File out = new File("/signed_plus_dss");

        byte[] buffer = new byte[8 * 1024];
        FileInputStream fis = new FileInputStream(signedDocument);
        FileOutputStream fos = new FileOutputStream(out);

        int c;
        while ((c = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, c);
        }
        fis.close();
        fis = new FileInputStream(out);

        // load document
        PDDocument doc = PDDocument.load(signedDocument);
        PDDocumentCatalog catalog = doc.getDocumentCatalog();
        COSDictionary catalogDictionary = catalog.getCOSDictionary();
        COSDictionary dssDictionary = new COSDictionary();

        /* ... I can add OCSP responses, and CRLS, and Certs here    
            in order to create document LTV, but now I don't need that. 
            I have another problem, not this... */


        /* if that's false, nothing happens */ 
        catalogDictionary.setNeedToBeUpdate(true);
        catalogDictionary.setItem(COSName.getPDFName("DSS"), dssDictionary);  

        /* ... if we add here Document level time stamp, everything is fine.
        signature will not be invalid with TSA. but it's invalid without TSA ... */  
        doc.saveIncremental(fis, fos);

that's it. everything is fine. when I see PDF Structure there is Document Security Store. but when I open PDF with adobe reader, my signature is invalid because - "Document has been altered or corrupted since it was signed." and "1 Miscellaneus Change(s)"

but, something interesting happens here - if I add Pades-LTV (DSS + TSA), Everything works:

for example, if we add that codes:

        URL tsaURL = new URL(TSAUrl);
        PDSignature signature = new PDSignature();
        signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); 
        signature.setSubFilter(COSName.getPDFName("ETSI.RFC3161"));
        signature.setSignDate(Calendar.getInstance());
        TimestampeInt signatureInt = new TimestampeInt(tsaURL, null, null);
        doc.addSignature(signature, signatureInterface);
        doc.saveIncremental(fis, fos);

by the result, Document Level Time stump works fine. But I need to add only DSS too without TSA. how can I resolve that problem, what do you think?

sample documents: First sample is - signature plus only DSS. Second sample is signature plus DSS plus Document level time stump


Solution

  • While both in the originally signed document and in the document with DSS and Timestamp added, the AcroForm dictionary is a direct object in the Catalog, it is an indirect object in the document with only DSS added:

    SIGN.pdf:

    5 0 obj
    <<
    /Type /Catalog
    /Pages 3 0 R
    /AcroForm <<
    /Fields [7 0 R]
    /SigFlags 3
    >>
    >> 
    endobj
    

    SIGN+DSS.pdf:

    5 0 obj
    <<
    /Type /Catalog
    /Pages 3 0 R
    /AcroForm 12 0 R
    /DSS 13 0 R
    >>
    endobj
    12 0 obj
    <<
    /Fields [7 0 R]
    /SigFlags 3
    >> 
    endobj
    

    SIGN+DSS+TSA.pdf:

    5 0 obj
    <<
    /Type /Catalog
    /Pages 3 0 R
    /AcroForm <<
    /Fields [7 0 R 12 0 R]
    /SigFlags 3
    >>
    /DSS 13 0 R
    >> 
    endobj
    

    While this is equivalent for the documents at hand, Adobe Reader might be befuddled by that.

    I patched your SIGN+DSS.pdf to also have the AcroForm dictionary as a direct object in the Catalog here and Adobe Reader was happy...

    Difference in the patched SIGN+DSS.pdf version