Hello everybody,
I've been working for a few days on some PDF-signing problem, and analyzing
the forum and examples didn't give me any answer. So, I'll be appreciated
for any help...

The subject is:
I have to "translate" XML-XADES electronicaly signed PDF into "normal" PDF
with the signature information, normaly viewable by Acrobat Reader.

The problem is:
Reader always "shouts" that signature is invalid, 'cause PDF was modified.
Certificate information about signer, etc. is OK
Please take a look at my code,  if You see something strange or wrong...

1. Source XML with electronicaly-signed PDF  looks like:

<ds:Signature Id="Signature-0">
  <ds:SignedInfo Id="SignedInfo-0">
  <ds:CanonicalizationMethod
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
  <ds:SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
  <ds:Reference Id="SignedProperties-Reference0"
Type="http://uri.etsi.org/01903#SignedProperties"; URI="#SignedProperties-0">
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <ds:DigestValue><!-- CUT --></ds:DigestValue>
  </ds:Reference>
  <ds:Reference URI="#Dokument-0">
    <ds:Transforms>
      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#base64"/>
    </ds:Transforms>
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    <ds:DigestValue>
      <!-- CUT -->
    </ds:DigestValue>
  </ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue Id="SignatureValue-0">
<!--CUT -->
</ds:SignatureValue>
<ds:KeyInfo Id="KeyInfo-0">
  <ds:X509Data>
  <ds:X509Certificate>
  <!-- CUT -->
  </ds:X509Certificate>
  </ds:X509Data>
</ds:KeyInfo>
<ds:Object>
  <xades:QualifyingProperties Target="#Signature-0">
    <xades:SignedProperties Id="SignedProperties-0">
      <xades:SignedSignatureProperties>
        <xades:SigningCertificate>
          <xades:Cert>
            <xades:CertDigest>
              <ds:DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
              <ds:DigestValue> <!-- CUT --> </ds:DigestValue>
            </xades:CertDigest>
            <xades:IssuerSerial>
              <ds:X509IssuerName>
                <!-- CUT -->
              </ds:X509IssuerName>
              <ds:X509SerialNumber><!-- CUT --></ds:X509SerialNumber>
            </xades:IssuerSerial>
          </xades:Cert>
        </xades:SigningCertificate>
      </xades:SignedSignatureProperties>
    </xades:SignedProperties>
  </xades:QualifyingProperties>
</ds:Object>
<ds:Object Id="Dokument-0"
Encoding="http://www.w3.org/2000/09/xmldsig#base64";>

<!-- CUT PDF in MIME -->

</ds:Object>
</ds:Signature>


2. My class for signing PDF is:
/* 
It's just a part of code, but should be enough for checking at first look...
- xml parameter is parsed XML data of XML listed above, it's easy to find
what information is being taken from it.
- PDFFile parameter is a PDF that was written to disk from XML, without any
signature information 
It's Based on Antonino Iacono's code of FirmaPDF and other examples of iText
*/

-- START
package org.opensignature.opensignpdf;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.FileOutputStream;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.HashMap;
import org.apache.commons.codec.binary.Base64;
import org.opensignature.opensignpdf.tools.CertUtil;
import org.opensignature.opensignpdf.tools.IOUtils;
import com.lowagie.bc.asn1.ASN1EncodableVector;
import com.lowagie.bc.asn1.ASN1InputStream;
import com.lowagie.bc.asn1.DERConstructedSet;
import com.lowagie.bc.asn1.DERInteger;
import com.lowagie.bc.asn1.DERNull;
import com.lowagie.bc.asn1.DERObjectIdentifier;
import com.lowagie.bc.asn1.DEROctetString;
import com.lowagie.bc.asn1.DERSequence;
import com.lowagie.bc.asn1.DERSet;
import com.lowagie.bc.asn1.DERTaggedObject;
import com.lowagie.bc.asn1.DERUTCTime;
import com.lowagie.text.DocumentException;
import com.lowagie.text.ExceptionConverter;
import com.lowagie.text.pdf.PdfArray;
import com.lowagie.text.pdf.PdfDate;
import com.lowagie.text.pdf.PdfDictionary;
import com.lowagie.text.pdf.PdfName;
import com.lowagie.text.pdf.PdfNumber;
import com.lowagie.text.pdf.PdfPKCS7;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfSignatureAppearance;
import com.lowagie.text.pdf.PdfSignatureAppearanceOSP;
import com.lowagie.text.pdf.PdfStamperOSP;
import com.lowagie.text.pdf.PdfString;

