/**
*
* In prepareSign, an Incremental Update is created that contains the Signature * block and the egiz dictionary. For formatting the layout, variable values are * filled with placeholders. After the layout has been fixed, all variable * fields (all holes in the byte ranges) are replaced with 0. This document is * then base64 encoded and signed. *
** In finishSign, the variable fields (values, /Cert) are replaced with the * values according to the encoding. *
* * @author wprinz */ public class BinarySignator_1_0_0 implements Signator { // 04.11.2010 changed by exthex - fillReplacesWithValue no longer removes multiple newlines from values private static Log log = LogFactory.getLog(BinarySignator_1_0_0.class); /** * Settings key for baik enables signatures */ public static final String SIG_BAIK_ENABLED = "SIG_BAIK_ENABLED"; /** * The Pdf-AS ID of this Signator. */ public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0); private Normalizer normalizer; /** * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() */ public PdfASID getMyId() { return MY_ID; } /** * Default constructor. */ public BinarySignator_1_0_0() { try { this.normalizer = new Normalizer(); } catch (NormalizeException e) { String msg = "Normalizer can not be initialized"; throw new RuntimeException(msg, new SignatureException(400, msg, e)); } } /** * @see at.gv.egiz.pdfas.framework.signator.Signator#prepareSign(PdfDataSource, String, TablePos, TimeStamper) */ public SignatorInformation prepareSign(PdfDataSource pdfDataSource, String profile, TablePos pos, TimeStamper timeStamper) throws SignatorException { try { // dferbas: has to be true everytime boolean has_SIG_ID = true; String baikStr = SettingsReader.getInstance().getSetting("sig_obj." +profile+".key."+SIG_BAIK_ENABLED, "default."+SIG_BAIK_ENABLED, "false"); boolean baikEnabled = "true".equalsIgnoreCase(baikStr); if (baikEnabled) { log.debug("found baik enabled signature"); } SignatureObject signature_object = PdfAS.createSignatureObjectFromType(profile); signature_object.fillValues((char) BinarySignature.LAYOUT_PLACEHOLDER, has_SIG_ID, baikEnabled); signature_object.setKZ(getMyId()); PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(signature_object); PositioningInstruction pi = PdfAS.determineTablePositioning(pos, profile, pdfDataSource, pdf_table); List all_field_definitions = signature_object.getSignatureTypeDefinition().getFieldDefinitions(); List variable_field_definitions = new ArrayList(); for (int i = 0; i < all_field_definitions.size(); i++) { SignatureFieldDefinition sfd = (SignatureFieldDefinition) all_field_definitions.get(i); if (sfd.placeholder_length > 0) { if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false) { continue; } if (sfd.field_name.equals(SignatureTypes.SIG_ALG) && baikEnabled == false) { continue; } variable_field_definitions.add(sfd); } } List all_invisible_field_definitions = signature_object.getSignatureTypeDefinition().getInvisibleFieldDefinitions(); List invisible_field_definitions = new ArrayList(); boolean isKZInvisible = false; String invKZString = null; for (int i = 0; i < all_invisible_field_definitions.size(); i++) { SignatureFieldDefinition sfd = (SignatureFieldDefinition) all_invisible_field_definitions.get(i); if (sfd.field_name.equals(SignatureTypes.SIG_KZ)) { isKZInvisible = true; invKZString = signature_object.getKZ().toString(); continue; } if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false) { continue; } if (sfd.field_name.equals(SignatureTypes.SIG_ALG) && baikEnabled == false) { continue; } invisible_field_definitions.add(sfd); } IncrementalUpdateInformation iui = IncrementalUpdateHelper.writeIncrementalUpdate(pdfDataSource, pdf_table, profile, pi, variable_field_definitions, all_field_definitions, invisible_field_definitions, invKZString, timeStamper, null, signature_object); iui.invisible_field_definitions = invisible_field_definitions; iui.invisibleKZString = invKZString; String temp_string = iui.temp_ir_number + " " + iui.temp_ir_generation + " obj"; //$NON-NLS-1$//$NON-NLS-2$ byte[] temp_bytes = ArrayUtils.add(temp_string.getBytes("US-ASCII"), 0, (byte) 0x0A); int temp_start = ByteArrayUtils.lastIndexOf(iui.signed_pdf, temp_bytes); byte[] stream_bytes = new byte[] { '>', '>', 's', 't', 'r', 'e', 'a', 'm', 0x0A }; int stream_start = ByteArrayUtils.indexOf(iui.signed_pdf, temp_start, stream_bytes); iui.content_stream_start = stream_start + stream_bytes.length; // update the stream indices Iterator it = iui.replaces.iterator(); while (it.hasNext()) { ReplaceInfo ri = (ReplaceInfo) it.next(); Iterator sit = ri.replaces.iterator(); while (sit.hasNext()) { StringInfo si = (StringInfo) sit.next(); si.string_start += iui.content_stream_start; } } // update KZ list indices: if (!isKZInvisible) { it = iui.kz_list.iterator(); while (it.hasNext()) { StringInfo si = (StringInfo) it.next(); si.string_start += iui.content_stream_start; } } BinarySignature.markByteRanges(iui); // byte [] old_signed_pdf = iui.signed_pdf; iui.signed_pdf = BinarySignature.prepareDataToSign(iui.signed_pdf, iui.byte_ranges); BinarySignatorInformation bsi = compressIUI(iui); return bsi; } catch (UnsupportedEncodingException e) { throw new SignatorException(201, e); } catch (PDFDocumentException e) { throw new SignatorException(e.getErrorCode(), e); } catch (PresentableException e) { throw new SignatorException(201, e); } } /** * @see at.gv.egiz.pdfas.framework.signator.Signator#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation, * at.gv.egiz.pdfas.framework.output.DataSink) */ public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException { try { IncrementalUpdateInformation iui = uncompressIUI((BinarySignatorInformation) signatorInformation); // PERF: need to keep the whole pdf in mem for processing // PdfAS.prefixID(iui.signed_signature_object, PdfAS.BINARY_ID); fillReplacesWithValues(iui); // This is needed so that certificates are stored try { iui.signed_signature_object.kz = getMyId().toString(); SignatureObjectHelper.convertSignSignatureObjectToSignatureObject(iui.signed_signature_object, iui.signProfile); } catch (PresentableException e) { throw new SignatorException(e); } BinarySignature.replaceCertificate(iui); BinarySignature.replaceTimestamp(iui); BinarySignature.replacePlaceholders(iui); // dferbas: alternative sign attrib creation // PdfReader reader = new PdfReader(iui.signed_pdf); // // OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE); // // try { // PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true); // // BinarySignature.createAdobeSigAttrib(stamper, signatorInformation, signatorInformation.getActualTablePos()); // // } catch (DocumentException e) { // log.error("pdf error", e); // throw new SignatorException(ErrorCode.CANNOT_WRITE_PDF, e); // } OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE); os.write(iui.signed_pdf); os.close(); } catch (PDFDocumentException e) { throw new SignatorException(e.getErrorCode(), e); } catch (IOException e) { throw new SignatorException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); } } /** * Reads the signature values from the signed signature object and fills the * corresponding value in the Replaces array. * * @param iui * The IncrementalUpdateInformation. */ protected void fillReplacesWithValues(final IncrementalUpdateInformation iui) { Iterator it = iui.replaces.iterator(); HashMap ognlCtx = new HashMap(); ognlCtx.put("iui", iui); ognlCtx.put("sso", iui.signed_signature_object); OgnlUtil ognl = new OgnlUtil(ognlCtx); while (it.hasNext()) { ReplaceInfo ri = (ReplaceInfo) it.next(); // dferbas if (ognl.containsExpression(ri.sfd.value)) { // evaluate expression String res = ognl.compileMessage(ri.sfd.value); ri.value = this.normalizer.normalize(res, true); } else { ri.value = iui.signed_signature_object.retrieveStringValue(ri.sfd.field_name); } } } /** * Forms the SignatureData to be used for signing. * * @param iui * The IncrementalUpdateInformation. * @return Returns the SignatureData to be used for signing. */ protected SignatureData formSignatureData(IncrementalUpdateInformation iui) { // String document_text = // BinarySignature.retrieveSignableTextFromData(iui.signed_pdf, // iui.signed_pdf.length); // signed_pdf.length); // // byte[] data; // try // { // data = document_text.getBytes("UTF-8"); //$NON-NLS-1$ // } // catch (UnsupportedEncodingException e) // { // throw new RuntimeException("Very strange: UTF-8 character encoding not // supported.", e); //$NON-NLS-1$ // } DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, iui.sign_iui_block); SignatureData signature_data = new SignatureDataImpl(ds, PdfAS.PDF_MIME_TYPE); return signature_data; } protected BinarySignatorInformation compressIUI(IncrementalUpdateInformation iui) { iui.sign_iui_block = new byte[iui.signed_pdf.length - iui.original_document.getLength()]; System.arraycopy(iui.signed_pdf, iui.original_document.getLength(), iui.sign_iui_block, 0, iui.sign_iui_block.length); iui.signature_data = formSignatureData(iui); // remove the signed pdf from memory iui.signed_pdf = null; BinarySignatorInformation bsi = new BinarySignatorInformation(); bsi.originalDocument = iui.original_document; bsi.incrementalUpdateBlock = iui.sign_iui_block; bsi.signatureData = iui.signature_data; bsi.replaces = iui.replaces; bsi.cert_start = iui.cert_start; bsi.cert_length = iui.cert_length; bsi.enc_start = iui.enc_start; bsi.enc_length = iui.enc_length; bsi.atp = iui.actualTablePos; bsi.signProfile = iui.signProfile; bsi.timestamp_length = iui.timestamp_length; bsi.timestamp_start = iui.timestamp_start; return bsi; } protected IncrementalUpdateInformation uncompressIUI(BinarySignatorInformation bsi) { IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); iui.original_document = bsi.originalDocument; iui.sign_iui_block = bsi.incrementalUpdateBlock; iui.signature_data = bsi.signatureData; iui.replaces = bsi.replaces; iui.cert_start = bsi.cert_start; iui.cert_length = bsi.cert_length; iui.enc_start = bsi.enc_start; iui.enc_length = bsi.enc_length; iui.actualTablePos = bsi.atp; iui.signProfile = bsi.signProfile; iui.timestamp_length = bsi.timestamp_length; iui.timestamp_start = bsi.timestamp_start; iui.signed_signature_object = bsi.signSignatureObject; restoreSignedPdf(iui); return iui; } protected void restoreSignedPdf(IncrementalUpdateInformation iui) { iui.signed_pdf = new byte[iui.original_document.getLength() + iui.sign_iui_block.length]; try { InputStream is = iui.original_document.createInputStream(); is.read(iui.signed_pdf, 0, iui.original_document.getLength()); is.close(); } catch (IOException e) { throw new RuntimeException(e); } System.arraycopy(iui.sign_iui_block, 0, iui.signed_pdf, iui.original_document.getLength(), iui.sign_iui_block.length); } public String getEncoding() { // not used for binary signature return "utf-8"; } }