From 61a2d23ef72630934c603fe9ffb96ebebff6ee09 Mon Sep 17 00:00:00 2001 From: netconomy Date: Thu, 29 Nov 2007 12:00:22 +0000 Subject: PDF-AS API git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@233 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java | 39 + src/main/java/at/gv/egiz/pdfas/api/PdfAs.java | 123 +++ .../egiz/pdfas/api/analyze/AnalyzeParameters.java | 69 ++ .../gv/egiz/pdfas/api/analyze/AnalyzeResult.java | 30 + .../at/gv/egiz/pdfas/api/commons/Constants.java | 77 ++ .../pdfas/api/commons/SignatureInformation.java | 97 ++ .../egiz/pdfas/api/commons/SignatureProfile.java | 29 + .../egiz/pdfas/api/exceptions/PdfAsException.java | 78 ++ .../java/at/gv/egiz/pdfas/api/io/DataSink.java | 75 ++ .../java/at/gv/egiz/pdfas/api/io/DataSource.java | 74 ++ .../java/at/gv/egiz/pdfas/api/io/FileBased.java | 31 + .../java/at/gv/egiz/pdfas/api/io/TextBased.java | 30 + .../at/gv/egiz/pdfas/api/sign/SignParameters.java | 173 ++++ .../java/at/gv/egiz/pdfas/api/sign/SignResult.java | 49 + .../egiz/pdfas/api/sign/pos/SignaturePosition.java | 52 + .../pdfas/api/sign/pos/SignaturePositioning.java | 189 ++++ .../api/sign/pos/axis/AbsoluteAxisAlgorithm.java | 35 + .../pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java | 14 + .../pdfas/api/sign/pos/axis/AxisAlgorithm.java | 14 + .../api/sign/pos/page/AbsolutePageAlgorithm.java | 37 + .../pdfas/api/sign/pos/page/AutoPageAlgorithm.java | 20 + .../pdfas/api/sign/pos/page/NewPageAlgorithm.java | 14 + .../pdfas/api/sign/pos/page/PageAlgorithm.java | 14 + .../gv/egiz/pdfas/api/verify/SignatureCheck.java | 31 + .../api/verify/VerifyAfterAnalysisParameters.java | 117 +++ .../gv/egiz/pdfas/api/verify/VerifyParameters.java | 183 ++++ .../at/gv/egiz/pdfas/api/verify/VerifyResult.java | 97 ++ .../at/gv/egiz/pdfas/api/verify/VerifyResults.java | 27 + .../java/at/gv/egiz/pdfas/commandline/Main.java | 1071 ++++++++++++++++++++ .../gv/egiz/pdfas/framework/ConnectorFactory.java | 12 +- .../egiz/pdfas/framework/ConnectorParameters.java | 85 ++ .../framework/signator/SignatorInformation.java | 20 + .../at/gv/egiz/pdfas/impl/api/CheckHelper.java | 213 ++++ .../at/gv/egiz/pdfas/impl/api/PdfAsObject.java | 317 ++++++ .../java/at/gv/egiz/pdfas/impl/api/PosHelper.java | 79 ++ .../pdfas/impl/api/analyze/AnalyzeResultImpl.java | 47 + .../pdfas/impl/api/commons/DataSinkAdapter.java | 83 ++ .../impl/api/commons/DataSourceApiAdapter.java | 85 ++ .../impl/api/commons/PdfDataSourceAdapter.java | 52 + .../api/commons/SignatureInformationAdapter.java | 87 ++ .../impl/api/commons/SignatureProfileImpl.java | 56 + .../impl/api/commons/TextDataSourceAdapter.java | 52 + .../api/sign/ActualSignaturePositionAdapter.java | 73 ++ .../egiz/pdfas/impl/api/sign/SignResultImpl.java | 75 ++ .../pdfas/impl/api/verify/SignatureCheckImpl.java | 51 + .../pdfas/impl/api/verify/VerifyResultAdapter.java | 126 +++ .../pdfas/impl/api/verify/VerifyResultsImpl.java | 38 + .../pdfas/impl/input/helper/DataSourceHelper.java | 17 +- .../impl/signator/IncrementalUpdateHelper.java | 8 +- .../signator/binary/BinarySignatorInformation.java | 19 + .../impl/signator/binary/BinarySignator_1_0_0.java | 2 + .../textual/TextualSignatorInformation.java | 19 +- .../signator/textual/TextualSignator_1_0_0.java | 4 +- .../at/gv/egiz/pdfas/io/ByteArrayDataSink.java | 87 ++ .../at/gv/egiz/pdfas/io/ByteArrayDataSource.java | 95 ++ .../at/gv/egiz/pdfas/io/FileBasedDataSink.java | 96 ++ .../at/gv/egiz/pdfas/io/FileBasedDataSource.java | 121 +++ .../pdfas/io/FileBasedTextBasedDataSource.java | 103 ++ .../egiz/pdfas/io/StringTextBasedDataSource.java | 96 ++ 59 files changed, 5089 insertions(+), 18 deletions(-) create mode 100644 src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/PdfAs.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java create mode 100644 src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java create mode 100644 src/main/java/at/gv/egiz/pdfas/commandline/Main.java create mode 100644 src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java create mode 100644 src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java create mode 100644 src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java create mode 100644 src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java create mode 100644 src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java create mode 100644 src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java create mode 100644 src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java create mode 100644 src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java (limited to 'src/main/java/at/gv/egiz') diff --git a/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java b/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java new file mode 100644 index 0000000..bc6f89d --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java @@ -0,0 +1,39 @@ +/** + * + */ +package at.gv.egiz.pdfas; + +import java.io.File; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.impl.api.PdfAsObject; + +/** + * Main factory for creating a PDF-AS API Instance (PdfAs Interface). + * + * @see PdfAs + * + * @author wprinz + */ +public class PdfAsFactory +{ + /** + * Creates a PDF-AS API instance for the given work directory. + * + * @param workDirectory + * The work directory. + * + * @return Returns an instance of the PDF-AS API. + * @throws IllegalArgumentException + * Thrown, if the workDirectory doesn't exist. + * @throws PdfAsException + * Thrown, if the work directory does not meet its requirements, or + * if the config file is invalid. + */ + public static PdfAs createPdfAs(File workDirectory) throws PdfAsException + { + return new PdfAsObject(workDirectory); + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java b/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java new file mode 100644 index 0000000..4a8a0e0 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java @@ -0,0 +1,123 @@ +/** + * + */ +package at.gv.egiz.pdfas.api; + +import java.util.List; + +import at.gv.egiz.pdfas.api.analyze.AnalyzeParameters; +import at.gv.egiz.pdfas.api.analyze.AnalyzeResult; +import at.gv.egiz.pdfas.api.commons.SignatureProfile; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.api.sign.SignResult; +import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.verify.VerifyParameters; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.gv.egiz.pdfas.api.verify.VerifyResults; + +/** + * The PDF-AS API main interface. + * + *

+ * Create an Object implementing this interface using the proper factory. + *

+ * + * @author wprinz + */ +public interface PdfAs +{ + + /** + * Signs a PDF document using PDF-AS. + * + * @param signParameters + * The sign parameters. + * @return Returns the signed document plus additional information. + * @throws PdfAsException + * Thrown, if an error occurs. + * + * @see SignParameters + * @see SignResult + */ + public SignResult sign(SignParameters signParameters) throws PdfAsException; + + /** + * Verifies a document with (potentially multiple) PDF-AS signatures. + * + * @param verifyParameters + * The verify parameters. + * @return Returns the verification results. + * @throws PdfAsException + * Thrown, if an error occurs. + * + * @see VerifyParameters + * @see VerifyResults + * @see VerifyResult + */ + public VerifyResults verify(VerifyParameters verifyParameters) throws PdfAsException; + + /** + * Analyzes a document for signatures and returns a verify-able list of such. + * + * @param analyzeParameters + * The analyzation parameters. + * @return Returns a list of verify-able signatures that were found in the + * document. + * @throws PdfAsException + * Thrown on error. + * + * @see AnalyzeParameters + * @see AnalyzeResult + * @see {@link #verify(AnalyzeResult)} + */ + public AnalyzeResult analyze(AnalyzeParameters analyzeParameters) throws PdfAsException; + + /** + * Verifies a list of signatures that have been analyzed previously. + * + * @param verifyAfterAnalysisParameters The parameters. + * + * @return Returns the verification results. + * @throws PdfAsException + * Thrown on error. + * + * @see AnalyzeResult + * @see VerifyAfterAnalysisParameters + * @see VerifyResults + * @see VerifyResult + * @see {@link #analyze(AnalyzeParameters)} + */ + public VerifyResults verify(VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) throws PdfAsException; + + /** + * Reloads the configuration from the work directory. + * + * @throws PdfAsException + * Thrown, if an error occurs. + */ + public void reloadConfig() throws PdfAsException; + + /** + * Returns the list of information objects about the profiles available in the + * configuration. + * + *

+ * Note: Currently the profile information consists of the profile Id and the + * MOA Key Id only. + *

+ *

+ * Note: In near future the profile management will be moved out of the config + * file into an API class representation of the profiles which may render this + * (and related) methods obsolete. + *

+ * + * @return Returns the list of {@link SignatureProfile} objects with + * information about the profiles available in the configuration. + * @throws PdfAsException + * Thrown on error. + * + * @see SignatureProfile + */ + public List getProfileInformation() throws PdfAsException; +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java b/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java new file mode 100644 index 0000000..0ab854c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java @@ -0,0 +1,69 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.analyze; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.io.DataSource; + +/** + * Parameter object that holds the analyze parameters. + * + * @author wprinz + */ +public class AnalyzeParameters +{ + + /** + * The document to be analyzed. + */ + protected DataSource document = null; + + /** + * The mode of operation how the document is analyzed. + * + *

+ * May be {@link Constants#VERIFY_MODE_BINARY_ONLY} to check the document for + * binary signatures only (very fast). Or may be + * {@link Constants#VERIFY_MODE_SEMI_CONSERVATIVE} to perform a semi + * conservative (optimized) text and binary verification (slow). Or may be + * {@link Constants#VERIFY_MODE_FULL_CONSERVATIVE} to perform a full + * conservative text and binary verification (very slow). + *

+ */ + protected String verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE; + + /** + * @return the document + */ + public DataSource getDocument() + { + return this.document; + } + + /** + * @param document the document to set + */ + public void setDocument(DataSource document) + { + this.document = document; + } + + /** + * @return the verifyMode + */ + public String getVerifyMode() + { + return this.verifyMode; + } + + /** + * @param verifyMode the verifyMode to set + */ + public void setVerifyMode(String verifyMode) + { + this.verifyMode = verifyMode; + } + + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java b/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java new file mode 100644 index 0000000..098f309 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java @@ -0,0 +1,30 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.analyze; + +import java.util.List; + +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; + +/** + * The result of an analyze operation, which is a list of verifyable signatures. + * + * @author wprinz + * + */ +public interface AnalyzeResult +{ + /** + * Returns the list of found signatures. + * + * @return Returns a list of {@link SignatureInformation} objects representing all + * found signatures. + * @throws PdfAsException + * Thrown on error. + * + * @see SignatureInformation + */ + public List getSignatures() throws PdfAsException; +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java b/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java new file mode 100644 index 0000000..e8ebc16 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java @@ -0,0 +1,77 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.commons; + +/** + * Contains commonly used constants. + * + * @author wprinz + */ +public final class Constants +{ + + /** + * Hidden default constructor. + */ + private Constants() + { + // empty + } + + /** + * A binary signature. + */ + public static String SIGNATURE_TYPE_BINARY = "binary"; + + /** + * A textual signature. + */ + public static String SIGNATURE_TYPE_TEXTUAL = "textual"; + + /** + * A "detached" textual signature. + * + *

+ * The document text is signed, but instead of returning the pdf with the signature block, + * the sign result XML of the connector is returned. + *

+ */ + public static String SIGNATURE_TYPE_DETACHEDTEXTUAL = "detachedtextual"; + + /** + * The signature device moa. + */ + public static String SIGNATURE_DEVICE_MOA = "moa"; + + /** + * The signature device bku. + */ + public static String SIGNATURE_DEVICE_BKU = "bku"; + + /** + * Only binary signatures are verified. + */ + public static String VERIFY_MODE_BINARY_ONLY = "binaryOnly"; + + /** + * Binary and textual signatures are verified with time optimization. + * + *

+ * This mode of operation tries to minimize the numbers of text extractions, + * which are very time intensive, at the cost of some rare cases, in which some + * signatures may not be found. + *

+ */ + public static String VERIFY_MODE_SEMI_CONSERVATIVE = "semiConservative"; + + /** + * Binary and textual signatures are verified. + */ + public static String VERIFY_MODE_FULL_CONSERVATIVE = "fullConservative"; + + /** + * All signatures are verified. + */ + public static int VERIFY_ALL = -1; +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java b/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java new file mode 100644 index 0000000..d8c2a34 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * This software is the confidential and proprietary information of Know-Center, + * Graz, Austria. You shall not disclose such Confidential Information and shall + * use it only in accordance with the terms of the license agreement you entered + * into with Know-Center. + * + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. + * + * $Id: SignatureHolder.java,v 1.3 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.gv.egiz.pdfas.api.commons; + +import java.security.cert.X509Certificate; +import java.util.Date; + +import at.gv.egiz.pdfas.api.io.DataSource; + +/** + * Holds the information of one found signature block, which is the signed data + * and the corresponding signature information. + * + * @author wprinz + */ +public interface SignatureInformation +{ + /** + * Returns the type of this signature (binary/textual). + * + *

+ * May be {@link Constants#SIGNATURE_TYPE_BINARY} or + * {@link Constants#SIGNATURE_TYPE_TEXTUAL}. + *

+ * + * @return Returns the type of this signature (binary/textual). + */ + public String getSignatureType(); + + /** + * Returns the DataSource providing the data that was signed. + * + *

+ * Note that this is the signed data as sent to the verification device by + * PDF-AS. The verification device (e.g. MOA) may perform several other + * transformations on the data before feeding it to the signature hash + * function. To get the actual hashed data use the ReturnHashInputData mechanism (which is very slow). + *

+ * + * @return Returns the DataSource providing the data that was signed. + * + * @see at.gv.egiz.pdfas.api.verify.VerifyParameters#setReturnHashInputData(boolean) + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getHashInputData() + * + */ + public DataSource getSignedData(); + + /** + * Returns the certificate of the signer. + * + *

+ * Information like subject name, issuer name or serial number can be + * retrieved form this certificate. + *

+ * + * @return Returns the certificate of the signer. + */ + public X509Certificate getSignerCertificate(); + + /** + * Returns the signing time, which is the time when the signature was created. + * + * @return Returns the signing time, which is the time when the signature was + * created. + */ + public Date getSigningTime(); + + /** + * Returns additional, internal information about the found signature. + * + *

+ * Note that this provides a way for developers to gather core information + * about the signature. What information is returned strongly depends on the + * core implementation. + *

+ * + * @return Returns additional, internal information about the signature. Null + * means that no additional information is available. + */ + public Object getInternalSignatureInformation(); + +} \ No newline at end of file diff --git a/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java b/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java new file mode 100644 index 0000000..52bd27f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java @@ -0,0 +1,29 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.commons; + +/** + * Definition of a signature profile. + * + * @author wprinz + */ +public interface SignatureProfile +{ + // TODO: the full profile information will be implemented in future + + /** + * Returns the profile id. + * + * @return Returns the profile id. + */ + public String getProfileId(); + + /** + * Returns the MOA KeyIdentifier. + * + * @return Returns the MOA KeyIdentifier. + */ + public String getMOAKeyIdentifier(); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java b/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java new file mode 100644 index 0000000..2986f81 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java @@ -0,0 +1,78 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.exceptions; + +/** + * This exception is the base for all PDF-AS exceptions. + * + *

+ * Every PDF-AS Exception has an error code. + *

+ * + * @author wprinz + */ +public abstract class PdfAsException extends Exception +{ + /** + * The error code. + */ + protected int errorCode = -1; + + /** + * Constructor. + * + * @param errorCode + * The error code. + * @param message + * The detail message. + */ + public PdfAsException(int errorCode, String message) + { + super(message); + + this.errorCode = errorCode; + } + + /** + * Constructor. + * + * @param errorCode + * The error code. + * @param message + * The detail message. + * @param cause + * The cause. + */ + public PdfAsException(int errorCode, String message, Throwable cause) + { + super(message, cause); + + this.errorCode = errorCode; + } + + /** + * Constructor. + * + * @param errorCode + * The error code. + * @param cause + * The cause. + */ + public PdfAsException(int errorCode, Throwable cause) + { + super(cause); + + this.errorCode = errorCode; + } + + /** + * Returns the error code of this exception. + * + * @return Returns the error code of this exception. + */ + public int getErrorCode() + { + return this.errorCode; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java b/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java new file mode 100644 index 0000000..0136cf7 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java @@ -0,0 +1,75 @@ +package at.gv.egiz.pdfas.api.io; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Output document data sink. + * + *

+ * Actually, the DataSink can be seen as a factory for creating OutputStreams + * with mime type and character encoding provided. This allows the API user to + * decide how data is to be stored (e.g. in a file, in a byte array, etc.). + *

+ * + * @author wprinz + */ +public interface DataSink +{ + /** + * Creates an OutputStream for binary data. + * + *

+ * Note that the stream may be written only once. Creating another stream + * overwrites the existing one. + *

+ * + * @param mimeType + * The mime type of the output data. + * @return Returns the created output stream. + * @throws IOException + * Thrown if the stream cannot be created. + */ + public OutputStream createOutputStream(String mimeType) throws IOException; + + /** + * Creates an OutputStream for character data. + * + *

+ * This is basically the same as {@link #createOutputStream(String)}, but + * allows to specify the character encoding. + *

+ * + * @param mimeType + * The mime type of the output data. + * @param characterEncoding + * The character encoding of the data. + * @return Returns the created output stream. + * @throws IOException + * Thrown if the stream cannot be created. + */ + public OutputStream createOutputStream(String mimeType, String characterEncoding) throws IOException; + + /** + * Returns the mime type of the data stream. + * + *

+ * This is only valid after a stream has been created. + *

+ * + * @return Returns the mime type of the data stream. + */ + public String getMimeType(); + + /** + * Returns the character encoding of the data stream. + * + *

+ * This is only valid after a stream has been created. Null means that no + * character encoding was specified for the data (e.g. if the data is binary). + *

+ * + * @return Returns the character encoding of the data stream. + */ + public String getCharacterEncoding(); +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java b/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java new file mode 100644 index 0000000..bd8e0db --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java @@ -0,0 +1,74 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.io; + +import java.io.InputStream; + +/** + * Input document data source. + * + *

+ * This allows the holder of the data to decide how the data is to be stored (e.g. in a File or in a byte array). + *

+ * + * @author wprinz + * + */ +public interface DataSource +{ + /** + * Creates a new InputStream that allows to read out the document's binary + * data from the beginning. + * + * @return Returns the InputStream with the binary data. + */ + public InputStream createInputStream(); + + /** + * Returns the length (number of bytes) of the stream. + * + * @return Returns the length (number of bytes) of the stream. + */ + public int getLength(); + + /** + * Returns the data of this DataSource as a byte array for random read only access. + * + *

+ * Calling this method indicates that you need a byte array for random + * read only access. The DataSource implementation should of + * course cache this byte array to avoid too much memory usage. + *

+ *

+ * Performance analysis has shown that the libraries internally convert the + * streams to byte arrays and that file system access is very slow. + *

+ *

+ * Never write to this byte array! + *

+ * + * @return Returns the data of this DataSource as a byte array for random read only access. + */ + public byte[] getAsByteArray(); + + /** + * Returns the mime type of the data. + * + * @return Returns the mime type of the data. + */ + public String getMimeType(); + + /** + * Returns the character encoding of the data. + * + *

+ * This makes only sense for character based mime types. + *

+ * + * @return Returns the character encoding of the data or null if no encoding + * is applicable (e.g. if the data is binary). + */ + public String getCharacterEncoding(); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java b/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java new file mode 100644 index 0000000..555b630 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java @@ -0,0 +1,31 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.io; + +import java.io.File; + +/** + * Tells that the IO element (DataSink or DataSource) is backed by a file in the local file system. + * + *

+ * This is a hint that may be used by PDF-AS to optimize data access. + *

+ * + * @author wprinz + */ +public interface FileBased +{ + + /** + * Returns the File "behind" this io element. + * + *

+ * This is usually used to determine the file name itself. + *

+ * + * @return Returns the File "behind" this io element. + */ + public File getFile (); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java b/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java new file mode 100644 index 0000000..68b5729 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java @@ -0,0 +1,30 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.io; + +/** + * Tells, that the IO Element (DataSink - but mostly DataSource) is based upon + * character data. + * + *

+ * This can be used to retrieve the character text directly with the correct + * encoding etc. + *

+ *

+ * This makes most sense for text DataSources. + *

+ * + * @author wprinz + */ +public interface TextBased +{ + + /** + * Returns the text. + * + * @return Returns the text. + */ + public String getText(); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java b/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java new file mode 100644 index 0000000..cc59cbd --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java @@ -0,0 +1,173 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.io.DataSink; +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePositioning; + +/** + * Parameter object that holds the sign parameters. + * + * @author wprinz + */ +public class SignParameters +{ + /** + * The document to be signed. + * + *

+ * The DataSource implementation encapsulates the actual representaion of the + * data. E.g. the DataSource may be File based or byte array based. See + * package at.gv.egiz.pdfas.framework.input and at.gv.pdfas.impl.input + *

+ */ + protected DataSource document = null; + + /** + * The type of the signature. + * + *

+ * May be {@link Constants#SIGNATURE_TYPE_BINARY} or + * {@link Constants#SIGNATURE_TYPE_TEXTUAL}. + *

+ */ + protected String signatureType = Constants.SIGNATURE_TYPE_BINARY; + + /** + * The signature device to perform the actual signature. + * + *

+ * May be {@link Constants#SIGNATURE_DEVICE_MOA} or + * {@link Constants#SIGNATURE_DEVICE_BKU}. + *

+ */ + protected String signatureDevice = Constants.SIGNATURE_DEVICE_MOA; + + /** + * The signature profile identifier identifying the profile to be used in the + * config file. + * + *

+ * Note: In near future it will be possible to provide a full specified + * profile here instead of the profile id. + *

+ */ + protected String signatureProfileId = null;; + + /** + * The signature position. Consult the PDF-AS documentation section + * Commandline. + */ + protected SignaturePositioning signaturePositioning = null; + + /** + * The output DataSink that will receive the signed document. + */ + protected DataSink output = null; + + /** + * @return the document + */ + public DataSource getDocument() + { + return document; + } + + /** + * @param document + * the document to set + */ + public void setDocument(DataSource document) + { + this.document = document; + } + + /** + * @return the signatureType + */ + public String getSignatureType() + { + return signatureType; + } + + /** + * @param signatureType + * the signatureType to set + */ + public void setSignatureType(String signatureType) + { + this.signatureType = signatureType; + } + + /** + * @return the signatureDevice + */ + public String getSignatureDevice() + { + return signatureDevice; + } + + /** + * @param signatureDevice + * the signatureDevice to set + */ + public void setSignatureDevice(String signatureDevice) + { + this.signatureDevice = signatureDevice; + } + + /** + * @return the signatureProfileId + */ + public String getSignatureProfileId() + { + return signatureProfileId; + } + + /** + * @param signatureProfileId + * the signatureProfileId to set + */ + public void setSignatureProfileId(String signatureProfileId) + { + this.signatureProfileId = signatureProfileId; + } + + /** + * @return the signaturePositioning + */ + public SignaturePositioning getSignaturePositioning() + { + return this.signaturePositioning; + } + + /** + * @param signaturePositioning + * the signaturePositioning to set + */ + public void setSignaturePositioning(SignaturePositioning signaturePositioning) + { + this.signaturePositioning = signaturePositioning; + } + + /** + * @return the output + */ + public DataSink getOutput() + { + return output; + } + + /** + * @param output + * the output to set + */ + public void setOutput(DataSink output) + { + this.output = output; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java b/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java new file mode 100644 index 0000000..519a9e1 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java @@ -0,0 +1,49 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign; + +import java.security.cert.X509Certificate; + +import at.gv.egiz.pdfas.api.io.DataSink; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePosition; + +/** + * The result of a sign operation. + * + * @author wprinz + */ +public interface SignResult +{ + + /** + * Returns the filled output data sink. + * + * @return Returns the filled output data sink. + */ + public DataSink getOutputDocument(); + + /** + * Returns the certificate of the signer. + * + * @return Returns the certificate of the signer. + */ + public X509Certificate getSignerCertificate(); + + /** + * Returns the position where the signature is finally placed. + * + *

+ * This information can be useful for post-processing the document. + *

+ * + *

+ * Consult the PDF-AS documentation section Commandline for further + * information about positioning. + *

+ * + * @return Returns the position where the signature is finally placed. May + * return null if no position information is available. + */ + public SignaturePosition getSignaturePosition(); +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java new file mode 100644 index 0000000..8dc6b6c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java @@ -0,0 +1,52 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos; + +/** + * Holds the actual, absolute signature position where a signature was placed. + * + *

+ * This is usually returned after signing. + *

+ * + * @author wprinz + */ +public interface SignaturePosition +{ + /** + * Returns the page on which the signature was placed. + * + * @return Returns the page on which the signature was placed. + */ + public int getPage(); + + /** + * Returns the x position. + * + * @return Returns the x position. + */ + public float getX(); + + /** + * Returns the y position. + * + * @return Returns the y position. + */ + public float getY(); + + /** + * Returns the width of the signature. + * + * @return Returns the width of the signature. + */ + public float getWidth(); + + /** + * Returns the height of the signature. + * + * @return Returns the height of the signature. + */ + public float getHeight(); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java new file mode 100644 index 0000000..b9e2c8a --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java @@ -0,0 +1,189 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos; + +import at.gv.egiz.pdfas.api.sign.pos.axis.AbsoluteAxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.axis.AutoAxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.axis.AxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.AbsolutePageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.AutoPageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.NewPageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.PageAlgorithm; + +/** + * Defines how the signature positioning is to be performed. + * + *

+ * This positioning allows to select the location where the signature block is + * placed in the document. + *

+ * + * @author wprinz + */ +public class SignaturePositioning +{ + /** + * The x axis algorithm. + * + *

+ * May be {@link AutoAxisAlgorithm} or {@link AbsoluteAxisAlgorithm} + *

+ */ + protected AxisAlgorithm xAlgorithm = new AutoAxisAlgorithm(); + + /** + * The y axis algorithm. + * + *

+ * May be {@link AutoAxisAlgorithm} or {@link AbsoluteAxisAlgorithm} + *

+ */ + protected AxisAlgorithm yAlgorithm = new AutoAxisAlgorithm(); + + /** + * The width algorithm. + * + *

+ * May be {@link AutoAxisAlgorithm} or {@link AbsoluteAxisAlgorithm} + *

+ */ + protected AxisAlgorithm widthAlgorithm = new AutoAxisAlgorithm(); + + /** + * The page algorithm. + * + *

+ * May be {@link AutoPageAlgorithm}, {@link AbsolutePageAlgorithm} or + * {@link NewPageAlgorithm} + *

+ */ + protected PageAlgorithm pageAlgorithm = new AutoPageAlgorithm(); + + /** + * Provides the position of the footline. + * + *

+ * Only used if the pageAlgorithm is {@link AutoPageAlgorithm} and the + * yAlgorithm is {@link AutoAxisAlgorithm} + *

+ */ + protected float footerLine = 0.0f; + + protected void checkAxisAlgorithm(AxisAlgorithm algorithm) + { + if (algorithm == null) + { + throw new IllegalArgumentException("The algorithm must not be null."); + } + if (!(algorithm instanceof AutoAxisAlgorithm) && !(algorithm instanceof AbsoluteAxisAlgorithm)) + { + throw new IllegalArgumentException("The algorithm must be either Auto or Absolute."); + } + } + + protected void checkPageAlgorithm(PageAlgorithm algorithm) + { + if (algorithm == null) + { + throw new IllegalArgumentException("The algorithm must not be null."); + } + if (!(algorithm instanceof AutoPageAlgorithm) && !(algorithm instanceof AbsolutePageAlgorithm) && !(algorithm instanceof NewPageAlgorithm)) + { + throw new IllegalArgumentException("The algorithm must be either Auto or Absolute."); + } + + } + + /** + * @return the xAlgorithm + */ + public AxisAlgorithm getXAlgorithm() + { + return this.xAlgorithm; + } + + /** + * @param algorithm + * the xAlgorithm to set + */ + public void setXAlgorithm(AxisAlgorithm algorithm) + { + checkAxisAlgorithm(algorithm); + xAlgorithm = algorithm; + } + + /** + * @return the yAlgorithm + */ + public AxisAlgorithm getYAlgorithm() + { + return this.yAlgorithm; + } + + /** + * @param algorithm + * the yAlgorithm to set + */ + public void setYAlgorithm(AxisAlgorithm algorithm) + { + checkAxisAlgorithm(algorithm); + + yAlgorithm = algorithm; + } + + /** + * @return the widthAlgorithm + */ + public AxisAlgorithm getWidthAlgorithm() + { + return this.widthAlgorithm; + } + + /** + * @param widthAlgorithm + * the widthAlgorithm to set + */ + public void setWidthAlgorithm(AxisAlgorithm widthAlgorithm) + { + checkAxisAlgorithm(widthAlgorithm); + + this.widthAlgorithm = widthAlgorithm; + } + + /** + * @return the pageAlgorithm + */ + public PageAlgorithm getPageAlgorithm() + { + return this.pageAlgorithm; + } + + /** + * @param pageAlgorithm + * the pageAlgorithm to set + */ + public void setPageAlgorithm(PageAlgorithm pageAlgorithm) + { + checkPageAlgorithm(pageAlgorithm); + this.pageAlgorithm = pageAlgorithm; + } + + /** + * @return the footerLine + */ + public float getFooterLine() + { + return this.footerLine; + } + + /** + * @param footerLine + * the footerLine to set + */ + public void setFooterLine(float footerLine) + { + this.footerLine = footerLine; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java new file mode 100644 index 0000000..234484c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java @@ -0,0 +1,35 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.axis; + +/** + * An absolute positioned element. + * @author wprinz + */ +public class AbsoluteAxisAlgorithm extends AxisAlgorithm +{ + + /** + * The absolute positioning value on the axis. + */ + protected float absoluteValue = 0.0f; + + /** + * Constructor. + * @param absoluteValue The absolute positioning value on the axis. + */ + public AbsoluteAxisAlgorithm (float absoluteValue) + { + this.absoluteValue = absoluteValue; + } + + /** + * Returns absolute positioning value on the axis. + * @return the absoluteValue Returns absolute positioning value on the axis. + */ + public float getAbsoluteValue() + { + return this.absoluteValue; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java new file mode 100644 index 0000000..4c5459f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java @@ -0,0 +1,14 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.axis; + +/** + * Auto positioning for this element. + * + * @author wprinz + */ +public class AutoAxisAlgorithm extends AxisAlgorithm +{ +// empty +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java new file mode 100644 index 0000000..a4baac6 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java @@ -0,0 +1,14 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.axis; + +/** + * Determines how a certain position is chosen on the axis (x, y, width). + * + * @author wprinz + */ +public abstract class AxisAlgorithm +{ +// base class +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java new file mode 100644 index 0000000..206aa19 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java @@ -0,0 +1,37 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +/** + * The page is selected absolutely by giving the page number directly. + * + * @author wprinz + */ +public class AbsolutePageAlgorithm extends PageAlgorithm +{ + /** + * The page. + */ + protected int page = -1; + + /** + * Constructor. + * + * @param page + * The page. + */ + public AbsolutePageAlgorithm(int page) + { + this.page = page; + } + + /** + * @return the page + */ + public int getPage() + { + return this.page; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java new file mode 100644 index 0000000..0070d5e --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java @@ -0,0 +1,20 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +/** + * The page for placing the signature is selected automatically. + * + *

+ * The algorithm first tries to place the signature on the free space of the + * last page (considering the footer). If there is not enough space on the last + * page, a new page is appended and the signature is placed there. + *

+ * + * @author wprinz + */ +public class AutoPageAlgorithm extends PageAlgorithm +{ +// empty +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java new file mode 100644 index 0000000..2a8f67c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java @@ -0,0 +1,14 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +/** + * Places the signature on a new Page. + * + * @author wprinz + */ +public class NewPageAlgorithm extends PageAlgorithm +{ + // empty block +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java new file mode 100644 index 0000000..9b0fe8a --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java @@ -0,0 +1,14 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +/** + * Determines how the page on which the signature is to be placed is selected. + * + * @author wprinz + */ +public abstract class PageAlgorithm +{ + // empty +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java b/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java new file mode 100644 index 0000000..df29570 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java @@ -0,0 +1,31 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.verify; + +/** + * The result of a signature check performed by a verification device. + * + * @see VerifyResult + * + * @author wprinz + */ +public interface SignatureCheck +{ + /** + * Returns the response code of the check. + * + * @return Returns the response code of the check. + */ + public int getCode(); + + /** + * Returns the textual response message of the check (corresponding to the + * code). + * + * @return Returns the textual response message of the check (corresponding to + * the code). + */ + public String getMessage(); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java new file mode 100644 index 0000000..dd50d79 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java @@ -0,0 +1,117 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.verify; + +import java.util.Date; + +import at.gv.egiz.pdfas.api.analyze.AnalyzeResult; +import at.gv.egiz.pdfas.api.commons.Constants; + +/** + * Parameter object that holds the verify after analysis parameters. + * + * @author wprinz + */ +public class VerifyAfterAnalysisParameters +{ + + /** + * The list of signatures to be verified. + */ + protected AnalyzeResult analyzeResult = null; + + /** + * The signature device to perform the actual signature. + * + *

+ * May be {@link Constants#SIGNATURE_DEVICE_MOA} or + * {@link Constants#SIGNATURE_DEVICE_BKU}. + *

+ */ + protected String signatureDevice = Constants.SIGNATURE_DEVICE_MOA; + + /** + * Allows to pass a VerificationTime to the signature device. + */ + protected Date verificationTime = null; + + /** + * Tells the signature device (e.g. MOA) to return the signature hash input + * data (which is the probably transformed signed data). + * + *

+ * Note that this forces MOA to return the potentially large signature data to + * be returned in the result XML, which may result in very bad performance. + *

+ */ + protected boolean returnHashInputData = false; + + /** + * @return the analyzeResult + */ + public AnalyzeResult getAnalyzeResult() + { + return this.analyzeResult; + } + + /** + * @param analyzeResult + * the analyzeResult to set + */ + public void setAnalyzeResult(AnalyzeResult analyzeResult) + { + this.analyzeResult = analyzeResult; + } + + /** + * @return the signatureDevice + */ + public String getSignatureDevice() + { + return this.signatureDevice; + } + + /** + * @param signatureDevice + * the signatureDevice to set + */ + public void setSignatureDevice(String signatureDevice) + { + this.signatureDevice = signatureDevice; + } + + /** + * @return the verificationTime + */ + public Date getVerificationTime() + { + return this.verificationTime; + } + + /** + * @param verificationTime the verificationTime to set + */ + public void setVerificationTime(Date verificationTime) + { + this.verificationTime = verificationTime; + } + + /** + * @return the returnHashInputData + */ + public boolean isReturnHashInputData() + { + return this.returnHashInputData; + } + + /** + * @param returnHashInputData + * the returnHashInputData to set + */ + public void setReturnHashInputData(boolean returnHashInputData) + { + this.returnHashInputData = returnHashInputData; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java new file mode 100644 index 0000000..fb3b8b8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java @@ -0,0 +1,183 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.verify; + +import java.util.Date; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.io.DataSource; + +/** + * Parameter object that holds the verify parameters. + * + * @author wprinz + */ +public class VerifyParameters +{ + // This would be a perfect point for multiple inheritance in Java. + // VerifyParameters extends AnalyzeParameters, VerifyAfterAnalysisParameters + // Then a lot of code could be easily reused in the PdfAsObject's check*Parameters methods. + + /** + * The document to be verified. + */ + protected DataSource document = null; + + /** + * The signature device to perform the actual signature. + * + *

+ * May be {@link Constants#SIGNATURE_DEVICE_MOA} or + * {@link Constants#SIGNATURE_DEVICE_BKU}. + *

+ */ + protected String signatureDevice = Constants.SIGNATURE_DEVICE_MOA; + + /** + * The mode of operation how the document is analyzed. + * + *

+ * May be {@link Constants#VERIFY_MODE_BINARY_ONLY} to check the document for + * binary signatures only (very fast). Or may be + * {@link Constants#VERIFY_MODE_SEMI_CONSERVATIVE} to perform a semi + * conservative (optimized) text and binary verification (slow). Or may be + * {@link Constants#VERIFY_MODE_FULL_CONSERVATIVE} to perform a full + * conservative text and binary verification (very slow). + *

+ */ + protected String verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE; + + /** + * The (zero based) index of the signature to verify. + * + *

+ * This allows to verify only one found signature instead of all. {@link Constants#VERIFY_ALL} means to + * verify all found signatures. + *

+ */ + protected int signatureToVerify = Constants.VERIFY_ALL; + + /** + * Allows to pass a VerificationTime to the verification device. + * + *

+ * Note that the actual usage of this parameter depends on the verification device. + *

+ */ + protected Date verificationTime = null; + + /** + * Tells the signature device (e.g. MOA) to return the signature hash input + * data (which is the probably transformed signed data). + * + *

+ * Note that this forces MOA to return the potentially large signature data to + * be returned in the result XML, which may result in very bad performance. + *

+ */ + protected boolean returnHashInputData = false; + + /** + * @return the document + */ + public DataSource getDocument() + { + return this.document; + } + + /** + * @param document + * the document to set + */ + public void setDocument(DataSource document) + { + this.document = document; + } + + /** + * @return the signatureDevice + */ + public String getSignatureDevice() + { + return this.signatureDevice; + } + + /** + * @param signatureDevice + * the signatureDevice to set + */ + public void setSignatureDevice(String signatureDevice) + { + this.signatureDevice = signatureDevice; + } + + /** + * @return the verifyMode + */ + public String getVerifyMode() + { + return this.verifyMode; + } + + /** + * @param verifyMode + * the verifyMode to set + */ + public void setVerifyMode(String verifyMode) + { + this.verifyMode = verifyMode; + } + + /** + * @return the signatureToVerify + */ + public int getSignatureToVerify() + { + return this.signatureToVerify; + } + + /** + * @param signatureToVerify + * the signatureToVerify to set + */ + public void setSignatureToVerify(int signatureToVerify) + { + this.signatureToVerify = signatureToVerify; + } + + /** + * @return the verificationTime + */ + public Date getVerificationTime() + { + return this.verificationTime; + } + + /** + * @param verificationTime + * the verificationTime to set + */ + public void setVerificationTime(Date verificationTime) + { + this.verificationTime = verificationTime; + } + + /** + * @return the returnHashInputData + */ + public boolean isReturnHashInputData() + { + return this.returnHashInputData; + } + + /** + * @param returnHashInputData + * the returnHashInputData to set + */ + public void setReturnHashInputData(boolean returnHashInputData) + { + this.returnHashInputData = returnHashInputData; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java new file mode 100644 index 0000000..be5a88f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java @@ -0,0 +1,97 @@ +package at.gv.egiz.pdfas.api.verify; + +import java.util.Date; +import java.util.List; + +import at.gv.egiz.pdfas.api.commons.SignatureInformation; + +/** + * Encapsulates the data of a verification of one signature. + * + * @author wprinz + */ +public interface VerifyResult extends SignatureInformation +{ + /** + * Returns the result of the certificate check. + * + * @return Returns the result of the certificate check. + */ + public SignatureCheck getCertificateCheck(); + + /** + * Returns the result of the value (and hash) check. + * + * @return Returns the result of the value (and hash) check. + */ + public SignatureCheck getValueCheckCode(); + + /** + * Returns the result of the manifest check. + * + * @return Returns the result of the manifest check. + */ + public SignatureCheck getManifestCheckCode(); + + /** + * Returns true, if the signer's certificate is a qualified certificate. + * + * @return Returns true, if the signer's certificate is a qualified + * certificate. + */ + public boolean isQualifiedCertificate(); + + /** + * Returns a list of Strings each stating one public property of the + * certificate. + * + *

+ * Such public properties are certificate extensions each being assigned an + * own OID. For example the public property "Verwaltungseigenschaft" has the + * OID "1.2.40.0.10.1.1.1". + *

+ * + * @return Returns the list of Strings representing the public properties of + * this certificate, if any. + */ + public List getPublicProperties(); + + /** + * Returns the verification time, which is the time when the signature was + * verified. + * + *

+ * Note that this is actually the Date passed to the verify methods over + * {@link VerifyParameters#setVerificationTime(Date)} or + * {@link VerifyAfterAnalysisParameters#setVerificationTime(Date)}. The + * signature devices don't respond the actual verification time so there is no + * guarantee that the set verification time was actually used as time of + * verification. Please consult the device's documentation for more + * information. + *

+ * + * @return Returns the verification time, which is the time when the signature + * was verified. + */ + public Date getVerificationTime(); + + /** + * Returns the hash input data as returned by MOA. + * + *

+ * This will only return a value other than null if the corresponding + * VerifyParameter was set to true. + *

+ *

+ * Note that the HashInputData does not necessarily have to be exactly the + * same as the signed date return by the + * {@link SignatureInformation#getSignedData()} method. + *

+ * + * @return Returns the hash input data as returned by MOA. + * + * @see SignatureInformation#getSignedData() + */ + public String getHashInputData(); + +} diff --git a/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java new file mode 100644 index 0000000..abda1fe --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java @@ -0,0 +1,27 @@ +/** + * + */ +package at.gv.egiz.pdfas.api.verify; + +import java.util.List; + +/** + * The result of the verification of a document. + * + *

+ * Currently, this is not more than a list of VerifyResult objects, one for each + * verified signature. There may be additional items in future PDF-AS versions. + *

+ * + * @author wprinz + */ +public interface VerifyResults +{ + /** + * Returns the List of VerifyResult objects, one for each verified signature. + * + * @return Returns the List of VerifyResult objects, one for each verified + * signature. + */ + public List getResults(); +} diff --git a/src/main/java/at/gv/egiz/pdfas/commandline/Main.java b/src/main/java/at/gv/egiz/pdfas/commandline/Main.java new file mode 100644 index 0000000..415c1fd --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/commandline/Main.java @@ -0,0 +1,1071 @@ +/** + * Copyright (c) 2006 by Know-Center, Graz, Austria + * + * This software is the confidential and proprietary information of Know-Center, + * Graz, Austria. You shall not disclose such Confidential Information and shall + * use it only in accordance with the terms of the license agreement you entered + * into with Know-Center. + * + * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF + * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY + * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. + * + * $Id: Main.java,v 1.5 2006/10/31 08:06:56 wprinz Exp $ + */ +package at.gv.egiz.pdfas.commandline; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.log4j.PropertyConfigurator; + +import at.gv.egiz.pdfas.PdfAsFactory; +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.io.DataSink; +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePositioning; +import at.gv.egiz.pdfas.api.sign.pos.axis.AbsoluteAxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.AbsolutePageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.NewPageAlgorithm; +import at.gv.egiz.pdfas.api.verify.VerifyParameters; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.gv.egiz.pdfas.api.verify.VerifyResults; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.ErrorCodeHelper; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.gv.egiz.pdfas.framework.config.SettingsHelper; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; +import at.gv.egiz.pdfas.io.FileBasedDataSink; +import at.gv.egiz.pdfas.io.FileBasedDataSource; +import at.gv.egiz.pdfas.io.StringTextBasedDataSource; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.web.servlets.VerifyServlet; + +/** + * The main program entry point of the commandline tool. + * + *

+ * The commandline uses the PDF-AS API. + *

+ * + * @author wprinz + */ +public abstract class Main +{ + /** + * Command line parameter setting the application mode sign|verify + */ + protected static final String PARAMETER_MODE = "-mode"; + + /** + * Command line parameter setting the application to connect + */ + protected static final String PARAMETER_CONNECTOR = "-connector"; + + /** + * Command line parameter setting the signature mode. + */ + protected static final String PARAMETER_SIGNATURE_MODE = "-sigmode"; + + /** + * Command line parameter setting the signature type. + */ + protected static final String PARAMETER_SIGNATURE_TYPE = "-sigtype"; + + /** + * Command line parameter setting the username + */ + protected static final String PARAMETER_USER_NAME = "-username"; + + /** + * Command line parameter setting the users password + */ + protected static final String PARAMETER_USER_PASSWORD = "-password"; + + /** + * Command line parameter selecting the position of the signature. + */ + protected static final String PARAMETER_POS = "-pos"; + + /** + * Command line parameter selecting the signature which is going to be + * verified. + */ + protected static final String PARAMETER_VERIFY_WHICH = "-verify_which"; + + /** + * The application mode sign + */ + public static final String VALUE_MODE_SIGN = "sign"; + + /** + * The application mode verify + */ + public static final String VALUE_MODE_VERIFY = "verify"; + + /** + * The application mode sign + */ + public static final String VALUE_SIGNATURE_MODE_BINARY = "binary"; + + /** + * The application mode verify + */ + public static final String VALUE_SIGNATURE_MODE_TEXTUAL = "textual"; + + /** + * The application mode verify + */ + public static final String VALUE_SIGNATURE_MODE_DETACHED = "detached"; + + /** + * The application mode verify + */ + public static final String VALUE_SIGNATURE_MODE_DETACHED_TEXT = "detachedtextual"; + + /** + * The log. + */ + private static final Log logger_ = LogFactory.getLog(Main.class); + + /** + * Main program entry point. + * + * @param args + * The commandline arguments. + * @throws IOException + */ + public static void main(String[] args) throws IOException + { + // ConfigLogger.setLevel(Level.DEBUG); + + SettingsReader.initializeForCommandLine(); + PropertyConfigurator.configure(SettingsReader.CONFIG_PATH + "log4j.properties"); + + // printUsage(System.out); + + String mode = null; + String signature_mode = null; + String connector = null; + + String signature_type = null; + String user_name = null; + String user_password = null; + String pos_string = null; + + int verify_which = -1; + + String input = null; + String output = null; + + try + { + + // for (int i = 0; i < args.length; i++) + // { + // logger_.debug("arg[" + i + "] = " + args[i]); + // } + + for (int i = 0; i < args.length; i++) + { + String cur_arg = args[i].trim(); + + if (cur_arg.equals(PARAMETER_MODE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_MODE); + return; + } + mode = args[i]; + if (!checkMode(mode)) + { + printUnrecognizedValue(PARAMETER_MODE, mode); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_CONNECTOR)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_CONNECTOR); + return; + } + connector = args[i]; + if (!checkConnector(connector)) + { + printUnrecognizedValue(PARAMETER_CONNECTOR, connector); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_SIGNATURE_MODE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_SIGNATURE_MODE); + return; + } + signature_mode = args[i]; + if (!checkSignatureMode(signature_mode)) + { + printUnrecognizedValue(PARAMETER_SIGNATURE_MODE, signature_mode); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_SIGNATURE_TYPE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_SIGNATURE_TYPE); + return; + } + signature_type = args[i]; + if (!checkSignatureType(signature_type)) + { + printUnrecognizedValue(PARAMETER_SIGNATURE_TYPE, signature_type); + return; + } + continue; + } + + if (cur_arg.equals(PARAMETER_USER_NAME)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_USER_NAME); + return; + } + user_name = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_USER_PASSWORD)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_USER_PASSWORD); + return; + } + user_password = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_POS)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_POS); + return; + } + pos_string = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_VERIFY_WHICH)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_VERIFY_WHICH); + return; + } + String str_verify_which = args[i]; + try + { + verify_which = Integer.parseInt(str_verify_which); + } + catch (NumberFormatException e) + { + printUnrecognizedValue(PARAMETER_VERIFY_WHICH, str_verify_which); + return; + } + + continue; + } + + if (cur_arg.charAt(0) == '-') + { + printUnrecognizedOption(cur_arg); + return; + } + + if (input == null) + { + input = cur_arg; + continue; + } + + if (output == null) + { + output = cur_arg; + continue; + } + + printUnrecognizedAdditionalCommandlineArgument(cur_arg); + return; + } + + if (mode == null) + { + printMissingParameter("a mode", PARAMETER_MODE); + return; + } + if (connector == null) + { + printMissingParameter("a connector", PARAMETER_CONNECTOR); + return; + } + if (mode.equals(VALUE_MODE_SIGN)) + { + if (signature_mode == null) + { + printMissingParameter("a signature mode", PARAMETER_SIGNATURE_MODE); + return; + } + if (signature_type == null) + { + SettingsReader settings = SettingsReader.getInstance(); + String default_type = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + signature_type = default_type; + } + if (user_name == null) + { + user_name = ""; + // printMissingParameter("a user name", PARAMETER_USER_NAME); + // return; + } + if (user_password == null) + { + user_password = ""; + // printMissingParameter("a user password", PARAMETER_USER_PASSWORD); + // return; + } + } + + if (input == null) + { + printMissing("an input document"); + return; + } + + File file = new File(input); + if (!file.exists()) + { + System.err.println("The input file '" + input + "' doesn't exist."); + return; + } + + if (mode.equals(VALUE_MODE_SIGN) && output == null) + { + output = generateOutputFileNameFromInput(input, signature_mode); + } + + carryOutCommand(mode, signature_mode, connector, signature_type, user_name, user_password, verify_which, input, output, pos_string); + + } + catch (PdfAsException e) + { + printPresentableException(e); + + if (output != null) + { + logger_.debug("Deleting output file on error."); + File oFile = new File(output); + boolean deleted = oFile.delete(); + if (!deleted) + { + logger_.error("Couldn't delete output file " + output); + } + } + } + finally + { + SettingsReader.clearTemporaryDirectory(); + } + } + + protected static void carryOutCommand(final String mode, final String signature_mode, final String connector, final String signature_type, final String user_name, final String user_password, + final int verify_which, final String input, String output, final String pos_string) throws PdfAsException + { + // File file = new File(input); + // + // byte[] input_bytes = null; + // try + // { + // FileInputStream fis = new FileInputStream(file); + // input_bytes = new byte[(int) file.length()]; + // fis.read(input_bytes); + // fis.close(); + // } + // catch (IOException e) + // { + // throw new PDFDocumentException(201); + // } + + PrintWriter messageOutput = new PrintWriter(System.out); + + if (mode.equals(VALUE_MODE_SIGN)) + { + carryOutSign(input, connector, signature_mode, signature_type, pos_string, user_name, user_password, output, messageOutput); + } + else + { + carryOutVerify(input, connector, verify_which, messageOutput); + } + messageOutput.flush(); + } + + public static void carryOutSign(String input, String connector, String signature_mode, String signature_type, String pos_string, String user_name, String user_password, String output, + PrintWriter messageOutput) throws PdfAsException + { + messageOutput.println("Signing..."); + + // for performance measurement + long startTime = 0; + long fileSize = 0; + if (logger_.isInfoEnabled()) + { + startTime = System.currentTimeMillis(); + } + + DataSource dataSource = null; + try + { + File file = new File(input); + dataSource = new FileBasedDataSource(file, "application/pdf"); + if (logger_.isDebugEnabled()) + { + fileSize = file.length(); + } + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + + DataSink dataSink = null; + try + { + File outputFile = new File(output); + + dataSink = new FileBasedDataSink(outputFile); + } + catch (IOException e) + { + throw new PDFDocumentException(ErrorCode.CANNOT_WRITE_PDF, e); + } + + processSign(dataSource, connector, signature_mode, signature_type, pos_string, dataSink); + + // for performance measurement + if (logger_.isInfoEnabled()) + { + long endTime = System.currentTimeMillis(); + String toReport = "SIGN;" + signature_mode + ";" + input + ";" + fileSize + ";" + (endTime - startTime); + logger_.info(toReport); + } + + messageOutput.println("Signing was successful."); + } + + public static void carryOutVerify(String input, String connector, int verify_which, PrintWriter messageOutput) throws PdfAsException + { + messageOutput.println("Verifying..."); + + // for performance measurement + long startTime = 0; + long fileSize = 0; + if (logger_.isInfoEnabled()) + { + startTime = System.currentTimeMillis(); + } + + DataSource dataSource = null; + try + { + File file = new File(input); + if (logger_.isDebugEnabled()) + { + fileSize = file.length(); + } + String extension = VerifyServlet.extractExtension(input); + if (extension != null && extension.equals("txt")) + { + try + { + FileInputStream fis = new FileInputStream(file); + byte[] input_bytes = new byte[(int) file.length()]; + fis.read(input_bytes); + fis.close(); + + String text = new String(input_bytes, "UTF-8"); + dataSource = new StringTextBasedDataSource(text); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Very strange: UTF-8 character encoding not supported.", e); + } + } + else + { + dataSource = new FileBasedDataSource(file, "application/pdf"); + } + } + catch (IOException e) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + + VerifyResults results = processVerify(dataSource, connector, verify_which); + + messageOutput.println("Verification results:"); + formatVerifyResults(results, messageOutput); + + // for performance measurement + if (logger_.isInfoEnabled()) + { + long endTime = System.currentTimeMillis(); + String toReport = "VERIFY;" + input + ";" + fileSize + ";" + (endTime - startTime) + ";" + debugVerifyResults(results); + logger_.info(toReport); + } + + } + + public static void processSign(DataSource dataSource, String connector, String signature_mode, String signature_type, String pos_string, DataSink dataSink) throws PdfAsException + { + // FIXME implement this + // TODO this will change soon due to the document-cleaning change request. + //PdfAS.applyStrictMode(pdfDataSource); + + TablePos pos = null; + if (pos_string != null) + { + try + { + pos = PdfAS.parsePositionFromPosString(pos_string); + } + catch (PDFDocumentException e) + { + printUnrecognizedValue(PARAMETER_POS, pos_string); + return; + + } + } + SignaturePositioning posi = null; + if (pos != null) + { + posi = new SignaturePositioning(); + if (!pos.isXauto()) + { + posi.setXAlgorithm(new AbsoluteAxisAlgorithm(pos.getPosX())); + } + if (!pos.isYauto()) + { + posi.setYAlgorithm(new AbsoluteAxisAlgorithm(pos.getPosY())); + } + if (!pos.isWauto()) + { + posi.setWidthAlgorithm(new AbsoluteAxisAlgorithm(pos.getWidth())); + } + if (pos.isNewPage()) + { + posi.setPageAlgorithm(new NewPageAlgorithm()); + } + if (!pos.isPauto()) + { + posi.setPageAlgorithm(new AbsolutePageAlgorithm(pos.getPage())); + } + posi.setFooterLine(pos.getFooterLine()); + } + + PdfAs pdfAs = PdfAsFactory.createPdfAs(new File(SettingsReader.RESOURCES_PATH)); + + SignParameters sp = new SignParameters(); + sp.setDocument(dataSource); + sp.setOutput(dataSink); + sp.setSignatureType(signature_mode); // TODO detached signaturen! + sp.setSignatureDevice(connector); + sp.setSignatureProfileId(signature_type); + sp.setSignaturePositioning(posi); + pdfAs.sign(sp); + + } + + public static VerifyResults processVerify(DataSource dataSource, String connector, int verify_which) throws PdfAsException + { + String verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE; + VerificationFilterParameters parameters = SettingsHelper.readVerificationFilterParametersFromSettings(); + if (parameters.extractBinarySignaturesOnly()) + { + verifyMode = Constants.VERIFY_MODE_BINARY_ONLY; + } + else + { + if (parameters.assumeOnlySignatureUpdateBlocks()) + { + verifyMode = Constants.VERIFY_MODE_SEMI_CONSERVATIVE; + } + else + { + verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE; + } + } + + PdfAs pdfAs = PdfAsFactory.createPdfAs(new File(SettingsReader.RESOURCES_PATH)); + + VerifyParameters vp = new VerifyParameters(); + vp.setDocument(dataSource); + vp.setVerifyMode(verifyMode); + vp.setSignatureDevice(connector); + vp.setReturnHashInputData(false); + vp.setVerificationTime(null); + vp.setSignatureToVerify(verify_which); + VerifyResults vrs = pdfAs.verify(vp); + + return vrs; + } + + protected static String generateOutputFileNameFromInput(String input, String sig_mode) + { + String output = input + "_out"; + if (sig_mode.startsWith("detached")) + { + output += ".xml"; + } + else + { + output += ".pdf"; + } + + return output; + } + + /** + * Prints that the provided option was unrecognized. + * + * @param option + * The unrecognized option. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printUnrecognizedOption(final String option) throws PresentableException + { + System.err.println("Unrecognized option '" + option + "'."); + printUsage(System.out); + } + + /** + * Prints that the provided value was unrecognized. + * + * @param parameter + * The parameter, which is missing a value. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printNoValue(final String parameter) throws PresentableException + { + System.err.println("The parameter " + parameter + " requires a value as next argument."); + printUsage(System.out); + } + + /** + * Prints that the provided value was unrecognized. + * + * @param value + * The unrecognized value. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printUnrecognizedValue(final String parameter, final String value) throws PresentableException + { + System.err.println("The parameter " + parameter + " doesn't recognize the provided value '" + value + "'."); + printUsage(System.out); + } + + /** + * Prints that the provided additional commandline argument was unrecognized. + * + * @param argument + * The unrecognized argument. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printUnrecognizedAdditionalCommandlineArgument(final String argument) throws PresentableException + { + System.err.println("Unrecognized additional commandline argument '" + argument + "'."); + printUsage(System.out); + } + + /** + * Prints that a certain parameter was missing. + * + * @param missing_term + * A description of the missing parameter ("e.g. a mode"). + * @param parameter + * The missing parameter itself (e.g. "-mode"). + * @throws PresentableException + * Forwarded exception. + */ + protected static void printMissingParameter(final String missing_term, final String parameter) throws PresentableException + { + printMissing(missing_term + " ('" + parameter + "' parameter)"); + } + + /** + * Prints that something is missing. + * + * @param missing_term + * A descriptive message of the missing thing. + * @throws PresentableException + * Forwarded exception. + */ + protected static void printMissing(final String missing_term) throws PresentableException + { + System.err.println("Please specify " + missing_term + "."); + printUsage(System.out); + } + + /** + * Prints out the ErrorCodeException in a descriptive form. + * + * @param ece + * The ErrorCodeException to be printed. + */ + protected static void printPresentableException(final PdfAsException e) + { + if (e.getErrorCode() == ErrorCode.PLACEHOLDER_EXCEPTION) + { + PlaceholderException phe = null; + if (e instanceof PlaceholderException) + { + phe = (PlaceholderException) e; + } + else + { + phe = (PlaceholderException) e.getCause(); + } + + System.err.println("Der Platzhalter des Feldes " + phe.getField() + " ist um " + phe.getMissing() + " Bytes zu kurz. "); + } + + System.err.println("Fehler " + e.getErrorCode() + ": " + ErrorCodeHelper.getMessageForErrorCode(e.getErrorCode())); + + if (e instanceof ExternalErrorException) + { + ExternalErrorException eee = (ExternalErrorException) e; + System.err.println("Externer Fehlergrund: " + eee.getExternalErrorCode() + ": " + eee.getExternalErrorMessage()); + } + + logger_.error(e); + } + + /** + * Prints the usage text. + * + * @param writer + * The writer to print the text to. + * @throws PresentableException + * Forwarded exception. + */ + public static void printUsage(PrintStream writer) throws PresentableException + { + writer.println("Usage: pdf-as [OPTIONS] [output file]"); + writer.println(" Required OPTIONS:"); + + writer.println(" " + PARAMETER_MODE + " <" + VALUE_MODE_SIGN + "|" + VALUE_MODE_VERIFY + ">"); + writer.println(" " + VALUE_MODE_SIGN + " ... signs a document"); + writer.println(" " + VALUE_MODE_VERIFY + " ... verifies a document"); + + writer.print(" " + PARAMETER_CONNECTOR + " "); + ConnectorInformation[] ci = ConnectorFactory.getConnectorInformationArray(); + for (int i = 0; i < ci.length; i++) + { + String id = ci[i].getIdentifier(); + if (!ConnectorFactory.isAvailableForCommandline(id)) + { + continue; + } + writer.print(id); + if (i < ci.length - 1) + { + writer.print("|"); + } + } + writer.println(); + for (int i = 0; i < ci.length; i++) + { + String id = ci[i].getIdentifier(); + if (!ConnectorFactory.isAvailableForCommandline(id)) + { + continue; + } + writer.println(" " + id + " ... " + ci[i].getDescription()); + } + + writer.println(" OPTIONS for signation:"); + + writer.println(" " + PARAMETER_SIGNATURE_MODE + " <" + VALUE_SIGNATURE_MODE_BINARY + "|" + VALUE_SIGNATURE_MODE_TEXTUAL + ">"); + writer.println(" " + VALUE_SIGNATURE_MODE_BINARY + " ... signs the complete binary document"); + writer.println(" " + VALUE_SIGNATURE_MODE_TEXTUAL + " ... signs only the textual portion of the document"); + // @iaik: why is this commented out? + //writer.println(" " + VALUE_SIGNATURE_MODE_DETACHED + " ... signs the document using the binary mode and returns the xml signature of it."); + writer.println(" " + VALUE_SIGNATURE_MODE_DETACHED_TEXT + " ... signs the document using the textual mode and returns the xml signature of it."); + + writer.print(" " + PARAMETER_SIGNATURE_TYPE + " <"); + SignatureTypes sig_types = SignatureTypes.getInstance(); + SettingsReader settings = SettingsReader.getInstance(); + List types_array = sig_types.getSignatureTypes(); + Iterator it = types_array.iterator(); + while (it.hasNext()) + { + String type = (String) it.next(); + writer.print(type); + if (it.hasNext()) + { + writer.print("|"); + } + } + writer.println(">"); + writer.println(" ... [optional] the profile to be used. If omitted, the default"); + writer.println(" profile is used."); + String default_type = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + it = types_array.iterator(); + while (it.hasNext()) + { + String type = (String) it.next(); + String descr_key = SignatureTypes.SIG_OBJ + type + "." + SignatureTypes.SIG_DESCR; + String type_descr = settings.getValueFromKey(descr_key); + + writer.println(" " + type + " ... " + (type.equals(default_type) ? "(default) " : "") + type_descr); + } + + writer.println(" " + PARAMETER_USER_NAME + " ... [optional] the user name"); + writer.println(" " + PARAMETER_USER_PASSWORD + " ... [optional] the user password"); + + writer.println(" " + PARAMETER_POS + " ... [optional] the position of the signature block"); + writer.println(" position has the format [x:x_algo];[y:y_algo];[w:w_algo][p:p_algo];[f:f_algo]"); + writer.println(" if not present default is set to x:auto;y:auto;w:auto;p:auto;f:0"); + writer.println(" x_algo:='auto' ... automatic positioning x"); + writer.println(" floatvalue ... absolute x must be >= 0"); + writer.println(" y_algo:='auto' ... automatic positioning y"); + writer.println(" floatvalue ... absolute y must be >= 0"); + writer.println(" w_algo:='auto' ... automatic width"); + writer.println(" floatvalue ... absolute width must be > 0"); + writer.println(" p_algo:='auto' ... automatic last page"); + writer.println(" 'new' ... new page"); + writer.println(" intvalue ... pagenumber must be > 0 if p>number of pages in document p-->handled like p:'new'"); + writer.println(" f_algo floatvalue ... consider footerline must be >= 0 (only if y_algo is auto and p_algo is not 'new')"); + + writer.println(" OPTIONS for verification:"); + writer.println(" " + PARAMETER_VERIFY_WHICH + " ... [optional] zero based number of the signature"); + writer.println(" to be verified. If omitted, all signatures are verified."); + + writer.println(" Example usage:"); + writer.println(" pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_SIGN + " " + PARAMETER_CONNECTOR + " moa some_document.pdf"); + writer.println(" pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_VERIFY + " some_document.pdf_out.pdf"); + } + + /** + * Checks the value for correctness. + * + * @param mode + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + */ + protected static boolean checkMode(String mode) + { + return mode.equals(VALUE_MODE_SIGN) || mode.equals(VALUE_MODE_VERIFY); + } + + /** + * Checks the value for correctness. + * + * @param signature_mode + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + */ + protected static boolean checkSignatureMode(String signature_mode) + { + return signature_mode.equals(VALUE_SIGNATURE_MODE_BINARY) || signature_mode.equals(VALUE_SIGNATURE_MODE_TEXTUAL) + //|| signature_mode.equals(VALUE_SIGNATURE_MODE_DETACHED) + || signature_mode.equals(VALUE_SIGNATURE_MODE_DETACHED_TEXT); + } + + /** + * Checks the value for correctness. + * + * @param connector + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + protected static boolean checkConnector(String connector) throws ConnectorFactoryException + { + return ConnectorFactory.isValidConnectorIdentifier(connector) && ConnectorFactory.isAvailableForCommandline(connector); + } + + /** + * Checks the value for correctness. + * + * @param signature_type + * The parameter's value. + * @return Returns true, if the value is correct, false otherwise. + */ + protected static boolean checkSignatureType(String signature_type) throws SignatureTypesException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + List types_array = sig_types.getSignatureTypes(); + Iterator it = types_array.iterator(); + while (it.hasNext()) + { + String type = (String) it.next(); + if (type.equals(signature_type)) + { + return true; + } + } + return false; + } + + /** + * Translates the commandline argument to a PDF-AS-ID. + * + * @param signature_mode + * The signator mode commandline argument. + * @return Returns the corresponding PDFASID. + */ + protected static PdfASID translateSignatureModeToPdfASID(String signature_mode) + { + if (signature_mode.equals(VALUE_SIGNATURE_MODE_BINARY)) + { + return SignatorFactory.MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_SIGNATURE_MODE_TEXTUAL)) + { + return SignatorFactory.MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_SIGNATURE_MODE_DETACHED)) + { + return SignatorFactory.MOST_RECENT_DETACHED_SIGNATOR_ID; + } + if (signature_mode.equals(VALUE_SIGNATURE_MODE_DETACHED_TEXT)) + { + return SignatorFactory.MOST_RECENT_DETACHEDTEXT_SIGNATOR_ID; + } + return null; + } + + /** + * Formats the verification results. + * + * @param results + * The List of SignatureResponse verification results. + * @param writer + * The output sink to write the formatted text to. + * @throws SettingNotFoundException + * Forwarded exception. + */ + protected static void formatVerifyResults(VerifyResults results, PrintWriter writer) throws SettingNotFoundException + { + Iterator it = results.getResults().iterator(); + while (it.hasNext()) + { + VerifyResult result = (VerifyResult) it.next(); + formatVerifyResult(result, writer); + + if (it.hasNext()) + { + writer.println(); + } + } + } + + /** + * Formats the verification results for debugging. Returns 0 if no error + * occurs or the sum of all error-codes. + * + * @param results + * + * @param writer + * The output sink to write the formatted text to. + * @throws SettingNotFoundException + * Forwarded exception. + */ + protected static int debugVerifyResults(VerifyResults results) throws SettingNotFoundException + { + int toreturn = 0; + Iterator it = results.getResults().iterator(); + while (it.hasNext()) + { + VerifyResult result = (VerifyResult) it.next(); + + toreturn += result.getValueCheckCode().getCode(); + } + return toreturn; + } + + public static void formatVerifyResult(VerifyResult result, PrintWriter writer) throws SettingNotFoundException + { + + writer.println(" Zertifikat:"); + writer.println(" Signator: " + result.getSignerCertificate().getSubjectDN().getName()); + writer.println(" Aussteller: " + result.getSignerCertificate().getIssuerDN().getName()); + writer.println(" Seriennummer: " + result.getSignerCertificate().getSerialNumber()); + List public_properties = result.getPublicProperties(); + Iterator it = public_properties.iterator(); + while (it.hasNext()) + { + String public_property = (String) it.next(); + writer.println(" Eigenschaft: " + public_property); + } + + writer.println(" Zertifikat-Check:"); + writer.println(" " + result.getCertificateCheck().getCode() + " - " + result.getCertificateCheck().getMessage()); + writer.println(" Signatur-Check:"); + writer.println(" " + result.getValueCheckCode().getCode() + " - " + result.getValueCheckCode().getMessage()); + writer.println(" Manifest-Check:"); + writer.println(" " + result.getManifestCheckCode().getCode() + " - " + result.getManifestCheckCode().getMessage()); + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java index b42c8ed..99d692e 100644 --- a/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java +++ b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java @@ -33,34 +33,34 @@ public class ConnectorFactory - public static Connector createConnector (String connectorId, String profile, String locRef) throws ConnectorFactoryException, ConnectorException + public static Connector createConnector (String connectorId, ConnectorParameters connectorParameters) throws ConnectorFactoryException, ConnectorException { if (connectorId.equals(DETACHED_MULTIPART_BKU_CONNECTOR)) { - return new MultipartDetachedBKUConnector(profile); + return new MultipartDetachedBKUConnector(connectorParameters); } if (connectorId.equals(ENVELOPING_BASE64_BKU_CONNECTOR)) { - return new EnvelopedBase64BKUConnector(profile); + return new EnvelopedBase64BKUConnector(connectorParameters.getProfileId()); } if (connectorId.equals(OLD_ENVELOPING_BASE64_BKU_CONNECTOR)) { - return new OldEnvelopingBase64BKUConnector(profile); + return new OldEnvelopingBase64BKUConnector(connectorParameters.getProfileId()); } if (connectorId.equals(DETACHED_LOCREF_MOA_CONNECTOR)) { // TODO Hier wird der neue Connector verwendet // return new DetachedLocRefMOAConnector(profile, locRef); - return new MOASoapWithAttachmentConnector(profile); + return new MOASoapWithAttachmentConnector(connectorParameters); } if (connectorId.equals(ENVELOPING_BASE64_MOA_CONNECTOR)) { // TODO Hier wird NICHT der neue Connector verwendet - return new EnvelopingBase64MOAConnector(profile); + return new EnvelopingBase64MOAConnector(connectorParameters.getProfileId()); // return new MOASoapWithAttachmentConnector(profile); } diff --git a/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java new file mode 100644 index 0000000..618624d --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java @@ -0,0 +1,85 @@ +/** + * + */ +package at.gv.egiz.pdfas.framework; + +import java.util.Date; + +/** + * Parameters passed to the constructor of the Connector. + * + *

+ * Each Connector must have a constructor accepting this parameter class as an + * argument. + *

+ * + * @author wprinz + */ +public class ConnectorParameters +{ + /** + * The profile Id to get the connector parameters from. + * + *

+ * The there are no explicit parameters for the connector in the profile, the + * default parameters are used. + *

+ */ + protected String profileId = null; + + /** + * Tells, if the connector should ask the device to return the hash input + * data. + * + *

+ * Note that not all connectors support to return the hash input data - so + * there is no guarantee that the hash value will actually be returned. + *

+ */ + protected boolean returnHashInputData = false; + + /** + * Allows to specify an explicit time of verification. + * + *

+ * If null, the device's default behaviour determines the time of + * verification, which is usually the current time. + *

+ *

+ * The time of verification usually influences the certificate check. E.g. the + * certificate may not be valid at the time of verification. + *

+ */ + protected Date verificationTime = null; + + public String getProfileId() + { + return this.profileId; + } + + public void setProfileId(String profileId) + { + this.profileId = profileId; + } + + public boolean isReturnHashInputData() + { + return this.returnHashInputData; + } + + public void setReturnHashInputData(boolean returnHashInputData) + { + this.returnHashInputData = returnHashInputData; + } + + public Date getVerificationTime() + { + return this.verificationTime; + } + + public void setVerificationTime(Date verificationTime) + { + this.verificationTime = verificationTime; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java b/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java index da81e87..9abf509 100644 --- a/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java +++ b/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java @@ -3,6 +3,7 @@ */ package at.gv.egiz.pdfas.framework.signator; +import at.knowcenter.wag.egov.egiz.pdf.ActualTablePos; import at.knowcenter.wag.egov.egiz.sig.SignatureData; import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; @@ -40,4 +41,23 @@ public interface SignatorInformation * The SignSignatureObject. */ public void setSignSignatureObject(SignSignatureObject signSignatureObject); + + /** + * Returns the SignSignatureObject. + * + *

+ * After signation, this is used by the framework/API to get additional + * information about the signature. + *

+ * + * @return Returns the SignSignatureObject. + */ + public SignSignatureObject getSignSignatureObject(); + + /** + * Returns the position where the signature table was actually placed. + * + * @return Returns the position where the signature table was actually placed. + */ + public ActualTablePos getActualTablePos(); } diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java new file mode 100644 index 0000000..467113f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java @@ -0,0 +1,213 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.analyze.AnalyzeParameters; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePositioning; +import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.verify.VerifyParameters; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Contains check methods frequently used by the {@link PdfAsObject} to check + * input parameters. + * + * @author wprinz + * + */ +public final class CheckHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(CheckHelper.class); + + /** + * Hidden default constructor. + */ + private CheckHelper() + { + // empty block + } + + /** + * Checks the SignParameters for integrity. + * + * @param sp + * The {@link SignParameters} + */ + public static void checkSignParameters(SignParameters sp) + { + if (sp == null) + { + throw new IllegalArgumentException("The signParameters must not be null."); + } + + checkDocument(sp.getDocument()); + if (sp.getOutput() == null) + { + throw new IllegalArgumentException("The output DataSink must not be null."); + } + checkSignatureType(sp.getSignatureType()); + checkSignatureDevice(sp.getSignatureDevice()); + if (sp.getSignatureProfileId() != null) + { + checkProfileId(sp.getSignatureProfileId()); + } + if (sp.getSignaturePositioning() != null) + { + checkSignaturePositioning(sp.getSignaturePositioning()); + } + } + + /** + * Checks the VerifyParameters for integrity. + * + * @param vp + * The {@link VerifyParameters} + */ + public static void checkVerifyParameters(VerifyParameters vp) + { + if (vp == null) + { + throw new IllegalArgumentException("The verifyParameters must not be null."); + } + + checkDocument(vp.getDocument()); + checkVerifyMode(vp.getVerifyMode()); + checkSignatureDevice(vp.getSignatureDevice()); + if (vp.getSignatureToVerify() < Constants.VERIFY_ALL) + { + throw new IllegalArgumentException("The signatureToVerify parameter is incorrect. " + vp.getSignatureToVerify()); + } + } + + /** + * Checks the AnalyzeParameters for integrity. + * + * @param ap + * The {@link AnalyzeParameters} + */ + public static void checkAnalyzeParameters(AnalyzeParameters ap) + { + if (ap == null) + { + throw new IllegalArgumentException("The analyzeParameters must not be null."); + } + + checkDocument(ap.getDocument()); + checkVerifyMode(ap.getVerifyMode()); + } + + /** + * Checks the VerifyAfterAnalysisParameters for integrity. + * + * @param vaap + * The {@link VerifyAfterAnalysisParameters} + */ + public static void checkVerifyAfterAnalysisParameters(VerifyAfterAnalysisParameters vaap) + { + if (vaap == null) + { + throw new IllegalArgumentException("The analyzeParameters must not be null."); + } + + if (vaap.getAnalyzeResult() == null) + { + throw new IllegalArgumentException("The analyzeResult must not be null."); + } + checkSignatureDevice(vaap.getSignatureDevice()); + } + + protected static void checkDocument(DataSource document) + { + if (document == null) + { + throw new IllegalArgumentException("The document DataSource must not be null."); + } + } + + protected static void checkSignatureType(String signatureType) + { + if (signatureType == null) + { + throw new IllegalArgumentException("The signatureType must not be null."); + } + if (!(signatureType.equals(Constants.SIGNATURE_TYPE_BINARY) || signatureType.equals(Constants.SIGNATURE_TYPE_TEXTUAL) || signatureType.equals(Constants.SIGNATURE_TYPE_DETACHEDTEXTUAL))) + { + throw new IllegalArgumentException("The signatureType must be one of the Constants.SIGNATURE_TYPE_* constants. " + signatureType); + } + } + + protected static void checkProfileId(String profileId) + { + if (profileId == null) + { + throw new IllegalArgumentException("The profileId must not be null."); + } + try + { + if (!SignatureTypes.getInstance().getSignatureTypes().contains(profileId)) + { + throw new IllegalArgumentException("The profileId must be defined in the configuration file. " + profileId); + } + } + catch (SignatureTypesException e) + { + String msg = "Error while checking the profileId parameter - cannot get list of valid profiles. " + profileId; + log.error(msg, e); + throw new IllegalArgumentException(msg); + } + } + + protected static void checkSignaturePositioning(SignaturePositioning signaturePositioning) + { + if (signaturePositioning == null) + { + throw new IllegalArgumentException("The signaturePosition must not be null."); + } + try + { + PosHelper.formTablePos(signaturePositioning); + } + catch (PDFDocumentException e) + { + String msg = "The signaturePosition string is not valid. " + signaturePositioning; + log.error(msg, e); + throw new IllegalArgumentException(msg); + } + } + + protected static void checkVerifyMode(String verifyMode) + { + if (verifyMode == null) + { + throw new IllegalArgumentException("The verifyMode must not be null."); + } + if (!(verifyMode.equals(Constants.VERIFY_MODE_BINARY_ONLY) || verifyMode.equals(Constants.VERIFY_MODE_SEMI_CONSERVATIVE) || verifyMode.equals(Constants.VERIFY_MODE_FULL_CONSERVATIVE))) + { + throw new IllegalArgumentException("The verifyMode must be one of the Constants.VERIFY_MODE_* constants. " + verifyMode); + } + } + + protected static void checkSignatureDevice(String signatureDevice) + { + if (signatureDevice == null) + { + throw new IllegalArgumentException("The signatureDevice must not be null."); + } + if (!(signatureDevice.equals(Constants.SIGNATURE_DEVICE_BKU) || signatureDevice.equals(Constants.SIGNATURE_DEVICE_MOA))) + { + throw new IllegalArgumentException("The signatureDevice must be one of the Constants.SIGNATURE_DEVICE_* constants. " + signatureDevice); + } + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java b/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java new file mode 100644 index 0000000..a343de8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java @@ -0,0 +1,317 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.analyze.AnalyzeParameters; +import at.gv.egiz.pdfas.api.analyze.AnalyzeResult; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.commons.SignatureProfile; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.api.sign.SignResult; +import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.verify.VerifyParameters; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.gv.egiz.pdfas.api.verify.VerifyResults; +import at.gv.egiz.pdfas.commandline.CommandlineConnectorChooser; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.config.SettingsHelper; +import at.gv.egiz.pdfas.framework.input.ExtractionStage; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; +import at.gv.egiz.pdfas.impl.api.analyze.AnalyzeResultImpl; +import at.gv.egiz.pdfas.impl.api.commons.DataSinkAdapter; +import at.gv.egiz.pdfas.impl.api.commons.PdfDataSourceAdapter; +import at.gv.egiz.pdfas.impl.api.commons.SignatureInformationAdapter; +import at.gv.egiz.pdfas.impl.api.commons.SignatureProfileImpl; +import at.gv.egiz.pdfas.impl.api.commons.TextDataSourceAdapter; +import at.gv.egiz.pdfas.impl.api.sign.ActualSignaturePositionAdapter; +import at.gv.egiz.pdfas.impl.api.sign.SignResultImpl; +import at.gv.egiz.pdfas.impl.api.verify.VerifyResultAdapter; +import at.gv.egiz.pdfas.impl.api.verify.VerifyResultsImpl; +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterParametersImpl; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Implementation of the {@link PdfAs} interface. + * + * @author wprinz + */ +public class PdfAsObject implements PdfAs +{ + /** + * The work directory. + */ + protected File workDirectory = null; + + /** + * This constructor is for internal use only - use + * {@link at.gv.egiz.pdfas.PdfAsFactory} instead. + * + * @param workDirectory + * The work directory. + * @throws PdfAsException + * Thrown, if the configuration cannot be processed. + */ + public PdfAsObject(File workDirectory) throws PdfAsException + { + if (workDirectory == null) + { + throw new IllegalArgumentException("The work directory must not be null."); + } + if (!workDirectory.isDirectory()) + { + throw new IllegalArgumentException("The work directory does not exist or is not a directory. " + workDirectory.getPath()); + } + + this.workDirectory = workDirectory; + + SettingsReader.initialize(workDirectory.getPath()); + reloadConfig(); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#reloadConfig() + */ + public void reloadConfig() throws PdfAsException + { + SettingsReader.createInstance(); + SignatureTypes.createInstance(); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#getProfileInformation() + */ + public List getProfileInformation() throws PdfAsException + { + final String MOA_SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; + + SettingsReader settings = SettingsReader.getInstance(); + final String defaultMoaKeyIdentifiert = settings.getSetting(MOA_SIGN_KEY_IDENTIFIER_KEY, null); + + SignatureTypes types = SignatureTypes.getInstance(); + List profiles = types.getSignatureTypeDefinitions(); + + List profileInformation = new ArrayList(profiles.size()); + + Iterator it = profiles.iterator(); + while (it.hasNext()) + { + SignatureTypeDefinition profile = (SignatureTypeDefinition) it.next(); + + final String profileId = profile.getType(); + final String moaKeyIdentifier = settings.getSetting("sig_obj." + profileId + "." + MOA_SIGN_KEY_IDENTIFIER_KEY, defaultMoaKeyIdentifiert); + + SignatureProfile signatureProfile = new SignatureProfileImpl(profileId, moaKeyIdentifier); + profileInformation.add(signatureProfile); + } + + return profileInformation; + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#sign(at.gv.egiz.pdfas.api.sign.SignParameters) + */ + public SignResult sign(SignParameters signParameters) throws PdfAsException + { + CheckHelper.checkSignParameters(signParameters); + + PdfASID signatorId = null; + if (signParameters.getSignatureType().equals(Constants.SIGNATURE_TYPE_BINARY)) + { + signatorId = SignatorFactory.MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signParameters.getSignatureType().equals(Constants.SIGNATURE_TYPE_TEXTUAL)) + { + signatorId = SignatorFactory.MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signParameters.getSignatureType().equals(Constants.SIGNATURE_TYPE_DETACHEDTEXTUAL)) + { + signatorId = SignatorFactory.MOST_RECENT_DETACHEDTEXT_SIGNATOR_ID; + } + + TablePos pos = PosHelper.formTablePos(signParameters.getSignaturePositioning()); + + String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForSign(signParameters.getSignatureDevice()); + + SignatorInformation si = PdfAS + .signCommandline(new PdfDataSourceAdapter(signParameters.getDocument()), new DataSinkAdapter(signParameters.getOutput()), signatorId, connectorId, signParameters.getSignatureProfileId(), pos); + + return new SignResultImpl(signParameters.getOutput(), si.getSignSignatureObject().getX509Certificate(), new ActualSignaturePositionAdapter(si.getActualTablePos())); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#verify(at.gv.egiz.pdfas.api.verify.VerifyParameters) + */ + public VerifyResults verify(VerifyParameters verifyParameters) throws PdfAsException + { + CheckHelper.checkVerifyParameters(verifyParameters); + + AnalyzeParameters ap = new AnalyzeParameters(); + fillAnalyzeParametersWithVerifyParameters(ap, verifyParameters); + AnalyzeResult analyzeResult = analyze(ap); + + if (verifyParameters.getSignatureToVerify() != Constants.VERIFY_ALL) + { + if (verifyParameters.getSignatureToVerify() >= analyzeResult.getSignatures().size()) + { + throw new SignatureException(312, "The selected signature to be verified doesn't exist. " + verifyParameters.getSignatureToVerify()); + } + + Object stv = analyzeResult.getSignatures().get(verifyParameters.getSignatureToVerify()); + List selectedSignature = new ArrayList(1); + selectedSignature.add(stv); + analyzeResult = new AnalyzeResultImpl(selectedSignature); + } + + VerifyAfterAnalysisParameters vaap = new VerifyAfterAnalysisParameters(); + vaap.setAnalyzeResult(analyzeResult); + fillVerifyAfterAnalysisParametersWithVerifyParameters(vaap, verifyParameters); + return verify(vaap); + } + + + /** + * Copies all adequate parameters from the {@link VerifyParameters} to the + * {@link AnalyzeParameters}. + * + * @param ap + * The {@link AnalyzeParameters}. + * @param vp + * The {@link VerifyParameters}. + */ + protected void fillAnalyzeParametersWithVerifyParameters(AnalyzeParameters ap, VerifyParameters vp) + { + ap.setDocument(vp.getDocument()); + ap.setVerifyMode(vp.getVerifyMode()); + } + + /** + * Copies all adequate parameters from the {@link VerifyParameters} to the + * {@link VerifyAfterAnalysisParameters}. + * + * @param vaap + * The {@link VerifyAfterAnalysisParameters}. + * @param vp + * The {@link VerifyParameters}. + */ + protected void fillVerifyAfterAnalysisParametersWithVerifyParameters(VerifyAfterAnalysisParameters vaap, VerifyParameters vp) + { + vaap.setSignatureDevice(vp.getSignatureDevice()); + vaap.setVerificationTime(vp.getVerificationTime()); + vaap.setReturnHashInputData(vp.isReturnHashInputData()); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#analyze(at.gv.egiz.pdfas.api.analyze.AnalyzeParameters) + */ + public AnalyzeResult analyze(AnalyzeParameters analyzeParameters) throws PdfAsException + { + CheckHelper.checkAnalyzeParameters(analyzeParameters); + + VerificationFilterParameters parametersConfig = SettingsHelper.readVerificationFilterParametersFromSettings(); + boolean binaryOnly = parametersConfig.extractBinarySignaturesOnly(); + if (analyzeParameters.getVerifyMode().equals(Constants.VERIFY_MODE_BINARY_ONLY)) + { + binaryOnly = true; + } + boolean assumeOnlySB = parametersConfig.assumeOnlySignatureUpdateBlocks(); + if (analyzeParameters.getVerifyMode().equals(Constants.VERIFY_MODE_SEMI_CONSERVATIVE)) + { + assumeOnlySB = true; + } + if (analyzeParameters.getVerifyMode().equals(Constants.VERIFY_MODE_FULL_CONSERVATIVE)) + { + assumeOnlySB = false; + } + VerificationFilterParameters parameters = new VerificationFilterParametersImpl(binaryOnly, assumeOnlySB, parametersConfig.scanForOldSignatures()); + + at.gv.egiz.pdfas.framework.input.DataSource inputDataSource = null; + if (analyzeParameters.getDocument().getMimeType().equals("application/pdf")) + { + inputDataSource = new PdfDataSourceAdapter(analyzeParameters.getDocument()); + } + else + { + try + { + inputDataSource = new TextDataSourceAdapter(analyzeParameters.getDocument()); + } + catch (UnsupportedEncodingException e) + { + throw new PresentableException(ErrorCode.DOCUMENT_CANNOT_BE_READ, "The characterEncoding is not supported." + analyzeParameters.getDocument().getCharacterEncoding(), e); + } + } + assert inputDataSource != null; + + ExtractionStage es = new ExtractionStage(); + List signature_holders = es.extractSignatureHolders(inputDataSource, parameters); + + List sigInfs = new ArrayList(signature_holders.size()); + Iterator it = signature_holders.iterator(); + while (it.hasNext()) + { + SignatureHolder sh = (SignatureHolder)it.next(); + SignatureInformation si = new SignatureInformationAdapter(sh); + sigInfs.add(si); + } + + return new AnalyzeResultImpl(sigInfs); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#verify(at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters) + */ + public VerifyResults verify(VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) throws PdfAsException + { + CheckHelper.checkVerifyAfterAnalysisParameters(verifyAfterAnalysisParameters); + + List signatures = verifyAfterAnalysisParameters.getAnalyzeResult().getSignatures(); + List signature_holders = new ArrayList(signatures.size()); + Iterator it = signatures.iterator(); + while (it.hasNext()) + { + SignatureInformation si = (SignatureInformation) it.next(); + SignatureHolder sh = (SignatureHolder) si.getInternalSignatureInformation(); + signature_holders.add(sh); + } + assert signature_holders.size() == signatures.size(); + + List results = PdfAS.verifySignatureHolders(signature_holders, verifyAfterAnalysisParameters.getSignatureDevice(), verifyAfterAnalysisParameters.isReturnHashInputData(), verifyAfterAnalysisParameters.getVerificationTime()); + + List vrs = new ArrayList(results.size()); + + assert signature_holders.size() == results.size() : "Not all signatures were verified."; + + for (int i = 0; i < signature_holders.size(); i++) + { + SignatureResponse response = (SignatureResponse) results.get(i); + SignatureHolder holder = (SignatureHolder) signature_holders.get(i); + + VerifyResult vr = new VerifyResultAdapter(response, holder, verifyAfterAnalysisParameters.getVerificationTime()); + vrs.add(vr); + } + + return new VerifyResultsImpl(vrs); + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java new file mode 100644 index 0000000..14f081f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java @@ -0,0 +1,79 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api; + +import at.gv.egiz.pdfas.api.sign.pos.SignaturePositioning; +import at.gv.egiz.pdfas.api.sign.pos.axis.AbsoluteAxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.axis.AutoAxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.axis.AxisAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.AbsolutePageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.AutoPageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.NewPageAlgorithm; +import at.gv.egiz.pdfas.api.sign.pos.page.PageAlgorithm; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; + +/** + * @author wprinz + * + */ +public final class PosHelper +{ + /** + * Hidden default constructor. + */ + private PosHelper() + { + // empty block + } + + public static TablePos formTablePos(SignaturePositioning signaturePositioning) throws PDFDocumentException + { + if (signaturePositioning == null) + { + return null; + } + + String positioningString = formPositioningString(signaturePositioning); + TablePos pos = PdfAS.parsePositionFromPosString(positioningString); + + return pos; + } + + protected static String formPositioningString(SignaturePositioning sp) + { + String x_algo = formAxisAlgoString(sp.getXAlgorithm()); + String y_algo = formAxisAlgoString(sp.getYAlgorithm()); + String w_algo = formAxisAlgoString(sp.getWidthAlgorithm()); + String p_algo = formPageAlgoString(sp.getPageAlgorithm()); + String positioning = "x:" + x_algo + ";y:" + y_algo + ";w:" + w_algo + ";p:" + p_algo + ";f:" + sp.getFooterLine(); + return positioning; + } + + protected static String formAxisAlgoString(AxisAlgorithm algorithm) + { + if (algorithm instanceof AutoAxisAlgorithm) + { + return "auto"; + } + AbsoluteAxisAlgorithm aaa = (AbsoluteAxisAlgorithm) algorithm; + return Float.toString(aaa.getAbsoluteValue()); + } + + protected static String formPageAlgoString(PageAlgorithm algorithm) + { + if (algorithm instanceof AutoPageAlgorithm) + { + return "auto"; + } + if (algorithm instanceof NewPageAlgorithm) + { + return "new"; + } + AbsolutePageAlgorithm apa = (AbsolutePageAlgorithm) algorithm; + return Integer.toString(apa.getPage()); + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java new file mode 100644 index 0000000..87a14f0 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java @@ -0,0 +1,47 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.analyze; + +import java.util.List; + +import at.gv.egiz.pdfas.api.analyze.AnalyzeResult; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; + +/** + * Holds the result of an analyzation. + * + * @author wprinz + */ +public class AnalyzeResultImpl implements AnalyzeResult +{ + /** + * The found signatures. + */ + protected List signatures = null; + + /** + * Constructor. + * + * @param signatures + * The found signatures. + */ + public AnalyzeResultImpl(List signatures) + { + if (signatures == null) + { + throw new IllegalArgumentException("The list of found signatures must not be null."); + } + + this.signatures = signatures; + } + + /** + * @see at.gv.egiz.pdfas.api.analyze.AnalyzeResult#getSignatures() + */ + public List getSignatures() throws PdfAsException + { + return this.signatures; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java new file mode 100644 index 0000000..5744a21 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java @@ -0,0 +1,83 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.io.IOException; +import java.io.OutputStream; + +import at.gv.egiz.pdfas.api.io.DataSink; + +/** + * Adapter that converts an API DataSink to a framework DataSink. + * + * @author wprinz + */ +public class DataSinkAdapter implements at.gv.egiz.pdfas.framework.output.DataSink +{ + /** + * The API DataSink to be adapted to a framework DataSink. + */ + protected at.gv.egiz.pdfas.api.io.DataSink apiDataSink = null; + + /** + * Constructor. + * + * @param apiDataSink + * The API DataSink to be adapted to a framework DataSink. + */ + public DataSinkAdapter(DataSink apiDataSink) + { + this.apiDataSink = apiDataSink; + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String) + */ + public OutputStream createOutputStream(String mimeType) + { + try + { + return this.apiDataSink.createOutputStream(mimeType); + } + catch (IOException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String, + * java.lang.String) + */ + public OutputStream createOutputStream(String mimeType, String characterEncoding) + { + try + { + return this.apiDataSink.createOutputStream(mimeType, characterEncoding); + } + catch (IOException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.apiDataSink.getCharacterEncoding(); + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#getMimeType() + */ + public String getMimeType() + { + return this.apiDataSink.getMimeType(); + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java new file mode 100644 index 0000000..9e5495c --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java @@ -0,0 +1,85 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.io.InputStream; + +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; + +/** + * Adapter that converts a framework DataSource to an API PdfDataSource. + * + * @author wprinz + */ +public class DataSourceApiAdapter implements at.gv.egiz.pdfas.api.io.DataSource +{ + /** + * The framework DataSource to be adapted to an API DataSource. + */ + protected at.gv.egiz.pdfas.framework.input.DataSource frameworkDataSource = null; + + /** + * Constructor. + * + * @param frameworkDataSource + * The framework DataSource to be adapted to an API DataSource. + */ + public DataSourceApiAdapter(at.gv.egiz.pdfas.framework.input.DataSource frameworkDataSource) + { + this.frameworkDataSource = frameworkDataSource; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + return this.frameworkDataSource.createInputStream(); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + return this.frameworkDataSource.getAsByteArray(); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getLength() + */ + public int getLength() + { + return this.frameworkDataSource.getLength(); + } + + public String getCharacterEncoding() + { + if (this.frameworkDataSource instanceof PdfDataSource) + { + return null; + } + if (this.frameworkDataSource instanceof TextDataSource) + { + return "UTF-8"; + } + return null; + } + + public String getMimeType() + { + if (this.frameworkDataSource instanceof PdfDataSource) + { + return "application/pdf"; + } + if (this.frameworkDataSource instanceof TextDataSource) + { + return "text/plain"; + } + + return null; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java new file mode 100644 index 0000000..fbafafe --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java @@ -0,0 +1,52 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.io.InputStream; + +/** + * Adapter that converts an API DataSource to a framework PdfDataSource. + * + * @author wprinz + */ +public class PdfDataSourceAdapter implements at.gv.egiz.pdfas.framework.input.PdfDataSource +{ + /** + * The API DataSource to be adapted to a framework PdfDataSource. + */ + protected at.gv.egiz.pdfas.api.io.DataSource apiDataSource = null; + + /** + * Constructor. + * @param apiDataSource The API DataSource to be adapted to a framework PdfDataSource. + */ + public PdfDataSourceAdapter(at.gv.egiz.pdfas.api.io.DataSource apiDataSource) + { + this.apiDataSource = apiDataSource; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + return this.apiDataSource.createInputStream(); + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + return this.apiDataSource.getAsByteArray(); + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength() + */ + public int getLength() + { + return this.apiDataSource.getLength(); + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java new file mode 100644 index 0000000..875c3d9 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java @@ -0,0 +1,87 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.security.cert.X509Certificate; +import java.util.Date; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.io.DataSource; +import at.knowcenter.wag.egov.egiz.pdf.EGIZDate; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; + +/** + * Adapter that converts a framework SignatureHolder to an API + * SignatureInformation. + * + * @author wprinz + */ +public class SignatureInformationAdapter implements SignatureInformation +{ + /** + * The framework SignatureHolder to be adapted to an API SignatureInformation. + */ + protected SignatureHolder signatureHolder = null; + + /** + * Constructor. + * + * @param signatureHolder + * The framework SignatureHolder to be adapted to an API + * SignatureInformation. + */ + public SignatureInformationAdapter(SignatureHolder signatureHolder) + { + this.signatureHolder = signatureHolder; + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getSignedData() + */ + public DataSource getSignedData() + { + return new DataSourceApiAdapter(this.signatureHolder.getDataSource()); + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getInternalSignatureInformation() + */ + public Object getInternalSignatureInformation() + { + return this.signatureHolder; + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getSignatureType() + */ + public String getSignatureType() + { + if (this.signatureHolder.getSignatureObject().isBinary()) + { + return Constants.SIGNATURE_TYPE_BINARY; + } + return Constants.SIGNATURE_TYPE_TEXTUAL; + } + + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getSignerCertificate() + */ + public X509Certificate getSignerCertificate() + { + return this.signatureHolder.getSignatureObject().getX509Cert().getX509Certificate(); + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getSigningTime() + */ + public Date getSigningTime() + { + String date_value = this.signatureHolder.getSignatureObject().getSignationDate(); + Date date = EGIZDate.parseDateFromString(date_value); + return date; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java new file mode 100644 index 0000000..0d2bfdd --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java @@ -0,0 +1,56 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import at.gv.egiz.pdfas.api.commons.SignatureProfile; + +/** + * Holds the data of a signature profile. + * + * @author wprinz + */ +public class SignatureProfileImpl implements SignatureProfile +{ + + /** + * The profile identifier. + */ + protected String profileId = null; + + /** + * The MOA key identifiert of this profile. + */ + protected String moaKeyIdentifier = null; + + /** + * Constructor. + * + * @param profileId + * The profile identifier. + * @param moaKeyIdentifier + * The MOA key identifiert of this profile. + */ + public SignatureProfileImpl(String profileId, String moaKeyIdentifier) + { + this.profileId = profileId; + this.moaKeyIdentifier = moaKeyIdentifier; + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureProfile#getProfileId() + */ + public String getProfileId() + { + return this.profileId; + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureProfile#getMOAKeyIdentifier() + */ + public String getMOAKeyIdentifier() + { + return this.moaKeyIdentifier; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java new file mode 100644 index 0000000..4b34d6f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java @@ -0,0 +1,52 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.pdfas.api.io.TextBased; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; + +/** + * Adapter that converts an API DataSource to a framework TextDataSource. + * + * @author wprinz + */ +public class TextDataSourceAdapter extends TextDataSourceImpl +{ + /** + * The API DataSource to be adapted to a framework TextDataSource. + */ + protected at.gv.egiz.pdfas.api.io.DataSource apiDataSource = null; + + /** + * Constructor. + * + * @param apiDataSource + * The API DataSource to be adapted to a framework TextDataSource. + * @throws UnsupportedEncodingException + */ + public TextDataSourceAdapter(at.gv.egiz.pdfas.api.io.DataSource apiDataSource) throws UnsupportedEncodingException + { + super(null); + this.apiDataSource = apiDataSource; + + if (this.apiDataSource instanceof TextBased) + { + TextBased tb = (TextBased) this.apiDataSource; + this.text = tb.getText(); + } + else + { + byte[] data = this.apiDataSource.getAsByteArray(); + String characterEncoding = this.apiDataSource.getCharacterEncoding(); + if (characterEncoding == null) + { + throw new UnsupportedEncodingException("The characterEncoding must not be null. Specify a correct encoding."); + } + this.text = new String(data, characterEncoding); + } + assert this.text != null; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java new file mode 100644 index 0000000..a0c32aa --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java @@ -0,0 +1,73 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.sign; + +import at.gv.egiz.pdfas.api.sign.pos.SignaturePosition; +import at.knowcenter.wag.egov.egiz.pdf.ActualTablePos; + +/** + * Adapter that converts from a framework ActualTablePos to an API + * ActualSignaturePosition. + * + * @author wprinz + * + */ +public class ActualSignaturePositionAdapter implements SignaturePosition +{ + /** + * The framework ActualTablePos. + */ + protected ActualTablePos atp = null; + + /** + * Constructor. + * + * @param actualTablePos + * The framework ActualTablePos. + */ + public ActualSignaturePositionAdapter(ActualTablePos actualTablePos) + { + this.atp = actualTablePos; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.pos.SignaturePosition#getPage() + */ + public int getPage() + { + return this.atp.page; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.pos.SignaturePosition#getX() + */ + public float getX() + { + return this.atp.x; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.pos.SignaturePosition#getY() + */ + public float getY() + { + return this.atp.y; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.pos.SignaturePosition#getWidth() + */ + public float getWidth() + { + return this.atp.width; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.pos.SignaturePosition#getHeight() + */ + public float getHeight() + { + return this.atp.height; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java new file mode 100644 index 0000000..7161f5b --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java @@ -0,0 +1,75 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.sign; + +import java.security.cert.X509Certificate; + +import at.gv.egiz.pdfas.api.io.DataSink; +import at.gv.egiz.pdfas.api.sign.SignResult; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePosition; + +/** + * Implementation of the SignResult interface. + * + * @author wprinz + */ +public class SignResultImpl implements SignResult +{ + /** + * The filled output DataSink. + */ + protected DataSink outputDocument = null; + + /** + * The signer certificate. + */ + protected X509Certificate signerCertificate = null; + + /** + * The signature position. + */ + protected SignaturePosition signaturePosition = null; + + /** + * Constructor. + * + * @param outputDocument + * The filled output DataSink. + * @param signerCertificate + * The signer certificate. + * @param signaturePosition + * The signature position. + */ + public SignResultImpl(DataSink outputDocument, X509Certificate signerCertificate, SignaturePosition signaturePosition) + { + this.outputDocument = outputDocument; + this.signerCertificate = signerCertificate; + this.signaturePosition = signaturePosition; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.SignResult#getOutputDocument() + */ + public DataSink getOutputDocument() + { + return this.outputDocument; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.SignResult#getSignaturePosition() + */ + public SignaturePosition getSignaturePosition() + { + return this.signaturePosition; + } + + /** + * @see at.gv.egiz.pdfas.api.sign.SignResult#getSignerCertificate() + */ + public X509Certificate getSignerCertificate() + { + return this.signerCertificate; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java new file mode 100644 index 0000000..d5803f8 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java @@ -0,0 +1,51 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.verify; + +import at.gv.egiz.pdfas.api.verify.SignatureCheck; + +/** + * @author wprinz + */ +public class SignatureCheckImpl implements SignatureCheck +{ + /** + * The check code. + */ + protected int code = -1; + + /** + * The check code message. + */ + protected String message = null; + + + + /** + * @param code The check code. + * @param message The check code message. + */ + public SignatureCheckImpl(int code, String message) + { + this.code = code; + this.message = message; + } + + /** + * @see at.gv.egiz.pdfas.api.verify.SignatureCheck#getCode() + */ + public int getCode() + { + return this.code; + } + + /** + * @see at.gv.egiz.pdfas.api.verify.SignatureCheck#getMessage() + */ + public String getMessage() + { + return this.message; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java b/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java new file mode 100644 index 0000000..d66097a --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java @@ -0,0 +1,126 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.verify; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import at.gv.egiz.pdfas.api.verify.SignatureCheck; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.gv.egiz.pdfas.impl.api.commons.SignatureInformationAdapter; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; + +/** + * Implements the VerifyResult interface. + * + * @author wprinz + */ +public class VerifyResultAdapter extends SignatureInformationAdapter implements VerifyResult +{ + protected SignatureResponse sigRes = null; + + protected Date vTime = null; + + /** + * Constructor. + * + * @param sigRes + * The SignatureResponse. + * @param sh + * The SignatureHolder. + * @param verificationTime + * The time of verification. This is directly returned by {@link #getVerificationTime()} + */ + public VerifyResultAdapter(SignatureResponse sigRes, SignatureHolder sh, Date verificationTime) + { + super(sh); + this.sigRes = sigRes; + this.vTime = verificationTime; + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getCertificateCheck() + */ + public SignatureCheck getCertificateCheck() + { + return new SignatureCheckImpl(Integer.parseInt(this.sigRes.getCertificateCheckCode()), this.sigRes.getCertificateCheckInfo()); + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getManifestCheckCode() + */ + public SignatureCheck getManifestCheckCode() + { + return new SignatureCheckImpl(Integer.parseInt(this.sigRes.getSignatureManifestCheckCode()), this.sigRes.getSignatureManifestCheckInfo()); + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getValueCheckCode() + */ + public SignatureCheck getValueCheckCode() + { + return new SignatureCheckImpl(Integer.parseInt(this.sigRes.getSignatureCheckCode()), this.sigRes.getSignatureCheckInfo()); + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getVerificationTime() + */ + public Date getVerificationTime() + { + return this.vTime; + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#isQualifiedCertificate() + */ + public boolean isQualifiedCertificate() + { + return this.sigRes.isQualifiedCertificate(); + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getPublicProperties() + */ + public List getPublicProperties() + { + try + { + return this.sigRes.getPublicProperties(); + } + catch (SettingNotFoundException e) + { + e.printStackTrace(); + return new ArrayList(); + } + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getInternalSignatureInformation() + */ + public Object getInternalSignatureInformation() + { + return null; + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureInformation#getSignerCertificate() + */ + public X509Certificate getSignerCertificate() + { + // TODO this should be the same as the signature holder's cert. + return this.sigRes.getCertificate().getX509Certificate(); + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getHashInputData() + */ + public String getHashInputData() + { + return this.sigRes.getHashInputData(); + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java b/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java new file mode 100644 index 0000000..e7cc79d --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java @@ -0,0 +1,38 @@ +/** + * + */ +package at.gv.egiz.pdfas.impl.api.verify; + +import java.util.List; + +import at.gv.egiz.pdfas.api.verify.VerifyResults; + +/** + * @author wprinz + */ +public class VerifyResultsImpl implements VerifyResults +{ + /** + * The results. + */ + protected List results = null; + + /** + * Constructor. + * + * @param results + * The results. + */ + public VerifyResultsImpl(List results) + { + this.results = results; + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResults#getResults() + */ + public List getResults() + { + return this.results; + } +} diff --git a/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java index 138b269..2a3fedd 100644 --- a/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java +++ b/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java @@ -75,6 +75,17 @@ public class DataSourceHelper { try { + return convertInputStreamToByteArrayIOEx(inputStream); + } + catch (IOException e) + { + log.error(e); + throw new RuntimeException(e); + } + } + + public static byte [] convertInputStreamToByteArrayIOEx(InputStream inputStream) throws IOException + { PerformanceCounters.byteArrays.increment(); ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); @@ -92,12 +103,6 @@ public class DataSourceHelper byte [] data = baos.toByteArray(); return data; - } - catch (IOException e) - { - log.error(e); - throw new RuntimeException(e); - } } public static void debugDataSourceToFile(DataSource dataSource, File file) diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java index a95cdc6..f308e30 100644 --- a/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java @@ -32,14 +32,14 @@ public final class IncrementalUpdateHelper return iui; } - public static void writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, PositioningInstruction pi) throws PresentableException + public static IncrementalUpdateInformation writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, PositioningInstruction pi) throws PresentableException { - writeIncrementalUpdateToDataSink(pdfDataSource, dataSink, pdf_table, pi, null, null); + return writeIncrementalUpdateToDataSink(pdfDataSource, dataSink, pdf_table, pi, null, null); } - public static void writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, PositioningInstruction pi, List variable_field_definitions, + public static IncrementalUpdateInformation writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, PositioningInstruction pi, List variable_field_definitions, List all_field_definitions) throws PresentableException { - BinarySignature.writeIncrementalUpdate(pdfDataSource, dataSink, pdf_table, pi, variable_field_definitions, all_field_definitions); + return BinarySignature.writeIncrementalUpdate(pdfDataSource, dataSink, pdf_table, pi, variable_field_definitions, all_field_definitions); } } diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java index 916abf4..0ed3699 100644 --- a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java @@ -5,6 +5,7 @@ package at.gv.egiz.pdfas.impl.signator.binary; import java.util.List; +import at.knowcenter.wag.egov.egiz.pdf.ActualTablePos; import at.knowcenter.wag.egov.egiz.sig.SignatureData; import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; import at.gv.egiz.pdfas.framework.input.PdfDataSource; @@ -31,6 +32,8 @@ public class BinarySignatorInformation implements SignatorInformation protected int enc_length = -1; protected SignSignatureObject signSignatureObject = null; + + protected ActualTablePos atp = null; /** * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData() @@ -48,4 +51,20 @@ public class BinarySignatorInformation implements SignatorInformation this.signSignatureObject = signSignatureObject; } + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignSignatureObject() + */ + public SignSignatureObject getSignSignatureObject() + { + return this.signSignatureObject; + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getActualTablePos() + */ + public ActualTablePos getActualTablePos() + { + return this.atp; + } + } diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java index b1f1cea..73d4866 100644 --- a/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java @@ -296,6 +296,7 @@ public class BinarySignator_1_0_0 implements Signator bsi.cert_length = iui.cert_length; bsi.enc_start = iui.enc_start; bsi.enc_length = iui.enc_length; + bsi.atp = iui.actualTablePos; return bsi; } @@ -312,6 +313,7 @@ public class BinarySignator_1_0_0 implements Signator iui.cert_length = bsi.cert_length; iui.enc_start = bsi.enc_start; iui.enc_length = bsi.enc_length; + iui.actualTablePos = bsi.atp; iui.signed_signature_object = bsi.signSignatureObject; diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java index c5b18ff..9e5ebb6 100644 --- a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java @@ -3,6 +3,7 @@ */ package at.gv.egiz.pdfas.impl.signator.textual; +import at.knowcenter.wag.egov.egiz.pdf.ActualTablePos; import at.knowcenter.wag.egov.egiz.pdf.TablePos; import at.knowcenter.wag.egov.egiz.sig.SignatureData; import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; @@ -24,6 +25,8 @@ public class TextualSignatorInformation implements SignatorInformation protected TablePos pos = null; public SignSignatureObject signSignatureObject = null; + + protected ActualTablePos atp = null; /** * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData() @@ -34,7 +37,6 @@ public class TextualSignatorInformation implements SignatorInformation } /** - * * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#setSignSignatureObject(at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) */ public void setSignSignatureObject(SignSignatureObject signSignatureObject) @@ -42,4 +44,19 @@ public class TextualSignatorInformation implements SignatorInformation this.signSignatureObject = signSignatureObject; } + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignSignatureObject() + */ + public SignSignatureObject getSignSignatureObject() + { + return this.signSignatureObject; + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getActualTablePos() + */ + public ActualTablePos getActualTablePos() + { + return this.atp; + } } diff --git a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java index 1714afc..b49803c 100644 --- a/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java +++ b/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java @@ -29,6 +29,7 @@ import at.knowcenter.wag.egov.egiz.PdfAS; import at.knowcenter.wag.egov.egiz.PdfASID; import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; import at.knowcenter.wag.egov.egiz.pdf.TablePos; import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; @@ -127,7 +128,8 @@ public class TextualSignator_1_0_0 implements Signator PositioningInstruction pi = PdfAS.determineTablePositioning(tsi.pos, tsi.profile, tsi.originalDocument, pdf_table); - IncrementalUpdateHelper.writeIncrementalUpdateToDataSink(tsi.originalDocument, dataSink, pdf_table, pi); + IncrementalUpdateInformation iui = IncrementalUpdateHelper.writeIncrementalUpdateToDataSink(tsi.originalDocument, dataSink, pdf_table, pi); + tsi.atp = iui.actualTablePos; // OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE); // os.write(signed_iui.signed_pdf); diff --git a/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java b/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java new file mode 100644 index 0000000..bf74ed5 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java @@ -0,0 +1,87 @@ +/** + * + */ +package at.gv.egiz.pdfas.io; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import at.gv.egiz.pdfas.api.io.DataSink; + +/** + * @author wprinz + * + */ +public class ByteArrayDataSink implements DataSink +{ + /** + * The byte output stream. + */ + ByteArrayOutputStream baos = null; + + /** + * The mime type. + */ + protected String mimeType = null; + + /** + * The character encoding. + */ + protected String characterEncoding = null; + + /** + * @see at.gv.egiz.pdfas.api.io.DataSink#createOutputStream(java.lang.String) + */ + public OutputStream createOutputStream(String mimeType) throws IOException + { + return createOutputStream(mimeType, null); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSink#createOutputStream(java.lang.String, + * java.lang.String) + */ + public OutputStream createOutputStream(String mimeType, String characterEncoding) throws IOException + { + this.mimeType = mimeType; + this.characterEncoding = characterEncoding; + this.baos = new ByteArrayOutputStream(); + return this.baos; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSink#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSink#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + + /** + * Returns the byte data, or null if none available. + * + *

+ * Note that internally, this just calls the {@link ByteArrayOutputStream#toByteArray()} method. + *

+ * + * @return Returns the byte data, or null if none available. + */ + public byte [] getData() + { + if (this.baos == null) + { + return null; + } + return this.baos.toByteArray(); + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java b/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java new file mode 100644 index 0000000..37726df --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java @@ -0,0 +1,95 @@ +/** + * + */ +package at.gv.egiz.pdfas.io; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import at.gv.egiz.pdfas.api.io.DataSource; + +/** + * A byte array backed DataSource. + * + * @author wprinz + */ +public class ByteArrayDataSource implements DataSource +{ + + /** + * The byte array. + */ + protected byte[] data = null; + + /** + * The mime type. + */ + protected String mimeType = null; + + /** + * The character encoding. + */ + protected String characterEncoding = null; + + /** + * @param data + * @param mimeType + */ + public ByteArrayDataSource(byte[] data, String mimeType) + { + this(data, mimeType, null); + } + + /** + * @param data + * @param mimeType + * @param characterEncoding + */ + public ByteArrayDataSource(byte[] data, String mimeType, String characterEncoding) + { + this.data = data; + this.mimeType = mimeType; + this.characterEncoding = characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + return new ByteArrayInputStream(this.data); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + return this.data; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getLength() + */ + public int getLength() + { + return this.data.length; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java b/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java new file mode 100644 index 0000000..184dd09 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java @@ -0,0 +1,96 @@ +/** + * + */ +package at.gv.egiz.pdfas.io; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import at.gv.egiz.pdfas.api.io.DataSink; +import at.gv.egiz.pdfas.api.io.FileBased; + +/** + * @author wprinz + * + */ +public class FileBasedDataSink implements DataSink, FileBased +{ + protected File file = null; + + protected String mimeType = null; + + protected String characterEncoding = null; + + + + /** + * @param file + * @throws IOException + */ + public FileBasedDataSink(File file) throws IOException + { + if (!file.exists()) + { + file.createNewFile(); + } + if (!file.isFile()) + { + throw new IOException("The file '" + file + "' is not a normal file."); + } + if (!file.canWrite()) + { + throw new IOException("The file '" + file + "' cannot be written."); + } + + this.file = file; + } + + /** + * @throws FileNotFoundException + * @see at.gv.egiz.pdfas.api.io.DataSink#createOutputStream(java.lang.String) + */ + public OutputStream createOutputStream(String mimeType) throws FileNotFoundException + { + return createOutputStream(mimeType, null); + } + + /** + * @throws FileNotFoundException + * @see at.gv.egiz.pdfas.api.io.DataSink#createOutputStream(java.lang.String, + * java.lang.String) + */ + public OutputStream createOutputStream(String mimeType, String characterEncoding) throws FileNotFoundException + { + this.mimeType = mimeType; + this.characterEncoding = characterEncoding; + return new FileOutputStream(this.file); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSink#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSink#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.api.io.FileBased#getFile() + */ + public File getFile() + { + return this.file; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java b/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java new file mode 100644 index 0000000..fd56bfe --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java @@ -0,0 +1,121 @@ +/** + * + */ +package at.gv.egiz.pdfas.io; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.io.FileBased; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; + +/** + * A FileBased DataSource implementation. + * + * @author wprinz + */ +public class FileBasedDataSource implements DataSource, FileBased +{ + protected File file = null; + + protected String mimeType = null; + + protected String characterEncoding = null; + + protected byte[] cache = null; + + /** + * @param file + * @param mimeType + * @throws IOException + */ + public FileBasedDataSource(File file, String mimeType) throws IOException + { + this(file, mimeType, null); + } + + /** + * @param file + * @param mimeType + * @param characterEncoding + * @throws IOException + */ + public FileBasedDataSource(File file, String mimeType, String characterEncoding) throws IOException + { + if (file == null) + { + throw new IllegalArgumentException("The file must not be null."); + } + if (mimeType == null) + { + throw new IllegalArgumentException("The mimeType must not be null."); + } + if (!file.exists()) + { + throw new FileNotFoundException("The file '" + file + "' does not exist."); + } + if (!file.canRead()) + { + throw new IOException("The file '" + file + "' cannot be read."); + } + + this.file = file; + this.mimeType = mimeType; + this.characterEncoding = characterEncoding; + this.cache = DataSourceHelper.convertInputStreamToByteArrayIOEx(new FileInputStream(this.file)); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + return new ByteArrayInputStream(this.cache); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + return this.cache; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getLength() + */ + public int getLength() + { + return this.cache.length; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.api.io.FileBased#getFile() + */ + public File getFile() + { + return this.file; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java b/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java new file mode 100644 index 0000000..5be2148 --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java @@ -0,0 +1,103 @@ +/** + * + */ +package at.gv.egiz.pdfas.io; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.pdfas.api.io.TextBased; + +/** + * FileBased DataSource that is TextBased. + * + * @author wprinz + */ +public class FileBasedTextBasedDataSource extends FileBasedDataSource implements TextBased +{ + protected String text = null; + + /** + * @param file + * @param mimeType + * @param characterEncoding + * @throws IOException + */ + public FileBasedTextBasedDataSource(File file, String mimeType, String characterEncoding) throws IOException + { + super(file, mimeType, characterEncoding); + if (characterEncoding == null) + { + throw new IllegalArgumentException("The characterEncoding must not be null."); + } + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + return new ByteArrayInputStream(this.cache); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + return this.cache; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getLength() + */ + public int getLength() + { + return this.cache.length; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.api.io.FileBased#getFile() + */ + public File getFile() + { + return this.file; + } + + public String getText() + { + if (this.text == null) + { + try + { + this.text = new String(this.cache, this.characterEncoding); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + return this.text; + } + +} diff --git a/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java b/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java new file mode 100644 index 0000000..d8b879f --- /dev/null +++ b/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java @@ -0,0 +1,96 @@ +/** + * + */ +package at.gv.egiz.pdfas.io; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.io.TextBased; + +/** + * A String TextBased DataSource. + * + * @author wprinz + * + */ +public class StringTextBasedDataSource implements DataSource, TextBased +{ + /** + * The text. + */ + protected String text = null; + + protected byte[] cache = null; + + /** + * @param text + */ + public StringTextBasedDataSource(String text) + { + this.text = text; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + return new ByteArrayInputStream(getAsByteArray()); + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + if (cache == null) + { + try + { + this.cache = this.text.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + return this.cache; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getLength() + */ + public int getLength() + { + return getAsByteArray().length; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getMimeType() + */ + public String getMimeType() + { + return "text/plain"; + } + + /** + * @see at.gv.egiz.pdfas.api.io.DataSource#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return "UTF-8"; + } + + /** + * @see at.gv.egiz.pdfas.api.io.TextBased#getText() + */ + public String getText() + { + return this.text; + } + +} -- cgit v1.2.3