From db52e4d66d60184d53a27ba4d6772461daacc03d Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 22 Mar 2013 08:57:51 +0000 Subject: Maintenance update (bugfixes, new features, cleanup...) Refer to /dok/RELEASE_NOTES-3.3.txt for further information. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/pdf-as/trunk@931 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../wag/egov/egiz/pdf/BinarySignature.java | 215 ++++++++++++--------- 1 file changed, 123 insertions(+), 92 deletions(-) (limited to 'pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java') diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java index ece9525..75a64f1 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java @@ -40,6 +40,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -89,25 +90,46 @@ import com.lowagie.text.pdf.PdfStamper; import com.lowagie.text.pdf.PdfStamperImp; import com.lowagie.text.pdf.PdfString; import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; /** * Contains various extension functions to digitally sign documents. - * + * *

* These functions are used to replace parts of the original Egiz plain text * signature mechanism. *

- * + * * @author wprinz */ public abstract class BinarySignature { //23.11.2010 changed by exthex - added replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) method - + protected static Log logger = LogFactory.getLog(BinarySignature.class); + + /** + * The resource path of the srgb profile to be embedded in case of PDF/A-1b. + */ + private static final String srgbProfileResource = "/at/gv/egiz/pdfas/itext/srgb.profile"; + + /** + * The color profile to be embedded in case of PDF/A-1b. + */ + private static final byte[] SRGB_PROFILE; + + static { + try { + logger.debug("Preloading srgb color profile '" + srgbProfileResource + "."); + SRGB_PROFILE = IOUtils.toByteArray(BinarySignature.class.getResourceAsStream(srgbProfileResource)); + } catch (IOException e) { + throw new RuntimeException("Unable to preload srgb color profile.", e); + } + } + /** * The tolerance area of the line break algorithm. - * + * * @see Placeholder#replacePlaceholderWithTolerance(byte[], List, byte[], int) */ public static final int LINE_BREAK_TOLERANCE = 10; @@ -116,11 +138,11 @@ public abstract class BinarySignature * The number of bytes left out for the certificate placeholder. */ public static final int CERTIFICATE_PLACEHOLDER_LENGTH = 10000; - + /** * The number of bytes left out for the timestamp placeholder. */ - public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; + public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; /** * The placeholder character used to fill out Strings in the layout process. @@ -162,11 +184,11 @@ public abstract class BinarySignature * The SIG_ID brev. */ public static final byte[] BREV_SID = { 's', 'i', 'd' }; - + /** * The SIG_ALG brev. */ - public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; + public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; /** * No explicit encoding. @@ -185,7 +207,7 @@ public abstract class BinarySignature /** * The PDFName of the Egiz Dictionary. - * + * *

* Used to locate and identify the Egiz Dictionary in the document. *

@@ -195,7 +217,7 @@ public abstract class BinarySignature /** * The PDFName of the Original Document Size (ODS) field in an Egiz * Dictionary. - * + * *

* The ODS must be a positive integral number. *

@@ -226,7 +248,7 @@ public abstract class BinarySignature * The PdfName of the certificate array. */ public static final PdfName EGIZ_CERTIFICATE_NAME = new PdfName("Cert"); - + /** * The PdfName of the Timestamp */ @@ -239,7 +261,7 @@ public abstract class BinarySignature /** * The PDFName of the Signature XObject field in an Egiz Dictionary. - * + * *

* This must be an indirect reference to the XObject containing the Signature * table. @@ -251,17 +273,17 @@ public abstract class BinarySignature * The number placeholder that is used to give numbers a fixed length. */ protected static final PdfNumber NUMBER_PLACEHOLDER = new PdfNumber(999999999); - + /** * Extracts the signature text only. - * + * *

* The signature text is the text of the Signature XObject. *

- * + * * @param egiz_dict * The Egiz Dictionary. - * + * * @return Returns the signature text. */ public static String extractSignatureTextOnly(PdfDictionary egiz_dict) throws IOException @@ -276,7 +298,7 @@ public abstract class BinarySignature /** * Retrieves the size of the original document from the Egiz Dictionary. - * + * * @param egiz_dict * The Egiz Dictionary. * @return Returns the size (in bytes) of the original document. @@ -292,7 +314,7 @@ public abstract class BinarySignature /** * Retrieves the previous Egiz dictionary from the given one, if a previous * dictionary exists. - * + * * @param egiz_dict * The Egiz Dictionary. * @return Returns the previous Egiz Dictionary, or null if there is none. @@ -306,7 +328,7 @@ public abstract class BinarySignature /** * Retrieves the Egiz Dictionary from the document if present. - * + * * @param reader * The reader to retrieve the dictionary from. * @return Returns the Egiz Dictionary, if present, or returns null, if no @@ -327,7 +349,7 @@ public abstract class BinarySignature /** * Retrieves the Egiz Dictionary's indirect reference from the reader. - * + * * @param reader * The reader. * @return Returns the indirect reference of the Egiz Dictionary, or null, if @@ -342,14 +364,14 @@ public abstract class BinarySignature /** * Retrieves the chain of Egiz Dictionaries from the reader. - * + * *

* The first element in the List will be the top most (oldest) Egiz * Dictionary. The last element in the List will be the bottom most (latest) * Egiz Dictionary. If the list is empty, no dictionary could be found at all, * which means that the document is not digitally signed. *

- * + * * @param reader * The reader. * @return Returns the List of PdfDictionaries from the document. @@ -374,7 +396,7 @@ public abstract class BinarySignature /** * Builds a digest of the given data. - * + * * @param data * The data to be digested. * @param length @@ -393,7 +415,6 @@ public abstract class BinarySignature } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); throw new PDFDocumentException(202, "Digest algorithm not supported - NoSuchAlgorithmException", e); } @@ -406,7 +427,7 @@ public abstract class BinarySignature /** * Retrieves the signable text from the given document. - * + * * @param data * The data. * @param ods @@ -423,7 +444,7 @@ public abstract class BinarySignature /** * Fills the holes in the byte ranges with the SIGN_PLACEHOLDER. - * + * * @param data * The given byte ranged data. * @param byte_ranges @@ -697,7 +718,7 @@ public abstract class BinarySignature // throw new PresentableException(e); // } // } - + protected static int getLineBreakTolerance(IncrementalUpdateInformation iui) throws PDFDocumentException { SettingsReader settings; @@ -717,7 +738,7 @@ public abstract class BinarySignature } return lineBreakTolerance; } - + protected static int getCertificatePlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException { SettingsReader settings; @@ -737,7 +758,7 @@ public abstract class BinarySignature } return certLen; } - + protected static int getTimestampPlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException { SettingsReader settings; @@ -761,7 +782,7 @@ public abstract class BinarySignature /** * Signs a document with the given signature table using the Incremental * Update method. - * + * *

* The table containing the signature text will be appended. As specified by * the parameters, the signature will be appended to the last page, or a plain @@ -777,7 +798,7 @@ public abstract class BinarySignature * information about the signature. Basically the size of the original * document and the reference of the signature table. *

- * + * * @param original_document * The original document. * @param pdf_table @@ -811,10 +832,7 @@ public abstract class BinarySignature // System.out.println("wprinz: STAMPING PDF"); // InputStream is = original_document.createInputStream(); - byte[] pdf_data = original_document.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - // is.close(); + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(original_document); OutputStream baos = written_pdf.createOutputStream("application/pdf"); // ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -823,7 +841,7 @@ public abstract class BinarySignature // incremental updated // The stamper allows this by setting append = true boolean adobeSigField = AdobeSignatureHelper.isAdobeSignatureFieldEnabled(so.getSignatureTypeDefinition().getType()); - PdfStamper stamper = null; + PdfStamper stamper = null; if (adobeSigField) { stamper = PdfStamper.createSignature(reader, baos, '\0', null, true); } else { @@ -843,13 +861,13 @@ public abstract class BinarySignature { throw new PDFDocumentException(224, "The provided page (=" + pi.getPage() + ") is out of range."); } - + if (SignaturePlaceholderContext.isSignaturePlaceholderDataSet() && SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName() != null) { replacePlaceholder(stamper, pi.getPage(), SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName()); } - + PdfContentByte content = stamper.getOverContent(pi.getPage()); // content = StampContent einer PageStamp. @@ -857,12 +875,12 @@ public abstract class BinarySignature // table_height = " + pdf_table.getTotalHeight()); PdfTemplate table_template = content.createTemplate(pdf_table.getTotalWidth(), pdf_table.getTotalHeight()); - table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig + table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig // exthex StructContentHelper structHelper = new StructContentHelper(stamper, content, pi.getPage()); structHelper.prepareStructData(table_template); - + pdf_table.writeSelectedRows(0, -1, 0, pdf_table.getTotalHeight(), table_template); // table_template.moveTo(0, 0); @@ -876,13 +894,13 @@ public abstract class BinarySignature // pdf_table.writeSelectedRows(0, -1, SIGNATURE_BORDER / 2, // table_position, content); - + structHelper.beginSigBlockContent(); - + content.addTemplate(table_template, pi.getX(), pi.getY() - pdf_table.getTotalHeight()); - - structHelper.endSigBlockContent(); - + + structHelper.endSigBlockContent(); + ActualTablePos atp = new ActualTablePos(); atp.page = pi.getPage(); @@ -891,13 +909,13 @@ public abstract class BinarySignature atp.width = pdf_table.getTotalWidth(); atp.height = pdf_table.getTotalHeight(); iui.actualTablePos = atp; - + structHelper.buildFigureStructData(so, table_template); structHelper.buildSigBlockStructData(); structHelper.finishMainStructData(); - + structHelper.buildVerifyLinkStructData(table_template, atp); - + // For debugging print a 100x100 grid // { // Rectangle psize = reader.getPageSizeWithRotation(pos.page); @@ -940,7 +958,22 @@ public abstract class BinarySignature // PdfObject value = resources.get(key); // System.out.println(" " + key + " = " + value); // } - + + // added by dti: fixing PDF/A-1b + if (PDFASUtils.isPdfAEnabled(profile)) { + logger.debug("Adding sRGB IEC61966-2.1 color profile (output intent) in order to satisfy PDF/A-1b requirements."); + PdfWriter writer = stamper.getWriter(); + writer.setOutputIntents("Custom", "sRGB", "", "sRGB IEC61966-2.1", SRGB_PROFILE); + PdfArray a = writer.getExtraCatalog().getAsArray(PdfName.OUTPUTINTENTS); + if (a != null) { + PdfDictionary d = a.getAsDict(0); + if (d != null) { + // overwrite PDF/X entry with PDF/A entry + d.put(PdfName.S, PdfName.GTS_PDFA1); + } + } + } + // add the EGIZ dict: if (variable_field_definitions != null) { @@ -964,22 +997,20 @@ public abstract class BinarySignature } catch (IOException e) { - e.printStackTrace(); throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); } catch (DocumentException e) { - e.printStackTrace(); throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); } } - + private static void replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) throws BadElementException, MalformedURLException, IOException, BadPdfFormatException, PresentableException { Image img = Image.getInstance(SignaturePlaceholderData.class.getResource("empty.jpg")); PdfImage pImg = new PdfImage(img, "Imwurscht", null); PdfStamperImp stamperImp = (PdfStamperImp)stamper.getWriter(); PdfIndirectObject ind = stamperImp.addToBody(pImg); - + PdfDictionary resources = stamper.getReader().getPageN(pageNr).getAsDict(PdfName.RESOURCES); if (ind != null && resources != null) { @@ -999,11 +1030,11 @@ public abstract class BinarySignature throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, new NullPointerException("Resource dictionary not found in document structure!")); } } - + /** * Creates the EGIZ Dictionary and adds it to the document. - * + * * @param stamper * The PdfStamper. * @param table_template @@ -1092,11 +1123,11 @@ public abstract class BinarySignature // /encodings replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the // /Cert - + if (iui.timeStamper != null) { encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the /Timestamp replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the /timestamp - + } // hidden replaces @@ -1153,9 +1184,9 @@ public abstract class BinarySignature } PdfString cert_placeholder = new PdfString(cert_bytes); cert_array.add(cert_placeholder); - egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); - - // Timestamp + egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); + + // Timestamp if (iui.timeStamper != null) { // only if handler is available PdfArray timestamp_array = new PdfArray(); @@ -1167,10 +1198,10 @@ public abstract class BinarySignature } PdfString timestamp_placeholder = new PdfString(timestamp_bytes); timestamp_array.add(timestamp_placeholder); - egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); + egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); } - + // /Data array with hidden information if (has_hidden_variable_fields || invisibleKZString != null) { @@ -1221,7 +1252,7 @@ public abstract class BinarySignature /** * Converts a field name (type) to the corresponding BREV. - * + * * @param type * The field name (type). * @return Returns the corresponding BREV, or BREV_NIL if the type is not @@ -1261,12 +1292,12 @@ public abstract class BinarySignature /** * Updates the information in the egiz dictionary to reflect the real offsets * of the byte ranges. - * + * *

* This replaces the "dummy numbers" in the egiz dictionary with the correct * values. *

- * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1309,7 +1340,7 @@ public abstract class BinarySignature byte[] cert_bytes = cert_str.getBytes("US-ASCII"); int cert_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, cert_bytes); int cert_start = cert_index + cert_bytes.length; - + //Timestamp int timestamp_index = 0; int timestamp_start = 0; @@ -1325,14 +1356,14 @@ public abstract class BinarySignature int cur_pos = array_start; int cur_br_start = 0; - + // write the /encodings byte range { int num_replaces = calcNumReps(iui.replaces); - int num_holes = num_replaces + 1 + 1; + int num_holes = num_replaces + 1 + 1; // +1 = the /encodings hole - // +1 = the /Cert + // +1 = the /Cert // +1 = the /Timestamp if (iui.timeStamper != null) { num_holes += 1; @@ -1376,7 +1407,7 @@ public abstract class BinarySignature iui.cert_start = cert_start; } - + // write the /Timestamp byte range if (iui.timeStamper != null) { StringInfo byte_range = new StringInfo(); @@ -1394,7 +1425,7 @@ public abstract class BinarySignature cur_br_start = timestamp_start + iui.timestamp_length; iui.timestamp_start = timestamp_start; - } + } // determine the /Data byte ranges if any List ifd = iui.invisible_field_definitions; @@ -1411,7 +1442,7 @@ public abstract class BinarySignature { StringInfo si = (StringInfo) iui.kz_list.get(0); si.string_start = hole_start; - + hole_start += si.string_length + 2; } @@ -1468,7 +1499,7 @@ public abstract class BinarySignature cur_pos += num_digits; cur_pos += 1; - + // update the Kennzeichnung byte ranges cur_pos = kz_start; for (int i = 0; i < iui.kz_list.size(); i++) @@ -1494,7 +1525,7 @@ public abstract class BinarySignature /** * Replaces the certificate placeholder with the certificate from the signed * Signature Object. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1550,7 +1581,7 @@ public abstract class BinarySignature /** * Replaces the timestam placeholder with the timestamp from the signed * Signature Object. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1558,27 +1589,27 @@ public abstract class BinarySignature public static void replaceTimestamp(IncrementalUpdateInformation iui) throws PDFDocumentException { String timestamp = iui.signed_signature_object.getSigTimeStamp(); - if (timestamp != null) { + if (timestamp != null) { byte[] escaped = Placeholder.escapePDFString(timestamp.getBytes()); if (escaped.length > iui.timestamp_length) { throw new PlaceholderException("timestamp", escaped.length - iui.timestamp_length); } - System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); + System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); } } - + /** * Replaces the placeholders with values from the signed SignatureObject. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException */ public static void replacePlaceholders(IncrementalUpdateInformation iui) throws PDFDocumentException { - final int lineBreakTolerance = getLineBreakTolerance(iui); - + final int lineBreakTolerance = getLineBreakTolerance(iui); + final byte[] signed_pdf = iui.signed_pdf; // int num_replaces = calcNumReps(iui.replaces); @@ -1661,7 +1692,7 @@ public abstract class BinarySignature * carried out. Accordingly to this number, entries in the dictionary are * created. *

- * + * * @param replaces * The ReplaceInfo list. * @return Returns the number of string replaces. @@ -1681,12 +1712,12 @@ public abstract class BinarySignature /** * Determines the List of ReplaceInfo objects of replaces in the content * stream regarding the given field definitions. - * + * *

* This method collects all variable String fields in a content stream and * orders them according to their start offset. *

- * + * * @param pdf * The PDF. * @param begin @@ -1760,7 +1791,7 @@ public abstract class BinarySignature /** * Determines the Kennzeichnug in the content stream. - * + * * @param pdf * The PDF. * @param begin @@ -1819,7 +1850,7 @@ public abstract class BinarySignature /** * Finds the index of the StringInfo within the StringInfo list that has the * given content (caption). - * + * * @param strings * The list of StringInfos. * @param caption @@ -1886,7 +1917,7 @@ public abstract class BinarySignature /** * Tells, if the given StringInfo contains only placeholder characters. - * + * * @param si * The StringInfo. * @param placeholder @@ -1935,7 +1966,7 @@ public abstract class BinarySignature /** * Finds the first string after and at the given index not being a placeholder * string. - * + * * @param strings * The list of StringInfos. * @param start @@ -1958,7 +1989,7 @@ public abstract class BinarySignature /** * Restores the given String to its placeholder. - * + * * @param pdf * The PDF. * @param si @@ -1978,7 +2009,7 @@ public abstract class BinarySignature /** * Reconstructs the replaces from the PDF and forms suitable value strings. - * + * * @param pdf * The PDF. * @param brevs @@ -2044,7 +2075,7 @@ public abstract class BinarySignature /** * Reads an unsigned integer number. - * + * * @param pdf * The PDF. * @param start_index @@ -2073,7 +2104,7 @@ public abstract class BinarySignature /** * Replaces a number by the new value. - * + * * @param pdf * The PDF. * @param start_index -- cgit v1.2.3