pdfbox-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Damien Butaye <damien.but...@gmail.com>
Subject Re: How to certify a PDF
Date Wed, 19 Oct 2016 21:09:34 GMT
Hello Jonathan,

Try also to use doc.saveIncremental(out) instead of doc.save(out)

Le 19 oct. 2016 23:01, "Diego Azevedo" <dazevedo@esec.com.br> a écrit :

> Hello Jonathan,
>
> After 'dictionary.setItem("Reference", references);' line, add:
>
> //Create Permissions Dictionary
> COSDictionary permissions = new COSDictionary();
> permissions.setItem("DocMDP", signature);
>
> //Add Permissions to Catalog
> COSDictionary catalog = document.getDocumentCatalog().getCOSObject();
> catalog.setItem("Perms", permissions);
>
> It is expected to see a difference in Contents and byteRange using
> different libraries, since they may or may not use references, spaces or
> line breaks the same way.
> []'s
>
> Diego Azevedo
>
> On 19/10/2016 17:09, Jonathan Barbero wrote:
>
> 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 JcaDigestCalculatorProviderBui
> lder().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 <damien.butaye@gmail.com>
> 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 <dazevedo@esec.com.br>:
>>
>> > 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 <damien.butaye@gmail.com>:
>> >>>
>> >>> 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 <dazevedo@esec.com.br>:
>> >>>>
>> >>>> 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 <damien.butaye@gmail.com
>> >>>>>> <mailto:damien.butaye@gmail.com>>:
>> >>>>>>
>> >>>>>>      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 <
>> dazevedo@esec.com.br
>> >>>>>>      <mailto:dazevedo@esec.com.br>>:
>> >>>>>>
>> >>>>>>          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>
>> <%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
>> >>>>>>>          <dazevedo@esec.com.br <mailto:dazevedo@esec.com.br>>:
>> >>>>>>>
>> >>>>>>>
>> >>>>>>>              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
>> >>>>>>>>              <THausherr@t-online.de> <mailto:
>> THausherr@t-online.de>
>> >>>>>>>> :
>> >>>>>>>>
>> >>>>>>>>              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:users-unsubscribe@pdfbox.apache.org>
>> >>>>>>>>>              For additional commands,
>> >>>>>>>>> e-mail:users-help@pdfbox.apach
>> >>>>>>>>> e.org
>> >>>>>>>>> <mailto:users-help@pdfbox.apache.org>
>> >>>>>>>>>
>> >>>>>>>>>
>> >>>>>>>>>
>> >>>>>>>>>
>> >>
>>
>
>
> --
>
>
>
>
>
>
> *_______________________________________________ Diego Azevedo
> Desenvolvedor E-SEC Segurança Digital www.esec.com.br
> <http://www.esec.com.br> 61 3323-4410*
>
>
> Os dados transmitidos, incluindo quaisquer anexos, são destinados apenas
> para a pessoa ou entidade ao qual está endereçada e pode conter material
> confidencial e/ou privilegiado. É proibida qualquer revisão, retransmissão,
> disseminação ou outro uso desta informação, ou a tomada de qualquer ação
> com base na confiança, por pessoas ou empresas que não o destinatário, e
> qualquer responsabilidade daí decorrente é negada. Se você recebeu por
> engano, favor contatar o remetente e apague o material de qualquer
> computador
>
> The information transmitted, including any attachments, is intended only
> for the person or entity to which it is addressed and may contain
> confidential and/or privileged material. Any review, retransmission,
> dissemination or other use of, or taking of any action in reliance upon,
> this information by persons or entities other than the intended recipient
> is prohibited, and all liability arising therefrom is disclaimed. If you
> received this in error, please contact the sender and delete the material
> from any computer
>
>

Mime
  • Unnamed multipart/related (inline, None, 0 bytes)
View raw message