aboutsummaryrefslogtreecommitdiff
path: root/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java
diff options
context:
space:
mode:
Diffstat (limited to 'pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java')
-rw-r--r--pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java215
1 files changed, 123 insertions, 92 deletions
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.
- *
+ *
* <p>
* These functions are used to replace parts of the original Egiz plain text
* signature mechanism.
* </p>
- *
+ *
* @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.
- *
+ *
* <p>
* Used to locate and identify the Egiz Dictionary in the document.
* </p>
@@ -195,7 +217,7 @@ public abstract class BinarySignature
/**
* The PDFName of the Original Document Size (ODS) field in an Egiz
* Dictionary.
- *
+ *
* <p>
* The ODS must be a positive integral number.
* </p>
@@ -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.
- *
+ *
* <p>
* 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.
- *
+ *
* <p>
* The signature text is the text of the Signature XObject.
* </p>
- *
+ *
* @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.
- *
+ *
* <p>
* 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.
* </p>
- *
+ *
* @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.
- *
+ *
* <p>
* 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.
* </p>
- *
+ *
* @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.
- *
+ *
* <p>
* This replaces the "dummy numbers" in the egiz dictionary with the correct
* values.
* </p>
- *
+ *
* @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.
* </p>
- *
+ *
* @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.
- *
+ *
* <p>
* This method collects all variable String fields in a content stream and
* orders them according to their start offset.
* </p>
- *
+ *
* @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