Hi,
I have tried to certify a PDF with the provided code, but failed. This is
the code I'm trying
final PrivateKey privateKey = ...
final Certificate certificate = ...
PDDocument doc = PDDocument.load(input);
// PDSignature
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setReason("The reason");
signature.setName("The name");
signature.setSignDate(Calendar.getInstance());
// DocMDP thing
COSDictionary dictionary = signature.getCOSObject();
//Create Permissions Dictionary
COSDictionary permissions = new COSDictionary();
permissions.setItem("DocMDP", signature);
//Add Permissions to Catalog
COSDictionary catalog = doc.getDocumentCatalog().getCOSObject();
catalog.setItem("Perms", permissions);
// Create a reference dictionary
COSDictionary reference = new COSDictionary();
reference.setItem("Type", COSName.getPDFName("SigRef"));
reference.setItem("TransformMethod", COSName.getPDFName("DocMDP"));
reference.setItem("DigestMethod", COSName.getPDFName("SHA1"));
// Now we add DocMDP specific stuff
COSDictionary transformParameters = new COSDictionary();
transformParameters.setItem("Type", COSName.getPDFName("TransformParams"));
transformParameters.setInt("P", 2); //
transformParameters.setItem("V", COSName.getPDFName("1.2"));
// Add everything in order
reference.setItem("TransformParams", transformParameters);
COSArray references = new COSArray();
references.add(reference); // Add SigRef Dictionary to a Array
dictionary.setItem("Reference", references); // Add Array to Signature
// dictionary
// From CreateSignature.java example
// register signature dictionary and sign interface
doc.addSignature(signature, new SignatureInterface() {
@Override
public byte[] sign(InputStream content) throws IOException {
try {
List<Certificate> certList = new ArrayList<Certificate>();
certList.add(certificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
org.bouncycastle.asn1.x509.Certificate cert =
org.bouncycastle.asn1.x509.Certificate
.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
ContentSigner sha1Signer = new
JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
gen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(new
JcaDigestCalculatorProviderBuilder().build())
.build(sha1Signer, new X509CertificateHolder(cert)));
gen.addCertificates(certs);
CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
CMSSignedData signedData = gen.generate(msg, false);
/*
* if (tsaClient != null) { signedData =
* signTimeStamps(signedData); }
*/
return signedData.getEncoded();
} catch (GeneralSecurityException e) {
throw new IOException(e);
} catch (CMSException e) {
throw new IOException(e);
// } catch (TSPException e) {
// throw new IOException(e);
} catch (OperatorCreationException e) {
throw new IOException(e);
}
}
});
//
doc.save(output);
doc.close();
When I open the PDF in Acrobat
[image: Inline image 1]
I compared a PDF certified with a paid library and the one generated with
my code. There is a difference in *contents, *and the *byte ranges* are
wrong.
Left paid library, right the code example
[image: Inline image 2]
The SignatureInterface implementation is the one from CreateSignature.java
example.
Thanks in advance,
Jonathan.
On Wed, Oct 19, 2016 at 11:03 AM, Damien Butaye <[email protected]>
wrote:
> Diego,
>
> One more times, thanks a lot. I just add the following part of your code
> and it works! :
>
>
>
>
>
>
>
>
> * //Create Permissions Dictionary COSDictionary permissions =
> new COSDictionary(); permissions.setItem("DocMDP", signature);
> //Add Permissions to Catalog COSDictionary catalog =
> document.getDocumentCatalog().getCOSObject();
> catalog.setItem("Perms", permissions);*
>
> Many Thanks!
> Damien.
>
> 2016-10-19 15:43 GMT+02:00 Diego Azevedo <[email protected]>:
>
> > Ok, I searched for "DocMDP" on ISO 32000 and found this:
> >
> > * On a 'Signature Field Dictionary', one *could *have a 'Seed Value
> > Dictionary' with a 'MDP entry'
> > o This entry *shall *have a dictionary with only one entry: 'P'
> > and a integer value <0-3>:
> > + 0 - Author Signature
> > + 1-3 - Same meaning from the P entry on the DocMDP Transform
> > Parameters Dictionary
> > * A certification Signature *may *be referenced from the DocMDP entry
> > in the Permissions Dictionary
> > o The signature Dictionary *shall *contain a signature reference
> > dictionary with the DocMDP transform method
> > o It *should *have a Legal Attestation Dictionary
> > o It *shall *be the first signed field in the document
> >
> > There where a few specific things about these entries and dictionaries,
> > but these are the changes that should be made from the beginning:
> >
> > * Create the Signature Reference Dictionary and add it to the
> > signature - OK
> > * Create a Permissions Dictionary and add it to Catalog:
> >
> > //Create Permissions Dictionary
> > COSDictionary permissions = new COSDictionary();
> > permissions.setItem("DocMDP", signature);
> >
> > //Add Permissions to Catalog
> > COSDictionary catalog =
> > document.getDocumentCatalog().getCOSObject();
> > catalog.setItem("Perms", permissions);
> >
> > * Create a Legal Attestation Dictionary and add it to catalog:
> >
> > //Create Legal Attestation Dictionary (I'd totally leave this
> > out on my implementation - Way too much trouble for something
> > optional)
> > COSDictionary legalAttestation= new COSDictionary();
> > <All entries are optional, and are like this:>
> > legalAttestation.setInt("JavaScriptActions", 10);// Means there
> > are 10 Javascript actions
> > legalAttestation.setInt("LaunchActions", 10);// Means there are
> > 10 Launch actions
> > [...]
> >
> > //Add Permissions to Catalog
> > COSDictionary catalog =
> > document.getDocumentCatalog().getCOSObject();
> > catalog.setItem("Legal", legalAttestation);
> >
> > * Create a Seed Value Dictionary and add it to the Signature Field
> > Dictionary
> > o The Signature Field Dictionary is manipulated by pdfbox itself
> > on document.addSignature. So, if necessary, it would be
> > something like this that would be changed in the source code:
> >
> > //Get the references
> > COSArray references = (COSArray)
> > signature.getCOSObject().getItem("Reference");
> > COSDictionary reference = null;
> > if( references != null){
> >
> > // loop all references, looking for a DocMDP TransformMethod
> > for(int i = 0; i< references.size(); i++){
> >
> > reference = (COSDictionary) references.getObject(i);
> > if(reference.getNameAsString("
> TransformMethod").equals("Doc
> > MDP")){
> >
> > // if it is a DocMDP, it shall heve TransformParams
> > as a integer
> > COSDictionary transform = (COSDictionary)
> > reference.getItem("TransformParams");
> > int pEntry = transform.getInt("P");
> >
> > //Add to the SeedValue Dictionary
> > PDSeedValue seedValue = ?; //How to get the
> > SeedValue? Should we create a new one? - Only
> > someone from the project could tell you that (along
> > with where this code should be placed)
> > PDSeedValueMDP mdp = new PDSeedValueMDP();
> > mdp.setP(pEntry);
> > seedValue.setMPD(mdp);
> >
> > }
> >
> > }
> >
> > }
> >
> > I only saw your reply now. The document you sent me only did the first
> > change (permissions Dictionary). Try it and tell me if it worked
> >
> > []'s
> >
> > Diego Azevedo
> >
> >
> > On 19/10/2016 09:25, Diego Azevedo wrote:
> >
> >> Damien,
> >>
> >> Can you upload a correctly certified PDF somewhere and share the link?
> >> Wîth the original one, if possible?
> >>
> >> I'll try to mimic the behavior.
> >>
> >> []'s
> >>
> >> Diego Azevedo
> >>
> >> On 19/10/2016 07:10, Damien Butaye wrote:
> >>
> >>> In some Java code of different PDF Signatue framework, I saw the use of
> >>> the
> >>> "Perms" dictionnary to certify PDF. Do you have any idea if the "Perms"
> >>> can
> >>> help to see the blue ribbon?
> >>>
> >>> 2016-10-19 10:48 GMT+02:00 Damien Butaye <[email protected]>:
> >>>
> >>> Yes but in my case my certificate has the authorization to certify
> >>>> document (the cross is green beside the "Certify Document" in your
> >>>> previous
> >>>> printscreen).
> >>>> I wonder me if another information must be present in the PDF to show
> >>>> the
> >>>> blue ribbon?!
> >>>>
> >>>> 2016-10-18 17:40 GMT+02:00 Diego Azevedo <[email protected]>:
> >>>>
> >>>> No, but in my case it would never happen, because my certificate is
> >>>>> trusted for signing, but not certifying:
> >>>>>
> >>>>> Image: http://imgur.com/XYZCB8H
> >>>>>
> >>>>> []'s
> >>>>>
> >>>>> Diego Azevedo
> >>>>>
> >>>>> On 18/10/2016 13:30, Damien Butaye wrote:
> >>>>>
> >>>>> One last question, have you got the "blue ribbon" on the top the pdf
> >>>>>> when you open it with Acrobat? In my case not, although it is well
> >>>>>> certified as shown in the Acrobat Signature Panel.
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>> 2016-10-18 15:58 GMT+02:00 Damien Butaye <[email protected]
> >>>>>> <mailto:[email protected]>>:
> >>>>>>
> >>>>>> Nice! Thank you very much!
> >>>>>>
> >>>>>> (Btw, it could be nice to integrate in a future release a
> method
> >>>>>> certify() in the PDSignature object).
> >>>>>>
> >>>>>> obrigado!
> >>>>>>
> >>>>>> 2016-10-18 15:42 GMT+02:00 Diego Azevedo <[email protected]
> >>>>>> <mailto:[email protected]>>:
> >>>>>>
> >>>>>> Hello Damien,
> >>>>>>
> >>>>>> I made a typo:
> >>>>>>
> >>>>>> dictionary.setItem("Reference", reference_*s*_); //
> Add
> >>>>>> Array to Signature dictionary
> >>>>>>
> >>>>>> There is no point in creating the array, add the "SigRef"
> >>>>>> dictionary to it... and not use the array on the "Sig"
> >>>>>> dictionary. So... just add the 'S' to the variable and
> >>>>>> re-run
> >>>>>> it. Just tested here, and it worked fine =)
> >>>>>>
> >>>>>> []'s
> >>>>>>
> >>>>>>
> >>>>>> -- *_______________________________________________
> >>>>>>
> >>>>>> Diego Azevedo
> >>>>>> Developer
> >>>>>> E-SEC Segurança Digital
> >>>>>> www.esec.com.br <http://www.esec.com.br>
> >>>>>> +55 61 3323-4410 <tel:%2B55%2061%203323-4410>*
> >>>>>>
> >>>>>>
> >>>>>> On 18/10/2016 10:21, Damien Butaye wrote:
> >>>>>>
> >>>>>> Hello Diego,
> >>>>>>>
> >>>>>>> Thank you for your help. I just tried your code but it
> >>>>>>> seems
> >>>>>>> that it doesn't work. The result has nor signature nor
> >>>>>>> certify element. I'll try again.
> >>>>>>> If you have any idea, don't hesitate ;)
> >>>>>>>
> >>>>>>> Damien.
> >>>>>>>
> >>>>>>> 2016-10-18 13:04 GMT+02:00 Diego Azevedo
> >>>>>>> <[email protected] <mailto:[email protected]>>:
> >>>>>>>
> >>>>>>>
> >>>>>>> From what I'm reading on ISO 32000, the certification
> >>>>>>> Signature is a normal signature, but with a DocMDP
> >>>>>>> transform method. So the ou should do something like
> >>>>>>> this:
> >>>>>>>
> >>>>>>> PDSignature signature = new PDSignature;
> >>>>>>> [..] //do your thing
> >>>>>>> COSDictinary dictionary =
> signature.getCOSObject();
> >>>>>>>
> >>>>>>> //Create a reference dictionary
> >>>>>>> COSDictionary reference = new COSDictionary();
> >>>>>>> reference.setItem("Type",
> >>>>>>> COSName.getPDFName("SigRef"));
> >>>>>>> reference.setItem("TransformMethod",
> >>>>>>> COSName.getPDFName("DocMDP"));
> >>>>>>> reference.setItem("DigestMethod",
> >>>>>>> COSName.getPDFName("SHA1")); //Only MD5 or SHA1...
> >>>>>>> Go
> >>>>>>> with the least worse
> >>>>>>>
> >>>>>>> //Now we add DocMDP specific stuff
> >>>>>>> COSDictionary transformParameters = new
> >>>>>>> COSDictionary();
> >>>>>>> transformParameters.setItem("Type",
> >>>>>>> COSName.getPDFName("TransformParams"));
> >>>>>>> transformParameters.setInteger("P", <1, 2 or 3>);
> >>>>>>> //
> >>>>>>> 1- no changes permited; 2- fill forms and signing;
> >>>>>>> 3-
> >>>>>>> Same as 2 plus annotation creation, deletion an
> >>>>>>> modification.
> >>>>>>> transformParameters.setItem("V",
> >>>>>>> COSName.getPDFName("1.2")); // This is right,
> it's a
> >>>>>>> name, not a number.
> >>>>>>>
> >>>>>>> // Add everything in order
> >>>>>>> reference.setItem("TransformParams",
> >>>>>>> transformParameters ); // Add DocMDP stuff to the
> >>>>>>> SigRef Dictionary;
> >>>>>>> COSArray references = new COSArray();
> >>>>>>> references.add(reference); // Add SigRef
> Dictionary
> >>>>>>> to a Array
> >>>>>>> dictionary.setItem("Reference", reference); //
> Add
> >>>>>>> Array to Signature dictionary
> >>>>>>>
> >>>>>>> I didn't try it myself, just wrote based on PdfBox API
> >>>>>>> and ISO specification. May have errors.
> >>>>>>>
> >>>>>>> On 18/10/2016 06:12, Damien Butaye wrote:
> >>>>>>>
> >>>>>>> Hello Tilman,
> >>>>>>>>
> >>>>>>>> Here follows two links explaining the difference :
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> 1.http://www.investintech.com/
> >>>>>>>> resources/articles/certifyingsigningpdf/
> >>>>>>>> <http://www.investintech.com/r
> >>>>>>>> esources/articles/certifyingsigningpdf/>
> >>>>>>>> 2.
> >>>>>>>> http://stackoverflow.com/quest
> >>>>>>>> ions/16710439/how-to-add-blank-page-in-digitally-signed-pdf-
> >>>>>>>> using-java/16711745#16711745
> >>>>>>>> <http://stackoverflow.com/ques
> >>>>>>>> tions/16710439/how-to-add-blank-page-in-digitally-signed-pdf
> >>>>>>>> -using-java/16711745#16711745>Damien.
> >>>>>>>> 2016-10-18 8:49 GMT+02:00 Tilman Hausherr
> >>>>>>>> <[email protected]> <mailto:
> [email protected]>
> >>>>>>>> :
> >>>>>>>>
> >>>>>>>> Dear all,
> >>>>>>>>>
> >>>>>>>>> I'm looking for a solution to certify a PDF.
> >>>>>>>>>> Currently I'm able to
> >>>>>>>>>> sign a
> >>>>>>>>>> PDF using PDFBox but I can't certify it. Is-it
> >>>>>>>>>> possible
> >>>>>>>>>> to do it with
> >>>>>>>>>> PDFBox?
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>> Thank you for your help!
> >>>>>>>>>>
> >>>>>>>>>> What's the difference? (See my other answer from
> >>>>>>>>>> today)
> >>>>>>>>>>
> >>>>>>>>> Tilman
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> ------------------------------
> >>>>>>>>> ---------------------------------------
> >>>>>>>>> To unsubscribe, e-mail:users-unsubscribe@pdfbo
> >>>>>>>>> x.apache.org
> >>>>>>>>> <mailto:[email protected]>
> >>>>>>>>> For additional commands,
> >>>>>>>>> e-mail:[email protected]
> >>>>>>>>> e.org
> >>>>>>>>> <mailto:[email protected]>
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>>
> >>
>