import com.novo.signpdf.SignedXML;

public class PDFSigner {

        public static void MySignPdf(SignedXML xml, File pdfFile) {

                X509Certificate[] certs = new X509Certificate[1];
                certs[0] = xml.getCertificate();

                PdfReader reader;
                PdfStamperOSP stamper = null;

                try {
                        reader = new PdfReader(pdfFile.getPath());
                        FileOutputStream fout;

                        fout = new 
FileOutputStream(pdfFile.getAbsolutePath().replaceAll(
                                        ".original.pdf", ".signed.pdf"));
                        BufferedOutputStream os = new 
BufferedOutputStream(fout);
                        stamper = PdfStamperOSP.createSignature(reader, os, 
'\0');

                } catch (IOException e) {
                        e.printStackTrace();
                } catch (DocumentException e) {
                        e.printStackTrace();
                }

                PdfSignatureAppearanceOSP sap = 
stamper.getSignatureAppearance();

                sap.setCrypto(null, certs, null, 
PdfSignatureAppearance.WINCER_SIGNED);
                sap.setReason("Testy NovoSigner");

                sap.setCertified(2);
                
                sap.setExternalDigest(new byte[128], new byte[20], "RSA");

                Calendar cal = Calendar.getInstance();
                cal.setTime(xml.getTimeStamp());

                PdfDictionary dic = new PdfDictionary();
                dic.put(PdfName.FT, PdfName.SIG);
                dic.put(PdfName.FILTER, new PdfName("Adobe.PPKLite"));
                dic.put(PdfName.SUBFILTER, new PdfName("adbe.pkcs7.detached"));
                dic.put(PdfName.M, new PdfDate(cal));
                dic.put(PdfName.NAME, new PdfString(PdfPKCS7.getSubjectFields(
                                (X509Certificate) certs[0]).getField("CN")));

                PdfDictionary transformParams = new PdfDictionary();
                transformParams.put(PdfName.P, new PdfNumber(1));
                transformParams.put(PdfName.V, new PdfName("1.2"));
                transformParams.put(PdfName.TYPE, new 
PdfName("TransformParams"));

                PdfDictionary reference = new PdfDictionary();
                reference.put(new PdfName("TransformMethod"), new 
PdfName("DocMDP"));
                reference.put(PdfName.TYPE, new PdfName("SigRef"));
                reference.put(new PdfName("TransformParams"), transformParams);
                PdfArray types = new PdfArray();
                types.add(reference);
                dic.put(new PdfName("Reference"), types);

                sap.setCryptoDictionary(dic);

                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
                exc.put(PdfName.CONTENTS, new Integer(0x5002));

                try {
                        sap.preClose(exc);
                } catch (IOException e) {
                        e.printStackTrace();
                } catch (DocumentException e) {
                        e.printStackTrace();
                }

                byte[] hash = null;
                hash = Base64.decodeBase64(xml.getDocumentDigest().getBytes());

                ASN1EncodableVector signedAttributes = 
buildSignedAttributes(hash, cal);
                byte[] encodedPkcs7;

                byte[] signatureBytes = Base64.decodeBase64(xml.getSignature()
                                .getBytes());


                System.out.println(signatureBytes.length);

                try {
                        DERConstructedSet digestAlgorithms = new 
DERConstructedSet();
                        ASN1EncodableVector algos = new ASN1EncodableVector();
                        algos.add(new DERObjectIdentifier("1.3.14.3.2.26")); // 
SHA1
                        algos.add(new DERNull());
                        digestAlgorithms.addObject(new DERSequence(algos));
                        ASN1EncodableVector ev = new ASN1EncodableVector();
                        ev.add(new 
DERObjectIdentifier("1.2.840.113549.1.7.1")); //
PKCS7SignedData

                        DERSequence contentinfo = new DERSequence(ev);

                        ASN1EncodableVector v = new ASN1EncodableVector();
                        for (int c = 0; c < certs.length; c++) {
                                ASN1InputStream tempstream = new 
ASN1InputStream(
                                                new 
ByteArrayInputStream(certs[c].getEncoded()));
                                v.add(tempstream.readObject());
                        }

                        DERSet dercertificates = new DERSet(v);

                        ASN1EncodableVector signerinfo = new 
ASN1EncodableVector();

                        signerinfo.add(new DERInteger(1));

                        v = new ASN1EncodableVector();
                        v.add(CertUtil.getIssuer(certs[0]));
                        v.add(new DERInteger(certs[0].getSerialNumber()));
                        signerinfo.add(new DERSequence(v));

                        v = new ASN1EncodableVector();
                        v.add(new DERObjectIdentifier("1.3.14.3.2.26")); // SHA1
                        v.add(new DERNull());
                        signerinfo.add(new DERSequence(v));

                        // add the authenticated attribute if present
                        signerinfo.add(new DERTaggedObject(false, 0, new DERSet(
                                        signedAttributes)));

                        // Add the digestEncryptionAlgorithm
                        v = new ASN1EncodableVector();
                        v.add(new 
DERObjectIdentifier("1.2.840.113549.1.1.1"));// RSA
                        v.add(new DERNull());
                        signerinfo.add(new DERSequence(v));

                        // Add the encrypted digest
                        signerinfo.add(new DEROctetString(signatureBytes));

                        // Finally build the body out of all the components 
above
                        ASN1EncodableVector body = new ASN1EncodableVector();
                        body.add(new DERInteger(1)); // pkcs7 version, always 1
                        body.add(digestAlgorithms);
                        body.add(contentinfo);
                        body.add(new DERTaggedObject(false, 0, 
dercertificates));

                        // Only allow one signerInfo
                        body.add(new DERSet(new DERSequence(signerinfo)));

                        // Now we have the body, wrap it in it's PKCS7Signed 
shell
                        // and return it
                        //
                        ASN1EncodableVector whole = new ASN1EncodableVector();
                        whole.add(new 
DERObjectIdentifier("1.2.840.113549.1.7.2"));//
PKCS7_SIGNED_DATA
                        whole.add(new DERTaggedObject(0, new 
DERSequence(body)));

                        encodedPkcs7 = IOUtils.toByteArray(new 
DERSequence(whole));

                } catch (Exception e) {
                        throw new ExceptionConverter(e);
                }

                PdfDictionary dic2 = new PdfDictionary();

                byte out[] = new byte[0x5000 / 2];
                System.arraycopy(encodedPkcs7, 0, out, 0, encodedPkcs7.length);

                dic2.put(PdfName.CONTENTS, new 
PdfString(out).setHexWriting(true));
                try {
                        sap.close(dic2);
                } catch (IOException e) {
                        e.printStackTrace();
                } catch (DocumentException e) {
                        e.printStackTrace();
                }

        }

