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/Problem-with-transforming-PDF-from-XADES-signed-XML-file-info-%22normal%22-signed-PDF-tp25167508p25167508.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/
