pdfbox-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stefan Santesson <ste...@aaa-sec.com>
Subject Re: Request to control random seed for signing PDF
Date Thu, 23 May 2013 12:57:27 GMT
Hi again,

I did not receive any reactions on this. Perhaps it was not explained
enough, or was of not interest.
Just checking. I would be grateful for a reply of any kind.

Stefan Santesson

3xA Security AB
Scheelev├Ągen 17, 223 70, Lund
http://AAA-sec.com
stefan@aaa-sec.com
+46-767 861337




On 5/17/13 1:20 AM, "Stefan Santesson" <stefan@aaa-sec.com> wrote:

>Hi,
>
>I have developed a prototype server based signing service for the Swedish
>National eID infrastructure.
>I'll skip the details, but I recently switched to PDFBox for the PDF
>signing
>process and it works great. However, I had to modify the COSWriter class
>to
>get this working.
>
>I'm writing to check whether you would consider adding the functionality I
>need to future version of PDFBox.
>
>The problem is the the signature service is just producing the signature,
>it
>is not trusted to handle the PDF document.
>The government service having the PDF document signed is using PDFBox in
>a 2
>step process.
>
>1) To produce the SignedAttributes DER Object of the CMS signature to be
>created. This is the part that is hashed and signed by the signature
>service.
>
>2) After receiving the signature and signature certs from the signature
>service, completing the PDF signature by delivering the complete PKCS#7
>object to PDFBox.
>
>There are probably a more pure way to handle this, but Since PDFBox allows
>me to create a signature interface that produces the SignedData. I found
>it
>to be the easiest way to run the signature process 2 times.
>1st pass using dummy key and dummy certs. This only to obtain the
>SignedAttributes.
>2nd pass by delivering a SignedData object that include the Signature
>value
>and certs produced by the signature service.
>
>Now in order to do this, I have to control the random seed added by the
>COSWriter, or else the signature created by the signature service will not
>match the hash in the SignedAttributes produced in the second pass.
>
>My modification is provided below.
>I simply provided an extra input parameter to the write function where I
>can
>provide the long seed
>
>I then added a backwards compatible write function where the long seed is
>current time.
>
>By providing the same seed to pass 1 and pass 2, I can get the externally
>created signature to match the SignedAttributes produced in the first
>pass.
>Modifications/additions are highlighted in bold.
>
>/Stefan Sanesson
>
>    /**
>     * This will write the pdf document.
>     *
>     * @param doc The document to write.
>     *
>     * @throws COSVisitorException If an error occurs while generating the
>data.
>     */
>    public void write(PDDocument doc) throws COSVisitorException {
>        write(doc, System.currentTimeMillis());
>    }
>
>    /**
>     * This will write the pdf document.
>     *
>     * @param doc The document to write.
>     * @param idTime The time seed used to generate the id
>     *
>     * @throws COSVisitorException If an error occurs while generating the
>data.
>     */
>    public void write(PDDocument doc, long idTime) throws
>COSVisitorException {
>        document = doc;
>        if (incrementalUpdate) {
>            prepareIncrement(doc);
>        }
>
>        // if the document says we should remove encryption, then we
>shouldn't encrypt
>        if (doc.isAllSecurityToBeRemoved()) {
>            this.willEncrypt = false;
>            // also need to get rid of the "Encrypt" in the trailer so
>readers 
>            // don't try to decrypt a document which is not encrypted
>            COSDocument cosDoc = doc.getDocument();
>            COSDictionary trailer = cosDoc.getTrailer();
>            trailer.removeItem(COSName.ENCRYPT);
>        } else {
>            SecurityHandler securityHandler =
>document.getSecurityHandler();
>            if (securityHandler != null) {
>                try {
>                  
>securityHandler.prepareDocumentForEncryption(document);
>                    this.willEncrypt = true;
>                } catch (IOException e) {
>                    throw new COSVisitorException(e);
>                } catch (CryptographyException e) {
>                    throw new COSVisitorException(e);
>                }
>            } else {
>                this.willEncrypt = false;
>            }
>        }
>
>        COSDocument cosDoc = document.getDocument();
>        COSDictionary trailer = cosDoc.getTrailer();
>        COSArray idArray = (COSArray)
>trailer.getDictionaryObject(COSName.ID);
>        if (idArray == null || incrementalUpdate) {
>            try {
>
>                //algorithm says to use time/path/size/values in doc to
>generate
>                //the id.  We don't have path or size, so do the best we
>can
>                MessageDigest md = MessageDigest.getInstance("MD5");
>                md.update(Long.toString(idTime).getBytes("ISO-8859-1"));
>                COSDictionary info = (COSDictionary)
>trailer.getDictionaryObject(COSName.INFO);
>                if (info != null) {
>                    Iterator<COSBase> values =
>info.getValues().iterator();
>                    while (values.hasNext()) {
>                  
>md.update(values.next().toString().getBytes("ISO-8859-1"));
>                    }
>                }
>                idArray = new COSArray();
>                COSString id = new COSString(md.digest());
>                idArray.add(id);
>                idArray.add(id);
>                trailer.setItem(COSName.ID, idArray);
>            } catch (NoSuchAlgorithmException e) {
>                throw new COSVisitorException(e);
>            } catch (UnsupportedEncodingException e) {
>                throw new COSVisitorException(e);
>            }
>        }
>        cosDoc.accept(this);
>    }
>
>



Mime
View raw message