        private static ASN1EncodableVector buildSignedAttributes(byte[] hash,
                        Calendar cal) {
                ASN1EncodableVector signedAttributes = new 
ASN1EncodableVector();

                // Content type
                ASN1EncodableVector v = new ASN1EncodableVector();
                v.add(new DERObjectIdentifier("1.2.840.113549.1.9.3"));// 
CONTENT_TYPE
                v.add(new DERSet(new 
DERObjectIdentifier("1.2.840.113549.1.7.1")));//
PKCS7_DATA
                signedAttributes.add(new DERSequence(v));

/*
-- we do not have this ifnformation in XML
                // signing time
                v = new ASN1EncodableVector();
                v.add(new DERObjectIdentifier("1.2.840.113549.1.9.5")); // 
SIGNING_TIME
                v.add(new DERSet(new DERUTCTime(cal.getTime())));
                signedAttributes.add(new DERSequence(v));
*/
                // message digest
                v = new ASN1EncodableVector();
                v.add(new DERObjectIdentifier("1.2.840.113549.1.9.4"));// 
MESSAGE_DIGEST
                v.add(new DERSet(new DEROctetString(hash)));
                signedAttributes.add(new DERSequence(v));

                return signedAttributes;

        }

}

----- END

I'll be very appreciated for any help.
Tomasz Korolczuk


-- 
View this message in context: 
http://www.nabble.com/Electronic-sign-from-xml-xades-into-PDF-problem-tp25167500p25167500.html
Sent from the iText - General mailing list archive at Nabble.com.


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
iText-questions mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/itext-questions

Buy the iText book: http://www.1t3xt.com/docs/book.php
Check the site with examples before you ask questions: 
http://www.1t3xt.info/examples/
You can also search the keywords list: http://1t3xt.info/tutorials/keywords/

Reply via email to