From 535a04fa05f739ec16dd81666e3b0f82dfbd442d Mon Sep 17 00:00:00 2001 From: tknall Date: Wed, 9 Jan 2013 15:41:29 +0000 Subject: pdf-as-lib maven project files moved to pdf-as-lib git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/pdf-as/trunk@926 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../main/java/at/gv/egiz/pdfas/PdfAsFactory.java | 124 ++ .../egiz/pdfas/algorithmSuite/AlgorithmMapper.java | 143 ++ .../pdfas/algorithmSuite/AlgorithmSuiteObject.java | 183 ++ .../pdfas/algorithmSuite/AlgorithmSuiteUtil.java | 230 +++ .../src/main/java/at/gv/egiz/pdfas/api/PdfAs.java | 285 +++ .../egiz/pdfas/api/analyze/AnalyzeParameters.java | 107 + .../gv/egiz/pdfas/api/analyze/AnalyzeResult.java | 63 + .../egiz/pdfas/api/analyze/NonTextObjectInfo.java | 99 + .../at/gv/egiz/pdfas/api/commons/Constants.java | 185 ++ .../api/commons/DynamicSignatureLifetimeEnum.java | 72 + .../pdfas/api/commons/DynamicSignatureProfile.java | 125 ++ .../api/commons/DynamicSignatureProfileImpl.java | 215 ++ .../pdfas/api/commons/SignatureInformation.java | 129 ++ .../egiz/pdfas/api/commons/SignatureProfile.java | 76 + .../pdfas/api/exceptions/ConfigUtilsException.java | 122 ++ .../egiz/pdfas/api/exceptions/PdfAsException.java | 98 + .../gv/egiz/pdfas/api/internal/LocalBKUParams.java | 64 + .../gv/egiz/pdfas/api/internal/PdfAsInternal.java | 163 ++ .../gv/egiz/pdfas/api/internal/SignatureEntry.java | 137 ++ .../java/at/gv/egiz/pdfas/api/io/DataSink.java | 98 + .../java/at/gv/egiz/pdfas/api/io/DataSource.java | 94 + .../java/at/gv/egiz/pdfas/api/io/FileBased.java | 51 + .../java/at/gv/egiz/pdfas/api/io/TextBased.java | 50 + .../at/gv/egiz/pdfas/api/sign/SignParameters.java | 393 ++++ .../java/at/gv/egiz/pdfas/api/sign/SignResult.java | 84 + .../pdfas/api/sign/SignatureDetailInformation.java | 147 ++ .../egiz/pdfas/api/sign/pos/SignaturePosition.java | 72 + .../pdfas/api/sign/pos/SignaturePositioning.java | 296 +++ .../api/sign/pos/axis/AbsoluteAxisAlgorithm.java | 62 + .../pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java | 41 + .../pdfas/api/sign/pos/axis/AxisAlgorithm.java | 41 + .../api/sign/pos/page/AbsolutePageAlgorithm.java | 64 + .../pdfas/api/sign/pos/page/AutoPageAlgorithm.java | 47 + .../pdfas/api/sign/pos/page/NewPageAlgorithm.java | 41 + .../pdfas/api/sign/pos/page/PageAlgorithm.java | 41 + .../egiz/pdfas/api/timestamp/DummyTimeStamper.java | 62 + .../gv/egiz/pdfas/api/timestamp/TimeStamper.java | 41 + .../gv/egiz/pdfas/api/verify/SignatureCheck.java | 51 + .../api/verify/VerifyAfterAnalysisParameters.java | 166 ++ .../VerifyAfterReconstructXMLDsigParameters.java | 169 ++ .../gv/egiz/pdfas/api/verify/VerifyParameters.java | 249 +++ .../at/gv/egiz/pdfas/api/verify/VerifyResult.java | 179 ++ .../at/gv/egiz/pdfas/api/verify/VerifyResults.java | 48 + .../api/xmldsig/ExtendedSignatureInformation.java | 69 + .../ReconstructXMLDsigAfterAnalysisParameters.java | 86 + .../api/xmldsig/ReconstructXMLDsigParameters.java | 218 ++ .../api/xmldsig/ReconstructXMLDsigResult.java | 74 + .../at/gv/egiz/pdfas/api/xmldsig/XMLDsigData.java | 83 + .../commandline/CommandlineConnectorChooser.java | 199 ++ .../java/at/gv/egiz/pdfas/commandline/Main.java | 1275 ++++++++++++ .../at/gv/egiz/pdfas/exceptions/ErrorCode.java | 101 + .../gv/egiz/pdfas/exceptions/ErrorCodeHelper.java | 119 ++ .../external/ExternalErrorException.java | 66 + .../exceptions/framework/CorrectorException.java | 56 + .../framework/PlaceholderExtractionException.java | 79 + .../exceptions/framework/SignatorException.java | 60 + .../framework/VerificationFilterException.java | 60 + .../framework/VerificatorFactoryException.java | 69 + .../exceptions/pdf/CaptionNotFoundException.java | 75 + .../exceptions/pdf/KZSettingNotFoundException.java | 47 + .../exceptions/web/SessionExpiredException.java | 68 + .../gv/egiz/pdfas/framework/ConnectorFactory.java | 107 + .../egiz/pdfas/framework/ConnectorParameters.java | 118 ++ .../at/gv/egiz/pdfas/framework/DataManager.java | 55 + .../gv/egiz/pdfas/framework/DataSourceHolder.java | 45 + .../at/gv/egiz/pdfas/framework/DataStrategy.java | 57 + .../gv/egiz/pdfas/framework/SignatorFactory.java | 131 ++ .../pdfas/framework/SignatureHolderHelper.java | 57 + .../egiz/pdfas/framework/VerificatorFactory.java | 65 + .../pdfas/framework/config/SettingsHelper.java | 81 + .../gv/egiz/pdfas/framework/input/DataSource.java | 70 + .../pdfas/framework/input/ExtractionStage.java | 90 + .../egiz/pdfas/framework/input/PdfDataSource.java | 41 + .../pdfas/framework/input/PdfDataSourceHolder.java | 49 + .../egiz/pdfas/framework/input/TextDataSource.java | 39 + .../framework/input/correction/Corrector.java | 61 + .../input/correction/CorrectorFactory.java | 63 + .../gv/egiz/pdfas/framework/output/DataSink.java | 42 + .../sigdevice/SequentialSignatureDevice.java | 45 + .../pdfas/framework/sigdevice/SignatureDevice.java | 36 + .../gv/egiz/pdfas/framework/signator/Signator.java | 71 + .../framework/signator/SignatorInformation.java | 99 + .../pdfas/framework/verificator/Verificator.java | 61 + .../framework/vfilter/VerificationFilter.java | 72 + .../vfilter/VerificationFilterParameters.java | 105 + .../at/gv/egiz/pdfas/impl/api/CheckHelper.java | 284 +++ .../at/gv/egiz/pdfas/impl/api/PdfAsObject.java | 865 ++++++++ .../java/at/gv/egiz/pdfas/impl/api/PosHelper.java | 99 + .../pdfas/impl/api/analyze/AnalyzeResultImpl.java | 116 ++ .../pdfas/impl/api/commons/DataSinkAdapter.java | 103 + .../impl/api/commons/DataSourceApiAdapter.java | 105 + .../impl/api/commons/PdfDataSourceAdapter.java | 72 + .../api/commons/SignatureInformationAdapter.java | 133 ++ .../impl/api/commons/SignatureProfileImpl.java | 158 ++ .../api/commons/TextBasedDataSourceApiAdapter.java | 92 + .../impl/api/commons/TextDataSourceAdapter.java | 72 + .../impl/api/internal/PdfAsInternalObject.java | 362 ++++ .../api/sign/ActualSignaturePositionAdapter.java | 93 + .../egiz/pdfas/impl/api/sign/SignResultImpl.java | 115 ++ .../api/sign/SignatureDetailInformationImpl.java | 190 ++ .../pdfas/impl/api/verify/SignatureCheckImpl.java | 71 + .../pdfas/impl/api/verify/VerifyResultAdapter.java | 205 ++ .../pdfas/impl/api/verify/VerifyResultsImpl.java | 60 + .../impl/input/ByteArrayPdfDataSourceImpl.java | 85 + .../impl/input/CompoundPdfDataSourceImpl.java | 85 + .../pdfas/impl/input/DelimitedInputStream.java | 125 ++ .../pdfas/impl/input/DelimitedPdfDataSource.java | 82 + .../at/gv/egiz/pdfas/impl/input/FileBased.java | 40 + .../impl/input/FileBasedPdfDataSourceImpl.java | 150 ++ .../impl/input/FileBasedTextDataSourceImpl.java | 160 ++ .../pdfas/impl/input/IncrementalUpdateParser.java | 92 + .../egiz/pdfas/impl/input/TextDataSourceImpl.java | 120 ++ .../impl/input/correction/ExternalCorrector.java | 283 +++ .../impl/input/correction/InternalCorrector.java | 82 + .../pdfas/impl/input/helper/DataSourceHelper.java | 148 ++ .../egiz/pdfas/impl/output/ByteArrayDataSink.java | 106 + .../egiz/pdfas/impl/output/FileBasedDataSink.java | 145 ++ .../impl/signator/IncrementalUpdateHelper.java | 74 + .../impl/signator/SignatorInformationImpl.java | 40 + .../signator/binary/BinarySignatorInformation.java | 104 + .../impl/signator/binary/BinarySignator_1_0_0.java | 598 ++++++ .../impl/signator/binary/BinarySignator_1_1_0.java | 77 + .../detached/DetachedTextualSignator_1_0_0.java | 150 ++ .../textual/TextualSignatorInformation.java | 96 + .../signator/textual/TextualSignator_1_0_0.java | 212 ++ .../signator/textual/TextualSignator_1_1_0.java | 53 + .../signator/textual/TextualSignator_1_2_0.java | 53 + .../binary/BinaryVerificator_1_0_0.java | 453 +++++ .../binary/BinaryVerificator_1_1_0.java | 44 + .../at/gv/egiz/pdfas/impl/vfilter/Partition.java | 29 + .../pdfas/impl/vfilter/VerificationFilterImpl.java | 964 +++++++++ .../vfilter/VerificationFilterParametersImpl.java | 98 + .../helper/VerificationFilterBinaryHelper.java | 190 ++ .../vfilter/helper/VerificationFilterHelper.java | 162 ++ .../helper/VerificationFilterTextHelper.java | 35 + .../impl/vfilter/partition/BinaryPartition.java | 39 + .../impl/vfilter/partition/TextPartition.java | 40 + .../pdfas/impl/xmldsig/XMLDsigReconstructor.java | 76 + .../at/gv/egiz/pdfas/io/ByteArrayDataSink.java | 107 + .../at/gv/egiz/pdfas/io/ByteArrayDataSource.java | 115 ++ .../at/gv/egiz/pdfas/io/FileBasedDataSink.java | 116 ++ .../at/gv/egiz/pdfas/io/FileBasedDataSource.java | 141 ++ .../pdfas/io/FileBasedTextBasedDataSource.java | 123 ++ .../egiz/pdfas/io/StringTextBasedDataSource.java | 116 ++ .../egiz/pdfas/performance/PerformanceCounter.java | 82 + .../pdfas/performance/PerformanceCounters.java | 42 + .../egiz/pdfas/performance/PerformanceTimer.java | 68 + .../placeholder/SignaturePlaceholderContext.java | 72 + .../placeholder/SignaturePlaceholderData.java | 152 ++ .../placeholder/SignaturePlaceholderExtractor.java | 350 ++++ .../java/at/gv/egiz/pdfas/test/JarExtractTest.java | 51 + .../java/at/gv/egiz/pdfas/utils/ConfigUtils.java | 318 +++ .../java/at/gv/egiz/pdfas/utils/DataHashUtils.java | 156 ++ .../main/java/at/gv/egiz/pdfas/utils/OgnlUtil.java | 209 ++ .../java/at/gv/egiz/pdfas/utils/PDFASUtils.java | 92 + .../main/java/at/gv/egiz/pdfas/utils/PdfAUtil.java | 66 + .../java/at/gv/egiz/pdfas/utils/StreamUtils.java | 66 + .../java/at/gv/egiz/pdfas/utils/TempDirHelper.java | 377 ++++ .../java/at/knowcenter/wag/egov/egiz/PdfAS.java | 1575 ++++++++++++++ .../java/at/knowcenter/wag/egov/egiz/PdfASID.java | 222 ++ .../knowcenter/wag/egov/egiz/cfg/ConfigLogger.java | 79 + .../wag/egov/egiz/cfg/OverridePropertyHolder.java | 86 + .../knowcenter/wag/egov/egiz/cfg/PropertyTree.java | 358 ++++ .../at/knowcenter/wag/egov/egiz/cfg/Settings.java | 63 + .../wag/egov/egiz/cfg/SettingsReader.java | 905 +++++++++ .../knowcenter/wag/egov/egiz/commandline/Main.java | 1149 +++++++++++ .../egov/egiz/exceptions/ConnectorException.java | 72 + .../egiz/exceptions/ConnectorFactoryException.java | 74 + .../egov/egiz/exceptions/ErrorCodeException.java | 318 +++ .../egov/egiz/exceptions/InvalidIDException.java | 55 + .../egov/egiz/exceptions/NormalizeException.java | 62 + .../egov/egiz/exceptions/OutOfMemoryException.java | 42 + .../egov/egiz/exceptions/PDFDocumentException.java | 70 + .../egov/egiz/exceptions/PlaceholderException.java | 66 + .../egov/egiz/exceptions/PresentableException.java | 68 + .../egiz/exceptions/SettingNotFoundException.java | 77 + .../egov/egiz/exceptions/SettingsException.java | 74 + .../egiz/exceptions/SignatorFactoryException.java | 47 + .../egov/egiz/exceptions/SignatureException.java | 79 + .../egiz/exceptions/SignatureTypesException.java | 75 + .../wag/egov/egiz/exceptions/WebException.java | 72 + .../wag/egov/egiz/framework/FoundBlock.java | 230 +++ .../wag/egov/egiz/framework/FoundKey.java | 104 + .../wag/egov/egiz/framework/SignResult.java | 104 + .../wag/egov/egiz/framework/Signator.java | 93 + .../wag/egov/egiz/framework/SignatorFactory.java | 226 +++ .../egov/egiz/framework/VerificationFilter.java | 569 ++++++ .../wag/egov/egiz/framework/Verificator.java | 62 + .../framework/signators/BinarySignator_1_0_0.java | 285 +++ .../framework/signators/BinarySignator_1_1_0.java | 83 + .../signators/DetachedSignator_1_0_0.java | 125 ++ .../signators/DetachedfTextualSignator_1_0_0.java | 133 ++ .../framework/signators/TextualSignator_1_0_0.java | 136 ++ .../framework/signators/TextualSignator_1_1_0.java | 53 + .../verificators/BinaryVerificator_1_0_0.java | 396 ++++ .../verificators/BinaryVerificator_1_1_0.java | 44 + .../verificators/TextualVerificator_1_0_0.java | 147 ++ .../verificators/TextualVerificator_pdfasold.java | 106 + .../wag/egov/egiz/ldap/api/LDAPAPIException.java | 77 + .../wag/egov/egiz/ldap/api/LDAPAPIFactory.java | 55 + .../wag/egov/egiz/ldap/api/LDAPAPIFactoryImpl.java | 92 + .../wag/egov/egiz/ldap/api/LDAPAPIImpl.java | 148 ++ .../wag/egov/egiz/ldap/client/LDAPClient.java | 88 + .../egov/egiz/ldap/client/LDAPClientFactory.java | 102 + .../egiz/ldap/client/LDAPClientFactoryImpl.java | 118 ++ .../wag/egov/egiz/ldap/client/LDAPClientImpl.java | 214 ++ .../wag/egov/egiz/ldap/client/LDAPException.java | 50 + .../egiz/ldap/client/LDAPIssuerNameFilter.java | 43 + .../wag/egov/egiz/ldap/client/LDAPMapping.java | 181 ++ .../egov/egiz/ldap/client/LDAPMappingStore.java | 102 + .../wag/egov/egiz/pdf/AbsoluteTextSignature.java | 956 +++++++++ .../wag/egov/egiz/pdf/ActualTablePos.java | 42 + .../wag/egov/egiz/pdf/AdobeSignatureHelper.java | 272 +++ .../wag/egov/egiz/pdf/BinaryBlockInfo.java | 61 + .../wag/egov/egiz/pdf/BinarySignature.java | 2145 ++++++++++++++++++++ .../wag/egov/egiz/pdf/BinarySignatureHolder.java | 185 ++ .../at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java | 284 +++ .../egiz/pdf/IncrementalUpdateInformation.java | 252 +++ .../wag/egov/egiz/pdf/NoSignatureHolder.java | 84 + .../wag/egov/egiz/pdf/ObjectExtractor.java | 233 +++ .../at/knowcenter/wag/egov/egiz/pdf/PDFPage.java | 377 ++++ .../wag/egov/egiz/pdf/PDFSignatureCreation.java | 176 ++ .../wag/egov/egiz/pdf/PDFSignatureObject.java | 56 + .../wag/egov/egiz/pdf/PDFSignatureObjectIText.java | 618 ++++++ .../knowcenter/wag/egov/egiz/pdf/PDFUtilities.java | 148 ++ .../knowcenter/wag/egov/egiz/pdf/Placeholder.java | 572 ++++++ .../java/at/knowcenter/wag/egov/egiz/pdf/Pos.java | 70 + .../wag/egov/egiz/pdf/PositioningInstruction.java | 139 ++ .../knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java | 93 + .../wag/egov/egiz/pdf/SignatureHolder.java | 76 + .../knowcenter/wag/egov/egiz/pdf/SplitStrings.java | 177 ++ .../knowcenter/wag/egov/egiz/pdf/StringInfo.java | 106 + .../wag/egov/egiz/pdf/StructContentHelper.java | 716 +++++++ .../at/knowcenter/wag/egov/egiz/pdf/TablePos.java | 262 +++ .../wag/egov/egiz/pdf/TextualSignature.java | 282 +++ .../wag/egov/egiz/pdf/TextualSignatureHolder.java | 153 ++ .../at/knowcenter/wag/egov/egiz/pdf/Utils.java | 124 ++ .../at/knowcenter/wag/egov/egiz/sig/Connector.java | 67 + .../wag/egov/egiz/sig/ConnectorFactory.java | 372 ++++ .../wag/egov/egiz/sig/ConnectorInformation.java | 97 + .../knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java | 100 + .../at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java | 50 + .../wag/egov/egiz/sig/LocalConnector.java | 127 ++ .../wag/egov/egiz/sig/SignatureBlock.java | 316 +++ .../wag/egov/egiz/sig/SignatureData.java | 82 + .../wag/egov/egiz/sig/SignatureDataImpl.java | 130 ++ .../wag/egov/egiz/sig/SignatureEntry.java | 163 ++ .../egov/egiz/sig/SignatureFieldDefinition.java | 88 + .../wag/egov/egiz/sig/SignatureObject.java | 2108 +++++++++++++++++++ .../wag/egov/egiz/sig/SignatureResponse.java | 559 +++++ .../wag/egov/egiz/sig/SignatureSeparator.java | 146 ++ .../wag/egov/egiz/sig/SignatureTypeDefinition.java | 605 ++++++ .../wag/egov/egiz/sig/SignatureTypes.java | 515 +++++ .../at/knowcenter/wag/egov/egiz/sig/X509Cert.java | 490 +++++ .../wag/egov/egiz/sig/connectors/A1Connector.java | 63 + .../wag/egov/egiz/sig/connectors/BKUConnector.java | 896 ++++++++ .../egiz/sig/connectors/BKUPostConnection.java | 157 ++ .../wag/egov/egiz/sig/connectors/Connector.java | 77 + .../egov/egiz/sig/connectors/ConnectorChooser.java | 353 ++++ .../sig/connectors/ConnectorConfigurationKeys.java | 55 + .../egiz/sig/connectors/ConnectorEnvironment.java | 52 + .../egov/egiz/sig/connectors/LocalConnector.java | 91 + .../wag/egov/egiz/sig/connectors/MOAConnector.java | 921 +++++++++ .../egov/egiz/sig/connectors/TemplateReplaces.java | 172 ++ .../egov/egiz/sig/connectors/bku/BKUHelper.java | 695 +++++++ .../egiz/sig/connectors/bku/BKUPostConnection.java | 179 ++ .../sig/connectors/bku/DetachedBKUConnector.java | 823 ++++++++ .../bku/EnvelopedBase64BKUConnector.java | 666 ++++++ .../connectors/bku/LocRefDetachedBKUConnector.java | 46 + .../bku/MultipartDetachedBKUConnector.java | 42 + .../bku/OldEnvelopingBase64BKUConnector.java | 135 ++ .../sig/connectors/bku/SignSignatureObject.java | 272 +++ .../connectors/bku/SignSignatureObjectHelper.java | 76 + .../connectors/moa/DetachedLocRefMOAConnector.java | 661 ++++++ .../moa/EnvelopingBase64MOAConnector.java | 638 ++++++ .../egov/egiz/sig/connectors/moa/FilePartMR.java | 152 ++ .../egov/egiz/sig/connectors/moa/MOAHelper.java | 228 +++ .../egiz/sig/connectors/moa/MOASoapConnection.java | 277 +++ .../moa/MOASoapWithAttachmentConnector.java | 745 +++++++ .../sig/connectors/moa/MultipartRelatedEntity.java | 79 + .../egov/egiz/sig/connectors/moa/StringPartMR.java | 189 ++ .../mocca/LocRefDetachedMOCCAConnector.java | 623 ++++++ .../egiz/sig/connectors/mocca/MOCCAHelper.java | 223 ++ .../egov/egiz/sig/sigid/DetachedIdFormatter.java | 101 + .../sig/sigid/DetachedLocRefMOAIdFormatter.java | 80 + .../egiz/sig/sigid/DetachedMOCIdFormatter.java | 78 + .../wag/egov/egiz/sig/sigid/HotfixIdFormatter.java | 74 + .../wag/egov/egiz/sig/sigid/IdFormatter.java | 34 + .../wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java | 42 + .../wag/egov/egiz/sig/sigid/SimpleIdFormatter.java | 48 + .../wag/egov/egiz/sig/sigkz/SigKZIDHelper.java | 262 +++ .../signaturelayout/SignatureLayoutHandler.java | 45 + .../SignatureLayoutHandlerFactory.java | 147 ++ .../atrust/ATrustSignatureLayoutHandler.java | 47 + .../mocca/MOCCASignatureLayout10Handler.java | 48 + .../mocca/OldMOCCASignatureLayoutHandler.java | 48 + .../td/TrustDeskSignatureLayoutHandler.java | 46 + .../AdditionalSignatureInformation.java | 41 + .../AlgorithmSignatureInformation.java | 33 + .../ConnectorSignatureInformation.java | 34 + .../MandatorySignatureInformation.java | 40 + .../sig/signatureobject/SignatureObjectHelper.java | 81 + .../at/knowcenter/wag/egov/egiz/table/Entry.java | 235 +++ .../at/knowcenter/wag/egov/egiz/table/Style.java | 630 ++++++ .../at/knowcenter/wag/egov/egiz/table/Table.java | 223 ++ .../wag/egov/egiz/tools/CodingHelper.java | 301 +++ .../wag/egov/egiz/tools/DebugHelper.java | 90 + .../knowcenter/wag/egov/egiz/tools/FileHelper.java | 125 ++ .../knowcenter/wag/egov/egiz/tools/Normalize.java | 55 + .../wag/egov/egiz/tools/NormalizeV01.java | 184 ++ .../knowcenter/wag/egov/egiz/tools/Normalizer.java | 280 +++ .../knowcenter/wag/exactparser/ByteArrayUtils.java | 148 ++ .../knowcenter/wag/exactparser/ParseDocument.java | 272 +++ .../parsing/IndirectObjectReference.java | 57 + .../wag/exactparser/parsing/PDFNames.java | 184 ++ .../wag/exactparser/parsing/PDFUtils.java | 1405 +++++++++++++ .../parsing/results/ArrayParseResult.java | 42 + .../parsing/results/BooleanParseResult.java | 38 + .../parsing/results/ContainerParseResult.java | 45 + .../parsing/results/DictionaryParseResult.java | 41 + .../parsing/results/EOFParseResult.java | 47 + .../parsing/results/FooterParseResult.java | 53 + .../parsing/results/HeaderParseResult.java | 48 + .../parsing/results/HexStringParseResult.java | 36 + .../IndirectObjectReferenceParseResult.java | 44 + .../parsing/results/IntegerParseResult.java | 36 + .../parsing/results/LiteralStringParseResult.java | 37 + .../parsing/results/NameParseResult.java | 35 + .../parsing/results/NullParseResult.java | 34 + .../parsing/results/NumberParseResult.java | 41 + .../parsing/results/ObjectHeaderParseResult.java | 51 + .../parsing/results/ObjectParseResult.java | 50 + .../exactparser/parsing/results/ParseResult.java | 50 + .../parsing/results/StartXRefParseResult.java | 36 + .../parsing/results/StreamParseResult.java | 41 + .../parsing/results/TrailerParseResult.java | 84 + .../parsing/results/XRefLineParseResult.java | 40 + .../parsing/results/XRefSectionParseResult.java | 66 + .../parsing/results/XRefSubSectionParseResult.java | 59 + 339 files changed, 61661 insertions(+) create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmMapper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteObject.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteUtil.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/NonTextObjectInfo.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureLifetimeEnum.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfile.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfileImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/ConfigUtilsException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/LocalBKUParams.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/PdfAsInternal.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/SignatureEntry.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignatureDetailInformation.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/DummyTimeStamper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/TimeStamper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterReconstructXMLDsigParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ExtendedSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigAfterAnalysisParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigResult.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/XMLDsigData.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/Main.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/CorrectorException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/PlaceholderExtractionException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/CaptionNotFoundException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataSourceHolder.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSourceHolder.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/Corrector.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/CorrectorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextBasedDataSourceApiAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/internal/PdfAsInternalObject.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignatureDetailInformationImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/ExternalCorrector.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/InternalCorrector.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_2_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/xmldsig/XMLDsigReconstructor.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderContext.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderData.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderExtractor.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/test/JarExtractTest.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/ConfigUtils.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/OgnlUtil.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PDFASUtils.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PdfAUtil.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/TempDirHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/OverridePropertyHolder.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/OutOfMemoryException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_1_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_1_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_1_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactoryImpl.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIImpl.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClient.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactoryImpl.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientImpl.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPException.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPIssuerNameFilter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMapping.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMappingStore.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ActualTablePos.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AdobeSignatureHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/NoSignatureHolder.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ObjectExtractor.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/DebugHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java (limited to 'pdf-as-lib/src/main/java/at') diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java new file mode 100644 index 0000000..ba184fb --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/PdfAsFactory.java @@ -0,0 +1,124 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; + +/** + * 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. If null the configuration is assumed to be located + * within the user's home directory. Note: IAIK JCE and IAIK ECC security provders are + * automatically registered. + * + * @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. + * @see PdfAS#USERHOME_CONFIG_FOLDER + */ + public static PdfAs createPdfAs(File workDirectory) throws PdfAsException + { + return createPdfAs(workDirectory, SettingsReader.REGISTER_IAIK_PROVIDERS_ON_DEFAULT); + } + + /** + * Creates a PDF-AS API instance for the given work directory. + * + * @param workDirectory + * The work directory. If null the configuration is assumed to be located + * within the user's home directory. + * + * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; + * false: providers will NOT be automatically registered, providers + * needed have to be registered by the API user + * @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. + * @see PdfAS#USERHOME_CONFIG_FOLDER + */ + public static PdfAs createPdfAs(File workDirectory, boolean registerProvider) throws PdfAsException + { + return new PdfAsObject(workDirectory, registerProvider); + } + + /** + * Creates a PDF-AS API instance assuming that the configuration is located within the user's + * home directory. Note: IAIK JCE and IAIK ECC security providers are automatically registered. + * + * @return Returns an instance of the PDF-AS API. + * @throws IllegalArgumentException + * Thrown, if the work directory doesn't exist within the user's home directory. + * @throws PdfAsException + * Thrown, if the work directory does not meet its requirements, or + * if the config file is invalid. + * @see PdfAS#USERHOME_CONFIG_FOLDER + */ + public static PdfAs createPdfAs() throws PdfAsException + { + return createPdfAs(null); + } + + /** + * Creates a PDF-AS API instance assuming that the configuration is located within the user's + * home directory. + * + * @return Returns an instance of the PDF-AS API. + * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; + * false: providers will NOT be automatically registered, providers + * needed have to be registered by the API user + * @throws IllegalArgumentException + * Thrown, if the work directory doesn't exist within the user's home directory. + * @throws PdfAsException + * Thrown, if the work directory does not meet its requirements, or + * if the config file is invalid. + * @see PdfAS#USERHOME_CONFIG_FOLDER + */ + public static PdfAs createPdfAs(boolean registerProvider) throws PdfAsException + { + return createPdfAs(null, registerProvider); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmMapper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmMapper.java new file mode 100644 index 0000000..24ac9a5 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmMapper.java @@ -0,0 +1,143 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.algorithmSuite; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Utility for mapping signature and hash algorithms between URI and abbreviation.
+ * Supported algorithms are defined in external resource {@value #SUPPORTED_ALGORITHMS_RESOURCE}
+ * + * e.g. sha1 <-> http://www.w3.org/2000/09/xmldsig#sha1 + * + * @author dferbas + * + */ + +public class AlgorithmMapper { + private static final String SUPPORTED_ALGORITHMS_RESOURCE = "supportedAlgorithms.txt"; + private static Map algorithmMap = new HashMap(); + private static Log log = LogFactory.getLog(AlgorithmMapper.class); + + /** + * read available algorithms from resource + */ + static { + try { + log.debug("reading supported algorithms from " + SUPPORTED_ALGORITHMS_RESOURCE); + List lines = IOUtils.readLines(AlgorithmMapper.class.getResourceAsStream(SUPPORTED_ALGORITHMS_RESOURCE)); + for (int i = 0; i < lines.size(); i++) { + String uri = (String)lines.get(i); + if (isValidLine(uri)) { + String abbr = parseAbbreviation(uri); + algorithmMap.put(abbr, uri); + if (log.isDebugEnabled()) { + log.debug("added supported algorithm: " + abbr + "=" + uri); + } + } + } + } catch (IOException e) { + throw new RuntimeException("error loading supportetAlgorithms.properties file", e); + } + } + + /** + * Get algorithm abbreviation (equals last part after namespace#) from uri
+ * + * e.g. sha1 from http://www.w3.org/2000/09/xmldsig#sha1 + * + * @param algorithmUri algorithm URI + * @return algorithm abbreviation + */ + public static String getAbbreviation(String algorithmUri) { + if (!algorithmMap.containsValue(algorithmUri)) { + throw new RuntimeException("unsupported Algorithm " + algorithmUri); + } + return parseAbbreviation(algorithmUri); + } + + private static boolean isValidLine(String uri) { + if (uri == null || uri.length() == 0) return false; + if (uri.trim().startsWith("#")) return false; + return true; + } + + /** + * Get valid URI from algorithm abbreviation
+ * + * e.g. http://www.w3.org/2000/09/xmldsig#sha1 from sha1 + * + * @param algorithmShort + * @return URI + */ + public static String getUri(String algorithmShort) { + if (!algorithmMap.containsKey(algorithmShort)) { + throw new RuntimeException("unsupported Algorithm " + algorithmShort); + } + return (String)algorithmMap.get(algorithmShort); + } + + /** + * Get hash (abbreviation) from signature method (eg. sha1 from ecdsa-sha1). + * @param suite abbreviation or full qualified signature method + * @return digest method abbreviation + */ + public static String getHashAbbrFromSuite(String suite) { + try { + int pos = suite.lastIndexOf('-'); + return suite.substring(pos + 1); + } catch (Exception e) { + throw new RuntimeException("cannot parse algorithm string for hash method: " + suite); + } + } + + /** + * + * Get hash method (URI) from signature method + * @param suite abbreviation or full qualified signature method + * @return digest method URI + * + */ + public static String getHashUriFromSuite(String suite) { + return getUri(getHashAbbrFromSuite(suite)); + } + + private static String parseAbbreviation(String algorithmUri) { + try { + int pos = algorithmUri.lastIndexOf('#'); + return algorithmUri.substring(pos + 1); + } catch (Exception e) { + throw new RuntimeException("invalid algorithm entry in " + SUPPORTED_ALGORITHMS_RESOURCE + + ": " + algorithmUri); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteObject.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteObject.java new file mode 100644 index 0000000..a8e19b3 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteObject.java @@ -0,0 +1,183 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.algorithmSuite; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Defines a used algorithm suite. Contains a {@link #signatureMethod} a + * {@link #dataDigestMethod} a {@link #propertiesDigestMethod} and a + * {@link #certDigestMethod}.
+ * + * This structured object is representing a string like + * ecdsa-sha256:sha256:sha256:ripemd160
+ * meaning + * signatureMethod:dataDigestMethod:propertiesDigestMethod:certDigestMethod + * + * @author dferbas + * + */ +public class AlgorithmSuiteObject { + private static Log log = LogFactory.getLog(AlgorithmSuiteObject.class); + + private String signatureMethod; + private String dataDigestMethod; + private String propertiesDigestMethod; + private String certDigestMethod; + + /** + * Create emtpy algorithm suite object + */ + public AlgorithmSuiteObject() { + + } + + /** + * Create object from parameter string like + * etsi-moc-1.2:ecdsa-sha1:ripemd160@207c44ff + * Prefix included + * + * @param parameterString + */ + public AlgorithmSuiteObject(String parameterString) { + parseFrom(parameterString, true); + } + + /** + * Create object from parameter string like
+ * etsi-moc-1.2:ecdsa-sha1:ripemd160@207c44ff hasPrefix=true
+ * ecdsa-sha1:ripemd160@207c44ff hasPrefix=false + * + * + * @param parameterString + * @param hasPrefix parse with/without prefix (e.g. etsi-moc-1.2) + */ + public AlgorithmSuiteObject(String parameterString, boolean hasPrefix) { + parseFrom(parameterString, hasPrefix); + } + + /** + * Initializes object from parameter string like + * etsi-moc-1.2:ecdsa-sha1:ripemd160@207c44ff hasPrefix=true
+ * ecdsa-sha1:ripemd160@207c44ff hasPrefix=false + * + * @param parameterString + * @param hasPrefix parse with/without prefix (e.g. etsi-moc-1.2) + */ + public void parseFrom(String parameterString, boolean hasPrefix) { + log.debug("parsing algorithmSuite from " + parameterString); + if (parameterString != null) { + parameterString = parameterString.split("@")[0]; + if (!hasPrefix) { + parameterString = "bla:" + parameterString; // fake prefix + } + String[] arr = parameterString.split(":"); + if (arr.length > 1) { + this.signatureMethod = arr[1]; + this.dataDigestMethod = this.propertiesDigestMethod = this.certDigestMethod = AlgorithmMapper + .getHashAbbrFromSuite(arr[1]); + + if (arr.length > 2) { + this.dataDigestMethod = this.propertiesDigestMethod = this.certDigestMethod = arr[2]; + } + if (arr.length > 3) { + this.propertiesDigestMethod = this.certDigestMethod = arr[3]; + } + if (arr.length > 4) { + this.certDigestMethod = arr[4]; + } + log.debug("successfully parsed to: " + this.toString()); + } + } + } + + /** + * Returns if algorithm object is valid specified (values are available) + * + * @return + */ + public boolean isSpecified() { + return this.signatureMethod != null; + } + + /** + * Signature method abbreviation. E.g. rsa-sha1, ecdsa-sha256 + * + * @return + */ + public String getSignatureMethod() { + return this.signatureMethod; + } + + /** + * Digest method for data (document). E.g. sha1, md5 + * + * @return + */ + public String getDataDigestMethod() { + return this.dataDigestMethod; + } + + /** + * Digest method for properties. E.g. sha1, md5 + * + * @return + */ + public String getPropertiesDigestMethod() { + return this.propertiesDigestMethod; + } + + /** + * Digest method for certificate digest. E.g. sha1, md5 + * + * @return + */ + public String getCertDigestMethod() { + return this.certDigestMethod; + } + + public void setSignatureMethod(String signatureMethod) { + this.signatureMethod = signatureMethod; + } + + public void setDataDigestMethod(String dataDigestMethod) { + this.dataDigestMethod = dataDigestMethod; + } + + public void setPropertiesDigestMethod(String propertiesDigestMethod) { + this.propertiesDigestMethod = propertiesDigestMethod; + } + + public void setCertDigestMethod(String certDigestMethod) { + this.certDigestMethod = certDigestMethod; + } + + public String toString() { + return "AlgorithmSuiteObject [certDigestMethod=" + this.certDigestMethod + + ", dataDigestMethod=" + this.dataDigestMethod + ", propertiesDigestMethod=" + + this.propertiesDigestMethod + ", signatureMethod=" + this.signatureMethod + "]"; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteUtil.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteUtil.java new file mode 100644 index 0000000..eba63c7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/algorithmSuite/AlgorithmSuiteUtil.java @@ -0,0 +1,230 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.algorithmSuite; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * Utility class for handling dynamic algorithm suites + * + * @author dferbas + * + */ +public class AlgorithmSuiteUtil { + private static Log log = LogFactory.getLog(AlgorithmSuiteUtil.class); + + /** + * Creates new verify_xml, evaluates algorithm suite and replaces methods in verify_xml + * + * @param algSuite out-param empty algorithm suite object + * @param environment connector environment to load verify template + * @param so signsignator object + * @return verify xml + */ + public static String evaluateReplaceAlgs(AlgorithmSuiteObject algSuite, ConnectorEnvironment environment, SignSignatureObject so) { + + String verify_template = environment.getVerifyTemplate(); + + String cert_alg = null; + String verify_xml = null; + X509Certificate cert = so.getX509Certificate(); + String ids_string = so.getSigID(); + + //AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(ids_string); + algSuite.parseFrom(ids_string, true); + // 1. is specified in sig_id + if (algSuite.isSpecified()) { + log.debug("Algorithm suite defined as parameter. Using new dynamic template replacement."); + cert_alg = AlgorithmMapper.getUri(algSuite.getSignatureMethod()); + + // 2. is specified in /alg replace -> baik + } else if (so.getSigAlgorithm() != null && so.getSigAlgorithm().length() > 0) { + String algAbbr = AlgorithmMapper.getAbbreviation(so.getSigAlgorithm()); + algSuite.parseFrom(algAbbr, false); + + if (algSuite.isSpecified()) { + log.debug("Algorithm /alg available. Using: " + so.getSigAlgorithm()); + cert_alg = AlgorithmMapper.getUri(algSuite.getSignatureMethod()); +// algSuite.setCertDigestMethod("sha1"); + //algSuite.setPropertiesDigestMethod("sha1"); + } + } + + // 3. default + if (cert_alg == null) { + log.debug("NO algorithm suite defined. Using default old static algorithm."); + + cert_alg = environment.getCertAlgEcdsa(); + if (cert.getPublicKey().getAlgorithm().indexOf("RSA") >= 0) //$NON-NLS-1$ + { + cert_alg = environment.getCertAlgRsa(); + } + + // fix digest methods to sha1 for old algorithm + String oldDigest = "sha1"; + algSuite.setCertDigestMethod(oldDigest); + algSuite.setDataDigestMethod(oldDigest); + algSuite.setPropertiesDigestMethod(oldDigest); + + } + + // cert alg replace + verify_xml = verify_template.replaceFirst(TemplateReplaces.CERT_ALG_REPLACE, cert_alg); + + // digest method replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DATA_DIGEST_REPLACE, + AlgorithmMapper.getUri(algSuite.getDataDigestMethod())); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.PROPERTIES_DIGEST_REPLACE, + AlgorithmMapper.getUri(algSuite.getPropertiesDigestMethod())); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.CERT_DIGEST_REPLACE, + AlgorithmMapper.getUri(algSuite.getCertDigestMethod())); + return verify_xml; + } + + + /** + * Extract algorithm suite as optimized string from CreateXMLSignatureResponse + * + * @param xmlResponse + * @return algorith suite string + */ + public static String extractAlgorithmSuiteString(String xmlResponse) { + + String elem = findFirstElement(xmlResponse, "SignatureMethod"); + + String alg = findAttributeValue(elem, "Algorithm"); + + List digAlgs = findAllAttributeValues(xmlResponse, "DigestMethod", "Algorithm"); + + digAlgs.add(0, AlgorithmMapper.getHashUriFromSuite(alg)); + + reduceDigestAlgs(digAlgs); + + digAlgs.remove(0); + + return createSigDevString(alg, digAlgs); + + } + + public static boolean isDefaultCertAlg(String algsString, String defaultCertAlg) { + return AlgorithmMapper.getAbbreviation(defaultCertAlg).equals(algsString); + } + + private static String createSigDevString(String suite, List digAlgs) { + StringBuffer sb = new StringBuffer(AlgorithmMapper.getAbbreviation(suite)); + for (Iterator iterator = digAlgs.iterator(); iterator.hasNext();) { + String dig = (String) iterator.next(); + sb.append(":").append(AlgorithmMapper.getAbbreviation(dig)); + } + return sb.toString(); + } + + private static String findAttributeValue(String elemContent, String attrName) { + + String sig_alg = removeAllWhitespace(elemContent); + + attrName += "=\""; + int start = sig_alg.indexOf(attrName) + attrName.length(); + int end = sig_alg.indexOf("\"", start); + return sig_alg.substring(start, end); + + } + + private static String findFirstElement(String xml, String elemName) { + Pattern p = Pattern.compile("<[\\w]*:?" + elemName); + Matcher m = p.matcher(xml); + if (m.find()) { + int start = m.start(); + int end = xml.indexOf("/>", start) + 2; + return xml.substring(start, end); + } + return null; + } + + private static List findElements(String xml, String elemName) { + Pattern p = Pattern.compile("<[\\w]*:?" + elemName); + Matcher m = p.matcher(xml); + ArrayList res = new ArrayList(); + while (m.find()) { + int start = m.start(); + int end = xml.indexOf("/>", start) + 2; + res.add(xml.substring(start, end)); + } + return res; + } + + private static String findAttributeValue(String xmlContent, String elemName, String attrName) { + String elemCont = findFirstElement(xmlContent, elemName); + return findAttributeValue(elemCont, attrName); + } + + private static List findAllAttributeValues(String xmlContent, String elemName, String attrName) { + List elemConts = findElements(xmlContent, elemName); + ArrayList res = new ArrayList(); + for (int i = 0; i < elemConts.size(); i++) { + res.add(findAttributeValue((String) elemConts.get(i), attrName)); + } + return res; + } + + /** + * Helper method to remove whitespaces from a string + * @param str + * @return + */ + public static String removeAllWhitespace(String str) { + return str.replaceAll("\\s", ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + private static void reduceDigestAlgs(List digestAlgs) { + if (digestAlgs == null) + return; + reduceDigestAlgsRec(digestAlgs, digestAlgs.size() - 1); + } + + private static void reduceDigestAlgsRec(List digestAlgs, int act) { + if (act <= 0) + return; + else if (digestAlgs.get(act - 1).equals(digestAlgs.get(act))) { + // reduce + digestAlgs.remove(act); + reduceDigestAlgsRec(digestAlgs, act - 1); + } else { + return; + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java new file mode 100644 index 0000000..3fda87c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/PdfAs.java @@ -0,0 +1,285 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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.DynamicSignatureLifetimeEnum; +import at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile; +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.sign.SignatureDetailInformation; +import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.verify.VerifyAfterReconstructXMLDsigParameters; +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.api.xmldsig.ReconstructXMLDsigAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigParameters; +import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigResult; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; + +/** + * The PDF-AS API main interface. + * + *

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

+ * + * @author wprinz + * @author exthex + */ +public interface PdfAs +{ +// 23.11.2010 changed by exthex - added: +// reconstructXMLDSIG(ReconstructXMLDsigParameters reconstructXMLDsigParameters) +// reconstructXMLDSIG(ReconstructXMLDsigAfterAnalysisParameters reconstructXMLDsigParameters) +// verify(VerifyAfterReconstructXMLDsigParameters verifyAfterReconstructXMLDsigParameters) + +// 16.12.2010 changed by exthex - added: +// prepareSign(SignParameters signParameters) +// sign(SignParameters signParameters, SignatureDetailInformation signatureDetailInformation) +// finishSign(SignParameters signParameters, SignatureDetailInformation signatureDetailInformation) + + /** + * 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; + + /** + * Signs a PDF document using PDF-AS.
+ * This uses the {@link SignatorInformation} which was obtained by a call to {@link PdfAs#prepareSign(SignParameters)} + * + * @param signParameters + * The sign parameters. + * @param signatureDetailInformation + * The signature information which was previously obtained by a call to {@link PdfAs#prepareSign(SignParameters)} + * @return Returns the signed document plus additional information. + * @throws PdfAsException + * Thrown, if an error occurs. + * + * @see SignParameters + * @see SignResult + */ + public SignResult sign(SignParameters signParameters, SignatureDetailInformation signatureDetailInformation) 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; + + /** + * Reconstruct the from the given parameters. + * + * @param reconstructXMLDsigParameters + * The data from which to reconstruct the xmldsig + * @return a list of xmldsigs, one for each signature in the document + * @throws PdfAsException if the reconstruction fails + */ + public ReconstructXMLDsigResult reconstructXMLDSIG(ReconstructXMLDsigParameters reconstructXMLDsigParameters) throws PdfAsException; + + /** + * Reconstruct the from the given parameters. + * + * @param reconstructXMLDsigParameters + * The data from which to reconstruct the xmldsigs + * @return a list of xmldsigs, one for each signature in the document + * @throws PdfAsException + */ + public ReconstructXMLDsigResult reconstructXMLDSIG(ReconstructXMLDsigAfterAnalysisParameters reconstructXMLDsigParameters) 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; + + /** + * Verifies a list of signatures that have been analyzed previously and the xmldsigs have been reconstructed. + * + * @param verifyAfterReconstructXMLDsigParameters + * The parameters. + * @return the verification results. + * @throws PdfAsException + * Thrown on error. + */ + public VerifyResults verify(VerifyAfterReconstructXMLDsigParameters verifyAfterReconstructXMLDsigParameters) 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 activated 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 active profiles available in the configuration. + * @throws PdfAsException + * Thrown on error. + * + * @see SignatureProfile + */ + public List getProfileInformation() throws PdfAsException; + + /** + * Create a signature profile dynamically. You have do apply() it for usage. See {@link SignatureProfile}. + * @param parentProfile a parent profile id to inherit all properties + * @param mode lifetime mode + * @return the created signature profile to work with. + */ + public DynamicSignatureProfile createDynamicSignatureProfile(String parentProfile, DynamicSignatureLifetimeEnum mode); + + /** + * Create a signature profile dynamically. You have to provide a unique name and have do apply() it for usage. See {@link SignatureProfile}. + * It is recommended to use {@link #createDynamicSignatureProfile(String, DynamicSignatureLifetimeEnum)} that generates + * a unique name on its own. + * @see DynamicSignatureProfile + * @param parentProfile a parent profile id to inherit all properties + * @param myUniqueName a unique name for the profile + * @param mode lifetime mode + * @return the created signature profile to work with. + */ + public DynamicSignatureProfile createDynamicSignatureProfile(String myUniqueName, String parentProfile, DynamicSignatureLifetimeEnum mode); + + /** + * Create a signature profile dynamically. You have fill it with properties and apply() it for usage. See {@link SignatureProfile}. + *
+ * It is recommended to use {@link #createDynamicSignatureProfile(String, DynamicSignatureLifetimeEnum)} that inherits from an + * existing profile saving you a lot of work. + * @param mode lifetime mode + * @return the created signature profile to work with. + * @see DynamicSignatureProfile + */ + public DynamicSignatureProfile createEmptyDynamicSignatureProfile(DynamicSignatureLifetimeEnum mode); + + /** + * Create a signature profile dynamically. You have fill it with properties and apply() it for usage. See {@link SignatureProfile}. + *
+ * It is recommended to use {@link #createDynamicSignatureProfile(String, DynamicSignatureLifetimeEnum)} that inherits from an + * existing profile saving you a lot of work. + * @param myUniqueName a unique name for the profile + * @param mode lifetime mode + * @return the created signature profile to work with. + */ + public DynamicSignatureProfile createEmptyDynamicSignatureProfile(String myUniqueName, DynamicSignatureLifetimeEnum mode); + + /** + * Loads an existing dynamic signature profile by its name. Profiles are saved when they are applied + * and it has {@link DynamicSignatureLifetimeEnum#MANUAL} + * @param profileName + * @return the signature profile or null if not found. + * @see DynamicSignatureProfile + */ + public DynamicSignatureProfile loadDynamicSignatureProfile(String profileName); + + /** + * Prepares the signature of the given PDF document. The table for the signature data is placed but not filled.
+ * Usually used for preview. + * + * @param signParameters + * The sign parameters. + * @return Only the {@link SignatureDetailInformation#getSignaturePosition()}, {@link SignatureDetailInformation#getNonTextualObjects()}, {@link SignatureDetailInformation#getSignatureData()} are filled. + * @throws PdfAsException if something goes wrong during the process + */ + public SignatureDetailInformation prepareSign(SignParameters signParameters) throws PdfAsException; + + /** + * Finish the signature process. The PDF is filled with the signature data.
+ * Usually used if some steps like the actual signing are to be performed externally. + * + * @param signParameters + * The sign parameters. + * @param signatureDetailInformation + * The signature detail information. + * @return + * @throws PdfAsException + */ + public SignResult finishSign(SignParameters signParameters, SignatureDetailInformation signatureDetailInformation) throws PdfAsException; + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java new file mode 100644 index 0000000..1ce7057 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeParameters.java @@ -0,0 +1,107 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + + protected boolean returnNonTextualObjects = false; + + protected boolean hasBeenCorrected = 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 verifyMode + */ + public String getVerifyMode() + { + return this.verifyMode; + } + + /** + * @param verifyMode the verifyMode to set + */ + public void setVerifyMode(String verifyMode) + { + this.verifyMode = verifyMode; + } + + public boolean isReturnNonTextualObjects() { + return this.returnNonTextualObjects; + } + + /** + * Tells if non text object of the signed pdf should be extracted and returned. + * One should show this to the user, especially in case of textual signature. + * Defaults to false + * + * @param returnNonTextualObjects + */ + public void setReturnNonTextualObjects(boolean returnNonTextualObjects) { + this.returnNonTextualObjects = returnNonTextualObjects; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java new file mode 100644 index 0000000..9b913ae --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/AnalyzeResult.java @@ -0,0 +1,63 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + + public List getNoSignatures(); + + /** + * Tells if the document has been corrected before verification. The correction maybe done + * after a first failing parse to repair a document (if enabled in the configuration + * correct_document_on_verify_if_necessary). The correction can only work for textual + * signatures. Binary signatures are lost anyhow. + * @return + */ + public boolean hasBeenCorrected(); + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/NonTextObjectInfo.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/NonTextObjectInfo.java new file mode 100644 index 0000000..08297b7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/analyze/NonTextObjectInfo.java @@ -0,0 +1,99 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.analyze; + +/** + * Encapsulates information about non textual objects in a pdf document. + * + * @author dferbas + * + */ +public class NonTextObjectInfo { + public static final String TYPE_IMAGE = "image"; + public static final String TYPE_ANNOTATION = "annotation"; + + private String objectType; + private String subType; + private String name; + private int pageNr; + private double width; + private double height; + + public String getObjectType() { + return this.objectType; + } + + public void setObjectType(String objectType) { + this.objectType = objectType; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPageNr() { + return this.pageNr; + } + + public void setPageNr(int pageNr) { + this.pageNr = pageNr; + } + + public double getWidth() { + return this.width; + } + + public void setWidth(double width) { + this.width = width; + } + + public double getHeight() { + return this.height; + } + + public void setHeight(double height) { + this.height = height; + } + + public String getSubType() { + return this.subType; + } + + public void setSubType(String subType) { + this.subType = subType; + } + + + + public String toString() { + return "NonTextObjectInfo [height=" + this.height + ", name=" + this.name + ", objectType=" + + this.objectType + ", pageNr=" + this.pageNr + ", subType=" + this.subType + + ", width=" + this.width + "]"; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java new file mode 100644 index 0000000..b351d50 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/Constants.java @@ -0,0 +1,185 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.commons; + +import at.knowcenter.wag.egov.egiz.pdf.AdobeSignatureHelper; + +/** + * Contains commonly used constants. + * + * @author wprinz + */ +public final class Constants +{ + + /** + * Hidden default constructor. + */ + private Constants() + { + // empty + } + + /** + * A binary signature. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_TYPE_BINARY = "binary"; + + /** + * A textual signature. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_TYPE_TEXTUAL = "textual"; + + /** + * The default signature type (one of "textual", "binary", "detachedtextual"). + */ + public static final String DEFAULT_SIGNATURE_TYPE = SIGNATURE_TYPE_BINARY; + + /** + * 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 final String SIGNATURE_TYPE_DETACHEDTEXTUAL = "detachedtextual"; + + /** + * The signature device moa. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_DEVICE_MOA = "moa"; + + /** + * The signature device bku. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_DEVICE_BKU = "bku"; + + /** + * The signature device a1. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_DEVICE_A1 = "a1"; + + /** + * The signature device MOCCA (online bku). + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_DEVICE_MOC = "moc"; + + /** + * Added by rpiazzi + * The signature device MOBILE. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_DEVICE_MOBILE = "mobile"; + + /** + * Added by rpiazzi + * The signature device MOBILETEST for the test version of the MOBILE CCS. + * This value should not be modified due to external dependencies! + */ + public static final String SIGNATURE_DEVICE_MOBILETEST = "mobiletest"; + + /** + * Only binary signatures are verified. + */ + public static final 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 final String VERIFY_MODE_SEMI_CONSERVATIVE = "semiConservative"; + + /** + * Binary and textual signatures are verified. + */ + public static final String VERIFY_MODE_FULL_CONSERVATIVE = "fullConservative"; + + /** + * All signatures are verified. + */ + public static final int VERIFY_ALL = -1; + + /** + * The system property that may be used to declare the pdf-as configuration folder. + */ + public static final String CONFIG_DIR_SYSTEM_PROPERTY = "pdf-as.work-dir"; + + /** + * The zip file containing the default configuration. + */ + public static final String DEFAULT_CONFIGURATION_ZIP_RESOURCE = "DefaultConfiguration.zip"; + + /** + * The configuration folder for pdf-as within the user's home folder. + */ + public static final String USERHOME_CONFIG_FOLDER = "PDF-AS"; + + /** + * The name of the directory, where temporary files are stored. + */ + public static final String TEMP_DIR_NAME = "pdfastmp"; + + public static final String BKU_HEADER_SIGNATURE_LAYOUT = "SignatureLayout"; + + public static final String ADOBE_SIG_FILTER = AdobeSignatureHelper.ADOBE_SIG_FILTER; + + /** + * Strict matching mode for placeholder extraction.
+ * If the placeholder with the given id is not found in the document, an exception will be thrown. + */ + public static final int PLACEHOLDER_MATCH_MODE_STRICT = 0; + + /** + * A moderate matching mode for placeholder extraction.
+ * If the placeholder with the given id is not found in the document, the first placeholder without an id will be taken.
+ * If there is no such placeholder, the signature will be placed as usual, according to the pos parameter of the signature profile used. + */ + public static final int PLACEHOLDER_MATCH_MODE_MODERATE = 1; + + /** + * A more lenient matching mode for placeholder extraction.
+ * If the placeholder with the given id is not found in the document, the first found placeholder will be taken, regardless if it has an id set, or not.
+ * If there is no placeholder at all, the signature will be placed as usual, according to the pos parameter of the signature profile used. + */ + public static final int PLACEHOLDER_MATCH_MODE_LENIENT = 2; + + /** + * Identifier for QR based placeholders. + */ + public static final String QR_PLACEHOLDER_IDENTIFIER = "PDF-AS-POS"; + +} + diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureLifetimeEnum.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureLifetimeEnum.java new file mode 100644 index 0000000..7b3d17b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureLifetimeEnum.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.commons; + +import java.io.Serializable; + +/** + * Pseudo enum defining lifetime models for {@link DynamicSignatureProfile}s. + * + * @author exthex + * + */ +public final class DynamicSignatureLifetimeEnum implements Serializable { + private static final long serialVersionUID = 1L; + + private int value; + + /** + * Automatic lifetime bound to one sign process + */ + public static final DynamicSignatureLifetimeEnum AUTO = new DynamicSignatureLifetimeEnum(1); + + /** + * Manual lifetime making YOU responsible for calling {@link DynamicSignatureProfile#dispose()}. + */ + public static final DynamicSignatureLifetimeEnum MANUAL = new DynamicSignatureLifetimeEnum(2); + + private DynamicSignatureLifetimeEnum(int val) { + this.value = val; + } + + public int hashCode() { + return value; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DynamicSignatureLifetimeEnum other = (DynamicSignatureLifetimeEnum) obj; + if (value != other.value) + return false; + return true; + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfile.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfile.java new file mode 100644 index 0000000..7418f4d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfile.java @@ -0,0 +1,125 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.commons; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.sign.SignParameters; + +/** + * A dynamic signature profile. It is used to define a signature profile like the ones from pdf-as/config.properties at runtime. + * After creation via {@link PdfAs} you can set properties via {@link #setPropertyRaw(String, String)} + * or {@link #setFieldValue(String, String)}.
+ * You have to call {@link #apply()} to use the profile. The identifying name (e.g. for {@link SignParameters#setSignatureProfileId(String)} + * can be obtained via {@link #getName()}.
+ * Depending on the {@link DynamicSignatureLifetimeEnum} the profile can be alive and usable till you {@link #dispose()} it manually. + *

+ * Sample usage:
+ *

+      SignParameters sp = new SignParameters();
+      . . .           
+      sp.setSignatureType(Constants.SIGNATURE_TYPE_TEXTUAL);
+      sp.setSignatureDevice(Constants.SIGNATURE_DEVICE_MOA);
+
+      // create a new dynamic profile based on SIGNATURBLOCK_DE (every property is copied) with manual lifetime
+      DynamicSignatureProfile dsp = pdfAs.createDynamicSignatureProfile("myUniqueName", "SIGNATURBLOCK_DE", 
+            DynamicSignatureLifetimeEnum.MANUAL);  
+            
+      // set something
+      dsp.setPropertyRaw("key.SIG_META", "Statement");
+      dsp.setPropertyRaw("value.SIG_META", "respect to the man in the icecream van ${subject.EMAIL}");
+      dsp.setPropertyRaw("value.SIG_LABEL", "./images/signatur-logo_en.png");
+      dsp.setPropertyRaw("table.main.Style.halign", "right");
+      
+      // mandatory: apply the profile, you have to apply again after changes (overriding your previous setting)
+      dsp.apply();                 
+      sp.setSignatureProfileId(dsp.getName());            
+      
+      // execute PDF-AS
+      pdfAs.sign(sp);              
+      
+      . . .
+                       
+     // your profile is saved and you can obtain it again anytime later:
+      dsp = pdfAs.loadDynamicSignatureProfile("myUniqueName");
+      // use it for another sign.
+      // dont forget to dispose() sometimes because it was manual lifetime
+      System.out.println(dsp.getName());
+ *  
+ *

+ * + * @author exthex + * + */ +public interface DynamicSignatureProfile { + + /** + * Get the name of the dynamic signature profile. Equals the SignatureProfileId + * @return + */ + public abstract String getName(); + + /** + * Set a field value for the profile. Use {@link #setPropertyRaw(String, String)} for setting any property.
+ * For example to set sig_obj.MEIN_DYN_SIGNATURBLOCK.value.SIG_META just use SIG_META as fieldName. + * @param fieldName the name of the field + * @param value the value to set + */ + public abstract void setFieldValue(String fieldName, String value); + + /** + * Get a field value from the profile. See {@link #setFieldValue(String, String)} + * @param fieldName + * @return + */ + public abstract String getFieldValue(String fieldName); + + /** + * Set any property for the signature profile. + * Uses the same keys as the property file without the "prefix" for the profile. + * For example to set sig_obj.MEIN_DYN_SIGNATURBLOCK.key.SIG_META use key.SIG_META + * @param key property key + * @param val property value + */ + public void setPropertyRaw(String key, String val); + + /** + * Get any property from the signature profile. See {@link #setPropertyRaw(String, String)} for details. + * @param key + * @return + */ + public String getPropertyRaw(String key); + + /** + * Apply the signature profile. Call this after all properties are set and you want to use the profile. It is then added + * to the globally available signature profiles. Depending on the lifetime model {@link DynamicSignatureLifetimeEnum} you + * have to {@link #dispose()} it manually when not needed anymore. + */ + public abstract void apply(); + + /** + * Disposes the signature profile from the global store. Call this for {@link DynamicSignatureLifetimeEnum#MANUAL} only. + */ + public abstract void dispose(); + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfileImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfileImpl.java new file mode 100644 index 0000000..7e1672a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/DynamicSignatureProfileImpl.java @@ -0,0 +1,215 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.commons; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.lang.StringUtils; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.knowcenter.wag.egov.egiz.cfg.PropertyTree; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +// TODO exception types? +/** + * Implementation class of the {@link DynamicSignatureProfile}. Don't use this class directly. Use {@link PdfAs} to create and the + * {@link DynamicSignatureProfile} interface for manipulation. + * @author exthex + * + */ +public class DynamicSignatureProfileImpl implements DynamicSignatureProfile { + private String name; + private Properties newProps = new Properties(); + private int dynamicTypeCounter = 0; + private static Map profiles = new HashMap(); + private static ThreadLocal localProfiles = new ThreadLocal(); + private DynamicSignatureLifetimeEnum lifeMode; + + + private DynamicSignatureProfileImpl(DynamicSignatureLifetimeEnum mode, String name) { + if (name != null) { + this.name = name; + } else { + this.name = createDynamicTypeName(); + } + this.lifeMode = mode; + } + + public static DynamicSignatureProfileImpl createFromParent(String myUniqueName, String parentProfile, DynamicSignatureLifetimeEnum mode) { + DynamicSignatureProfileImpl res = new DynamicSignatureProfileImpl(mode, myUniqueName); + res.initFromParent(parentProfile); + return res; + } + + private void store() { + if (lifeMode.equals(DynamicSignatureLifetimeEnum.MANUAL)) { + profiles.put(this.getName(), this); + } else if (lifeMode.equals(DynamicSignatureLifetimeEnum.AUTO)) { + localProfiles.set(this); + } + } + + private void remove() { + if (lifeMode.equals(DynamicSignatureLifetimeEnum.MANUAL)) { + profiles.remove(this); + } else if (lifeMode.equals(DynamicSignatureLifetimeEnum.AUTO)) { + localProfiles.set(null); + } + } + + public static void disposeLocalProfile() { + DynamicSignatureProfileImpl profile = (DynamicSignatureProfileImpl) localProfiles.get(); + if (profile != null) { + profile.dispose(); + } + } + + public static DynamicSignatureProfileImpl createEmptyProfile(String myUniqueName, DynamicSignatureLifetimeEnum mode) { + return new DynamicSignatureProfileImpl(mode, myUniqueName); + } + + public static DynamicSignatureProfileImpl loadProfile(String name) { + return (DynamicSignatureProfileImpl) profiles.get(name); + } + + private synchronized String createDynamicTypeName() { + return "dynprofile__#" + this.dynamicTypeCounter++; + } + + /* (non-Javadoc) + * @see at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile#getName() + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile#setName(String) + */ + public void setName(String uniqueName) { + this.name = uniqueName; + } + + public void setPropertyRaw(String key, String val) { + this.newProps.setProperty(localPropName(key), val); + } + + public String getPropertyRaw(String key) { + return this.newProps.getProperty(localPropName(key)); + } + + private void assertPropExists(String key) { + if (!this.newProps.containsKey(localPropName(key))) { + throw new RuntimeException("property '" + key + "'not existing, cannot add one"); + } + } + + private String localPropName(String key) { + return "sig_obj." + this.name + "." + key; + } + + /* (non-Javadoc) + * @see at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile#setFieldValue(java.lang.String, java.lang.String) + */ + public void setFieldValue(String fieldName, String value) { + if (SignatureTypes.isRequredSigTypeKey(fieldName)) { + throw new RuntimeException("cannot set value for pre defined signature field names"); + } + + String key = "value." +fieldName; + assertPropExists(key); + setPropertyRaw(key, value); + } + + /* (non-Javadoc) + * @see at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile#getFieldValue(java.lang.String) + */ + public String getFieldValue(String fieldName) { + return getPropertyRaw("value."+fieldName); + } + + private void initFromParent(String parentProfile) { + try { + SettingsReader cfg = null; + + cfg = SettingsReader.getInstance(); + + Properties props = cfg.getProperties(); + for (Enumeration e = props.keys(); e.hasMoreElements();) { + String oldKey = (String) e.nextElement(); + if (oldKey.startsWith("sig_obj." + parentProfile + ".")) { + String newKey = StringUtils.replace(oldKey, parentProfile, name); + String val = props.getProperty(oldKey); + this.newProps.put(newKey, val); + } + } + this.newProps.put("sig_obj.types." + name, "on"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* (non-Javadoc) + * @see at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile#register() + */ + public synchronized void apply() { + try { + SettingsReader settings = SettingsReader.getInstance(); + + settings.getProperties().putAll(this.newProps); + + for (Enumeration e = newProps.keys(); e.hasMoreElements();) { + String key = (String) e.nextElement(); + settings.getPTree().setKeyValue(key, newProps.getProperty(key)); + } + + SignatureTypes.getInstance().addSignatureType(this.name); + store(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /* (non-Javadoc) + * @see at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile#dispose() + */ + public synchronized void dispose() { + try { + SettingsReader.getInstance().getProperties().keySet().removeAll(newProps.keySet()); + + PropertyTree root = SettingsReader.getInstance().getPTree(); + root.getSubTree("sig_obj").removeEntry(this.name); + + SignatureTypes.getInstance().removeSignatureType(this.name); + remove(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java new file mode 100644 index 0000000..7315af6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureInformation.java @@ -0,0 +1,129 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $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 java.util.List; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +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(); + + /** + * Returns the embedded /TimeStamp value (b64 encoded) from the signature if available. + * @return + */ + public String getTimeStampValue(); + + /** + * Returns a list<{@link NonTextObjectInfo}> of non textual objects in the pdf document. + * Only available for textual signatures. Show this to the user who signed the textual content only! + * @return List<{@link NonTextObjectInfo} or null of not available (binary signature) + */ + public List getNonTextualObjects(); + + public void setNonTextualObjects(List nonTextualObjects); + + /** + * Returns true if non textual objects have been found, false if not. + * @return true if non textual objects have been found, false if not. + */ + public boolean hasNonTextualObjects(); + + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java new file mode 100644 index 0000000..8cd3108 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/commons/SignatureProfile.java @@ -0,0 +1,76 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.commons; + +import java.util.Properties; + +/** + * Definition of a signature profile. + * + * @author wprinz + */ +public interface SignatureProfile { + + // TODO: implement full profile support + + /** + * Returns the profile id. + * + * @return Returns the profile id. + */ + public String getProfileId(); + + /** + * Returns the MOA KeyIdentifier. + * + * @return Returns the MOA KeyIdentifier. + */ + public String getMOAKeyIdentifier(); + + /** + * Returns the entries relevant to the search algorithm for signature blocks.
+ * e.g. properties starting with sig_obj.PROFILE.key. and + * properties of the form sig_obj.PROFILE.table.TABLENAME.NUMBER + * where PROFILE is the name of the current profile, + * TABLENAME is the name of a table and NUMBER + * is the number of the specific row within the table TABLENAME. + * + * @return The entries relevant to the signature block search algorithm as + * Java properties. + */ + public Properties getSignatureBlockEntries(); + + /** + * Returns the profile description. + * + * @return The profile description. + */ + public String getProfileDescription(); + + /** + * True only if this is the default profile according to config. + * @return + */ + public boolean isDefault(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/ConfigUtilsException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/ConfigUtilsException.java new file mode 100644 index 0000000..644f74e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/ConfigUtilsException.java @@ -0,0 +1,122 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.exceptions; + +/** + * @author Thomas Knall + */ +public class ConfigUtilsException extends Exception { + + /** + * Marker for serialization. + */ + private static final long serialVersionUID = 1L; + + /** + * The underlying exception. + */ + private Exception wrappedException; + + /** + * Returns the underlying exception. + * + * @return The underlying exception. + */ + public Exception getException() { + return this.wrappedException; + } + + /** + * Returns the message of the wrapped exception. + * + * @return The message of the wrapped exception. + */ + public String getMessage() { + String message = super.getMessage(); + if (message == null && this.wrappedException != null) { + return this.wrappedException.getMessage(); + } else { + return message; + } + } + + /** + * Instantiation of a new exception based on a message and another (wrapped) + * exception. + * + * @param message + * The exception message. + * @param exception + * Another exception. + */ + public ConfigUtilsException(final String message, final Exception exception) { + super(message); + this.wrappedException = exception; + } + + /** + * Instantiated a new exception based on a message. + * + * @param message + * The message of the new exception. + */ + public ConfigUtilsException(final String message) { + super(message); + this.wrappedException = null; + } + + /** + * Instantiates a new exception based on another (wrapped) exception. + * + * @param exception + * The wrapped exception. + */ + public ConfigUtilsException(final Exception exception) { + super(); + this.wrappedException = exception; + } + + /** + * Instantiates a new (unspecified) exception. + */ + public ConfigUtilsException() { + super(); + this.wrappedException = null; + + } + + /** + * Returns the text representation of this instance. + * + * @return The text representation of this instance. + */ + public String toString() { + if (this.wrappedException != null) { + return this.wrappedException.toString(); + } else { + return super.toString(); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java new file mode 100644 index 0000000..a050543 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/exceptions/PdfAsException.java @@ -0,0 +1,98 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/LocalBKUParams.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/LocalBKUParams.java new file mode 100644 index 0000000..b798903 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/LocalBKUParams.java @@ -0,0 +1,64 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.internal; + + +/** + * Parameter container for local BKUs. (BKU, Mocca) + * + * @author exthex + * + */ +public class LocalBKUParams { + + private String server; + private String userAgent; + private String signatureLayout; + + public LocalBKUParams(String server, String userAgent, String signatureLayout) { + this.server = server; + this.userAgent = userAgent; + this.signatureLayout = signatureLayout; + } + + public String getServer() { + return server; + } + public void setServer(String server) { + this.server = server; + } + public String getUserAgent() { + return userAgent; + } + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + public String getSignatureLayout() { + return signatureLayout; + } + public void setSignatureLayout(String signatureLayout) { + this.signatureLayout = signatureLayout; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/PdfAsInternal.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/PdfAsInternal.java new file mode 100644 index 0000000..a77051d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/PdfAsInternal.java @@ -0,0 +1,163 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.internal; + +import java.util.Map; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.analyze.AnalyzeResult; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +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.sign.SignatureDetailInformation; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * The methods of this interface are used by the pdf-as-web project and are not for external use.
+ * Using this API is inadvisable as its functionality might change without notice from release to release. + * + * @author exthex + * + */ +public interface PdfAsInternal { + + /** + * Check if a BKU with the given parameters is supported. + * + * @param bkuParams + * @throws ConnectorException if the BKU is not supported + * @throws SettingsException if the BKU is not supported + */ + public void verifyBKUSupport(LocalBKUParams bkuParams) throws ConnectorException, SettingsException; + + /** + * Finish the sign process. + * + * @param pdfAs + * @param signParameters + * @param sdi This info will most likely come from a {@link PdfAs#prepareSign(SignParameters)} call + * @param bkuParams + * @param xmlResponse the SecurityLayer response from the BKU + * @return the signed document + additional info + * @throws PdfAsException + */ + public SignResult finishLocalSign(PdfAs pdfAs, SignParameters signParameters, SignatureDetailInformation sdi, LocalBKUParams bkuParams, boolean multipart, String xmlResponse) throws PdfAsException; + + /** + * Get the security layer address for the given connector. (zB: http://127.0.0.1:3495/http-security-layer-request) + * + * @param profile + * @param device + * @return + * @throws SettingsException + */ + public String getLocalServiceAddress(String profile, String device) throws SettingsException; + + /** + * Get the CreateXMLSignatureRequest for the given parameters. + * The request will use the given callback address to retrieve the data to sign. + * + * @param signParameters the sign parameters. {@link SignParameters#getSignatureDevice()} determines the connector to use. + * @param multipart true to select a {@link at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector} that uses multipart requests + * @param loc_ref_url the URL where to retrieve the PDF to sign + * @param sdi {@link SignatureDetailInformation#getSignatureData()} provides the data to be signed. + * @return + * @throws ConnectorException + */ + public String prepareLocalSignRequest(SignParameters signParameters, boolean multipart, String loc_ref_url, SignatureDetailInformation sdi) throws ConnectorException; + + /** + * Create an AnalyzeResult from raw text, instead of a PDF. + * + * @param rawText + * @param sigValues the signature values + * @return + * @throws SignatureException + * @throws SettingsException + * @throws SignatureTypesException + * @throws NormalizeException + */ + public AnalyzeResult analyzeFromRawText(String rawText, Map sigValues) throws SignatureException, SettingsException, SignatureTypesException, NormalizeException; + + /** + * Create the SecurityLayer VerifyXMLSignatureRequest for the given parameters. + * + * @param sigInfo + * @param connector + * @param profile + * @param loc_ref_url + * @return + * @throws SignatureException + * @throws ConnectorException + */ + public String prepareLocalVerifyRequest(SignatureInformation sigInfo, String connector, String profile, String loc_ref_url) throws SignatureException, ConnectorException; + + /** + * Parse the given xml_response - must be a VerifyXMLSignatureResponse - from the BKU or Mocca and generates a VerifyResult from it. + * + * @param sigInfo + * @param connector + * @param profile + * @param loc_ref_url + * @param xmlResponse + * @return + * @throws SignatureException + * @throws ConnectorException + */ + public VerifyResult finishLocalVerify(SignatureInformation sigInfo, String connector, String profile, String loc_ref_url, String xmlResponse) throws SignatureException, ConnectorException; + + /** + * Get the {@link SignatureEntry} corresponding to a given {@link SignatureInformation} + * + * @param key + * @param sigInfo + * @return + */ + public SignatureEntry getSignatureEntryFromSignatureInformation(String key, SignatureInformation sigInfo); + + /** + * Get the signed text for a given sigInfo.
+ * If this signature is not text based this method will return null. + * + * @param sigInfo + * @return + */ + public String getSignedText(SignatureInformation sigInfo); + + /** + * Get a map of all connectors available for web. + * The key is the connector id, the value is the description. + * + * @return + * @throws ConnectorFactoryException + */ + public Map getConnectorsAvailableForWeb() throws ConnectorFactoryException; +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/SignatureEntry.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/SignatureEntry.java new file mode 100644 index 0000000..a3d77b8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/internal/SignatureEntry.java @@ -0,0 +1,137 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureEntry.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.gv.egiz.pdfas.api.internal; + +import java.io.Serializable; + +/** + * A container for signature entries. + * Copied to internal api from {@link at.knowcenter.wag.egov.egiz.sig.SignatureEntry} + * + * @author exthex + * @see at.knowcenter.wag.egov.egiz.sig.SignatureEntry + */ +public class SignatureEntry implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = -1L; + + /** + * The signature key. + */ + private String key_ = null; + /** + * The signature caption for the key found or set in the signature text. + */ + private String caption_ = null; + /** + * The signature value for the key found or set in the signature text. + */ + private String value_ = null; + + /** + * The empty constructor. + */ + public SignatureEntry() { + } + + /** + * A new SignatureEntry init with the key. + * + * @param key + */ + public SignatureEntry(String key) { + key_ = key; + } + + /** + * Returns the caption off the current key. + * + * @return Returns the caption. + */ + public String getCaption() { + return caption_; + } + + /** + * Set the caption of the current key. + * + * @param caption The caption to set. + */ + public void setCaption(String caption) { + caption_ = caption; + } + + /** + * Return the current key. + * + * @return Returns the key. + */ + public String getKey() { + return key_; + } + + /** + * Set the current key. + * + * @param key The key to set. + */ + public void setKey(String key) { + key_ = key; + } + + /** + * Return the value of the current key. + * + * @return Returns the value. + */ + public String getValue() { + return value_; + } + + /** + * Set the value of the current key. + * + * @param value The value to set. + */ + public void setValue(String value) { + value_ = value; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + String the_string = ""; + the_string += "\n Key:" + key_; + the_string += "\nCaption:" + caption_; + the_string += "\n Value:" + value_; +// the_string += "\nStart I:" + startIndex_; + return the_string; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java new file mode 100644 index 0000000..a539ce0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSink.java @@ -0,0 +1,98 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java new file mode 100644 index 0000000..4150255 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/DataSource.java @@ -0,0 +1,94 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java new file mode 100644 index 0000000..f3d0d0e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/FileBased.java @@ -0,0 +1,51 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java new file mode 100644 index 0000000..39602ff --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/io/TextBased.java @@ -0,0 +1,50 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java new file mode 100644 index 0000000..8834481 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignParameters.java @@ -0,0 +1,393 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign; + +import java.util.Properties; + +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; +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Parameter object that holds the sign parameters. + * + * @author wprinz + */ +public class SignParameters +{ +// 23.11.2010 changed by exthex - added parameters for placeholder handling + + /** + * 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.DEFAULT_SIGNATURE_TYPE; + + /** + * 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 key identifier specifying which signature key should be used + * by the signature device to perform the signature. + * + *

+ * Providing a null value (default) means that no explicit signature key + * identifier is provided. The selected signature device will then use its + * default mechanism for retrieving this information (which is usually to read + * the key from the provided signature profile). + *

+ *

+ * Note that not all signature devices may support this parameter. + * If a signature device doesn't support this parameter the value should be null. + *

+ *

+ * This key is usually passed straight through to the signature device and + * thereby has to contain an appropriate value for the signature device + * chosen. + *

+ *

+ * Currently, only the {@link Constants#SIGNATURE_DEVICE_MOA} signature device + * evaluates this parameter and passes the provided String to MOA as the MOA + * key group identifier. If null is provided, the MOA signature device will + * determine the signature key identifier to be used from the provided profile + * and, if not specified there either, from the MOA default configuration. + *

+ */ + protected String signatureKeyIdentifier = 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; + + protected TimeStamper timeStamperImpl; + + /** + * The flag to de-/activate placeholder search + */ + protected Boolean checkForPlaceholder = null; + + /** + * The id of the placeholder which should be replaced. + */ + protected String placeholderId; + + /** + * The matching mode for placeholder extraction.
+ * If a {@link SignParameters#placeholderId} is set, the match mode determines what is to be done, if no matching placeholder is found in the document. + *
+ * Defaults to {@link Constants#PLACEHOLDER_MATCH_MODE_MODERATE}. + */ + protected int placeholderMatchMode = Constants.PLACEHOLDER_MATCH_MODE_MODERATE; + + protected Properties overrideProps = new Properties(); + + + + + + /** + * {@link #setTimeStamperImpl(TimeStamper)} + * @return + */ + public TimeStamper getTimeStamperImpl() { + return this.timeStamperImpl; + } + + /** + * Set a {@link TimeStamper} to create a timestamp on the signature value. Will be + * called after sign. For binary signatures only. Timestamp will be embedded in egiz dict /TimeStamp. + * @param timeStamperImpl + */ + public void setTimeStamperImpl(TimeStamper timeStamperImpl) { + this.timeStamperImpl = timeStamperImpl; + } + +/** + * @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; + } + + /** + * @return the signatureKeyIdentifier + */ + public String getSignatureKeyIdentifier() + { + return this.signatureKeyIdentifier; + } + + /** + * @param signatureKeyIdentifier the signatureKeyIdentifier to set + */ + public void setSignatureKeyIdentifier(String signatureKeyIdentifier) + { + this.signatureKeyIdentifier = signatureKeyIdentifier; + } + + /** + * Override user defined values from the used signature profile like "value.SIG_META". + * You cannot override pre defined values like SIG_VALUE, SIG_DATE {@link SignatureTypes#REQUIRED_SIG_KEYS}. + * The override values are bound to the {@link SignParameters} instance. + *

+ * Sample usage: + *

+      SignParameters sp = new SignParameters();
+      . . .
+      
+      sp.setSignatureProfileId("SIGNATURBLOCK_DE");  
+      
+      // expressions do not work on binary signature fields without phlength setting!!
+      sp.setProfileOverrideValue("SIG_META", "It's nice to be important, but it is more important to be nice ${subject.L}");;
+      sp.setProfileOverrideValue("SIG_LABEL", "./images/signatur-logo_en.png");                  
+      
+      // execute sign using the overrides
+      pdfAs.sign(sp);
+  
+ *

+ * @param key the name of the setting to override e.g. "SIG_META" + * @param value The new value + */ + public void setProfileOverrideValue(String key, String value) { + if (SignatureTypes.isRequredSigTypeKey(key)) { + throw new RuntimeException("cannot set value for pre defined signature field names"); + } + this.overrideProps.put(key, value); + } + + /** + * Get override values created via {@link #setProfileOverrideValue(String, String)} + * @return + */ + public Properties getProfileOverrideProperties() { + return this.overrideProps; + + } + + /** + * Get the value of the checkForPlaceholder flag. + * + * @return + */ + public Boolean isCheckForPlaceholder() { + return this.checkForPlaceholder; + } + + /** + * Set this to true, if you want a search for placeholder images to be performed and + * appropriate images to be replaced. + * If this is not set, a search will only be performed if the configuration property "enable_placeholder_search" is set to true. + * + * @param check + */ + public void setCheckForPlaceholder(boolean check) { + this.checkForPlaceholder = Boolean.valueOf(check); + } + + /** + * Set an explicit placeholder id. + * Only placeholder images that have a matching ID property embedded will be considered for replacement. + * + * @param placeholderId + */ + public void setPlaceholderId(String placeholderId) { + this.placeholderId = placeholderId; + } + + /** + * The id of the placeholder to replace. + * + * @return the placeholderId + */ + public String getPlaceholderId() { + return placeholderId; + } + + /** + * Set the behavior if no exactly matching placeholder could be found.
+ * Exactly matching meaning:
+ *
  • If a placeholderId is set: a placeholder which has exactly this id embedded
  • + *
  • If no placeholderId is set: a placeholder without an embedded id is found
+ * + * @see Constants#PLACEHOLDER_MATCH_MODE_LENIENT + * @see Constants#PLACEHOLDER_MATCH_MODE_MODERATE + * @see Constants#PLACEHOLDER_MATCH_MODE_STRICT + * + * Defaults to {@link Constants#PLACEHOLDER_MATCH_MODE_MODERATE}. + * + * @param placeholderMatchMode + */ + public void setPlaceholderMatchMode(int placeholderMatchMode) { + this.placeholderMatchMode = placeholderMatchMode; + } + + /** + * Get the placeholder matching mode. + * + * @see SignParameters#getPlaceholderMatchMode() + * @return the placeholderMatchMode + */ + public int getPlaceholderMatchMode() { + return this.placeholderMatchMode; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java new file mode 100644 index 0000000..fa0282f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignResult.java @@ -0,0 +1,84 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign; + +import java.security.cert.X509Certificate; +import java.util.List; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +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(); + + /** + * Returns a list<{@link NonTextObjectInfo} of non textual objects in the pdf document. + * Only available for textual signatures. Show this to the user who signed the textual content only! + * @return List<{@link NonTextObjectInfo} or null of not available (binary signature) + */ + public List getNonTextualObjects(); + + /** + * Returns if pdf has non textual objects (only for textual signature available). + * @return + */ + public boolean hasNonTextualObjects(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignatureDetailInformation.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignatureDetailInformation.java new file mode 100644 index 0000000..c5a0263 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/SignatureDetailInformation.java @@ -0,0 +1,147 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign; + +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePosition; + +/** + * A container for all relevant signature related data. + * + * @author exthex + */ +public interface SignatureDetailInformation +{ + public DataSource getSignatureData(); + + /** + * Returns the position where the signature table was actually placed. + * + * @return Returns the position where the signature table was actually placed. + */ + public SignaturePosition getSignaturePosition(); + + /** + * Returns a list<{@link NonTextObjectInfo} of non textual objects in the pdf document. + * Only available for textual signatures. Show this to the user who signed the textual content only! + * @return List<{@link NonTextObjectInfo} or null of not available (binary signature) + */ + public List getNonTextualObjects(); + + /** + * Returns the date of signature extracted from the signature. + * @return + */ + public Date getSignDate(); + + /** + * Get the name of the issuer. + * Short for {@link SignatureDetailInformation#getX509Certificate()#getIssuer()#getName()} + * + * @return + */ + public String getIssuer(); + + /** + * Short for {@link SignatureDetailInformation#getX509Certificate()#getIssuerDNMap()} + * + * @return + */ + public Map getIssuerDNMap(); + + /** + * Short for {@link SignatureDetailInformation#getX509Certificate()#getSubjectName()#toString()} + * + * @return + */ + public String getSubjectName(); + + /** + * Short for {@link SignatureDetailInformation#getX509Certificate()#getSerialNumber()#toString()} + * + * @return + */ + public String getSerialNumber(); + + /** + * Get the algorithm the signature was created with. + * @return + */ + public String getSigAlgorithm(); + + /** + * + * @return the signature id. + */ + public String getSigID(); + + /** + * + * @return the signature method. + */ + public String getSigKZ(); + + /** + * + * @return the signature value. + */ + public String getSignatureValue(); + + /** + * + * @return the signature time stamp. + */ + public String getSigTimeStamp(); + + /** + * Short for {@link SignatureDetailInformation#getX509Certificate()#getSubjectDNMap()} + * + * @return + */ + public Map getSubjectDNMap(); + + /** + * + * @return the certificate used for signature. + */ + public X509Certificate getX509Certificate(); + + /** + * + * @return true if the signature is textual, false otherwise. + */ + public boolean isTextual(); + + /** + * + * @return true if this signature is binary, false otherwise. + */ + public boolean isBinary(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java new file mode 100644 index 0000000..eee62cd --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePosition.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java new file mode 100644 index 0000000..d46c3f2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/SignaturePositioning.java @@ -0,0 +1,296 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos; + +import java.io.Serializable; +import java.util.StringTokenizer; + +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.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +/** + * 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 implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * 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; + } + + public SignaturePositioning() { + } + + public SignaturePositioning(String position) throws PDFDocumentException { + if (position != null) { + StringTokenizer tokenizer = new StringTokenizer(position, ";"); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken().replaceAll(" ", ""); + String[] sToken = token.split(":"); + if (sToken == null || sToken.length != 2 || sToken[0].length() != 1) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + char cmd = sToken[0].toLowerCase().charAt(0); + String value = sToken[1]; + switch (cmd) { + case 'x': + if ("auto".equalsIgnoreCase(value)) { + this.setXAlgorithm(new AutoAxisAlgorithm()); + } else { + try { + this.setXAlgorithm(new AbsoluteAxisAlgorithm(Float.parseFloat(value))); + } catch (NumberFormatException e) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + } + break; + case 'y': + if ("auto".equalsIgnoreCase(value)) { + this.setYAlgorithm(new AutoAxisAlgorithm()); + } else { + try { + this.setYAlgorithm(new AbsoluteAxisAlgorithm(Float.parseFloat(value))); + } catch (NumberFormatException e) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + } + break; + case 'w': + if ("auto".equalsIgnoreCase(value)) { + this.setWidthAlgorithm(new AutoAxisAlgorithm()); + } else { + try { + this.setWidthAlgorithm(new AbsoluteAxisAlgorithm(Float.parseFloat(value))); + } catch (NumberFormatException e) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + } + break; + case 'p': + if ("auto".equalsIgnoreCase(value)) { + this.setPageAlgorithm(new AutoPageAlgorithm()); + } else if ("new".equalsIgnoreCase(value)) { + this.setPageAlgorithm(new NewPageAlgorithm()); + } else { + try { + this.setPageAlgorithm(new AbsolutePageAlgorithm(Integer.parseInt(value))); + } catch (NumberFormatException e) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + } + break; + case 'f': + try { + this.setFooterLine(Float.parseFloat(value)); + } catch (NumberFormatException e) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + break; + default: + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_POSITION, "Invalid signature position element: " + token); + } + } + } + } + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java new file mode 100644 index 0000000..ea2143d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AbsoluteAxisAlgorithm.java @@ -0,0 +1,62 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.axis; + +import java.io.Serializable; + +/** + * An absolute positioned element. + * @author wprinz + */ +public class AbsoluteAxisAlgorithm extends AxisAlgorithm implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * 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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java new file mode 100644 index 0000000..a9857b4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AutoAxisAlgorithm.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.axis; + +import java.io.Serializable; + +/** + * Auto positioning for this element. + * + * @author wprinz + */ +public class AutoAxisAlgorithm extends AxisAlgorithm implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +// empty +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java new file mode 100644 index 0000000..dd1d170 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/axis/AxisAlgorithm.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.axis; + +import java.io.Serializable; + +/** + * Determines how a certain position is chosen on the axis (x, y, width). + * + * @author wprinz + */ +public abstract class AxisAlgorithm implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +// base class +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java new file mode 100644 index 0000000..434c20c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AbsolutePageAlgorithm.java @@ -0,0 +1,64 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +import java.io.Serializable; + +/** + * The page is selected absolutely by giving the page number directly. + * + * @author wprinz + */ +public class AbsolutePageAlgorithm extends PageAlgorithm implements Serializable +{ + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * 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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java new file mode 100644 index 0000000..fffcbad --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/AutoPageAlgorithm.java @@ -0,0 +1,47 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +import java.io.Serializable; + +/** + * 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 implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; +// empty +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java new file mode 100644 index 0000000..ded9f61 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/NewPageAlgorithm.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +import java.io.Serializable; + +/** + * Places the signature on a new Page. + * + * @author wprinz + */ +public class NewPageAlgorithm extends PageAlgorithm implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + // empty block +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java new file mode 100644 index 0000000..16aa72c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/sign/pos/page/PageAlgorithm.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.sign.pos.page; + +import java.io.Serializable; + +/** + * Determines how the page on which the signature is to be placed is selected. + * + * @author wprinz + */ +public abstract class PageAlgorithm implements Serializable +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + // empty +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/DummyTimeStamper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/DummyTimeStamper.java new file mode 100644 index 0000000..f3944da --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/DummyTimeStamper.java @@ -0,0 +1,62 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.timestamp; + +import java.util.Date; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.time.DateFormatUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Dummy/test implementation of the timestamper. Logs and stores test-timestamp for assertion {@link #getLastTimeStamp()} + * + * @author dferbas + * + */ +public class DummyTimeStamper implements TimeStamper { + private static Log log = LogFactory.getLog(DummyTimeStamper.class); + + private String lastTimeStamp; + + public String applyTimeStamp(String b64SignatureValue) { + log.debug("Applying dummy timestamp on signature value: " + b64SignatureValue); + String ts = DateFormatUtils.format(new Date(), "yyyy-MM-dd'T'hh:mm:ss.SSSZ"); + log.debug("Timestamp: " + ts); + ts = new String(Base64.encodeBase64(ts.getBytes())); + log.debug("Timestamp value (base64): " + ts); + this.lastTimeStamp = ts; + return ts; + } + + public String getLastTimeStamp() { + return this.lastTimeStamp; + } + + public void setLastTimeStamp(String lastTimeStamp) { + this.lastTimeStamp = lastTimeStamp; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/TimeStamper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/TimeStamper.java new file mode 100644 index 0000000..99bda3a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/timestamp/TimeStamper.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.timestamp; + +/** + * Interface for timestamper implementations/handlers + * + * @author dferbas + * + */ +public interface TimeStamper { + + /** + * Implement timestamp in this method. + * @param b64SignatureValue signature value, base64 encoded + * @return timestamp to be embedded in egiz dictionary base64 encoded (following RFC3161). + */ + public String applyTimeStamp(String b64SignatureValue); + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java new file mode 100644 index 0000000..c169077 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/SignatureCheck.java @@ -0,0 +1,51 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java new file mode 100644 index 0000000..8b9e2c6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterAnalysisParameters.java @@ -0,0 +1,166 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + + /** + * The index of the signature to be verified. A value < 0 indicates to verify all signatures. + */ + protected int verifySignatureIndex = -1; + + /** + * @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; + } + + /** + * Set the index of the signature to verify (index starting at 0). A value < 0 indicates to verify all values. + * @param verify_which + */ + public void setVerifySignatureIndex(int verify_which) { + this.verifySignatureIndex = verify_which; + } + + public int getVerifySignatureIndex() { + return verifySignatureIndex; + } + + /** + * @see VerifyParameters#setSuppressVerifyExceptions(boolean) + * @param suppress + */ + public void setSuppressVerifyExceptions(boolean suppress) { + VerifyParameters.setSuppressVerify(suppress); + } + + public boolean isSuppressVerifyExceptions() { + return VerifyParameters.isSuppressVerifyExceptions(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterReconstructXMLDsigParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterReconstructXMLDsigParameters.java new file mode 100644 index 0000000..8f8d17c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyAfterReconstructXMLDsigParameters.java @@ -0,0 +1,169 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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.xmldsig.ReconstructXMLDsigResult; + +/** + * This class represents the parameters needed for verify after reconstructXMLDsig has already been executed. + * + * @author exthex + * + */ +public class VerifyAfterReconstructXMLDsigParameters { + + /** + * The list of signatures to be verified. + */ + protected ReconstructXMLDsigResult reconstructXMLDsigResult = 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; + + /** + * 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; + + /** + * The index of the signature to be verified. A value < 0 indicates to verify all signatures. + */ + protected int verifySignatureIndex = -1; + + /** + * @return the reconstructXMLDsigResult + */ + public ReconstructXMLDsigResult getReconstructXMLDsigResult() + { + return this.reconstructXMLDsigResult; + } + + /** + * @param reconstructXMLDsigResult + * the reconstructXMLDsigResult to set + */ + public void setReconstructXMLDsigResult(ReconstructXMLDsigResult reconstructXMLDsigResult) + { + this.reconstructXMLDsigResult = reconstructXMLDsigResult; + } + + /** + * @return the signatureDevice + */ + public String getSignatureDevice() + { + return this.signatureDevice; + } + + /** + * Set the signature device to use for verification. + * If none is set here, the signature device that was used for reconstructXMLDsig will be used. + * + * @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; + } + + /** + * Set the index of the signature to verify (index starting at 0). A value < 0 indicates to verify all values. + * @param verify_which + */ + public void setVerifySignatureIndex(int verify_which) { + this.verifySignatureIndex = verify_which; + } + + public int getVerifySignatureIndex() { + return verifySignatureIndex; + } + + /** + * @see VerifyParameters#setSuppressVerifyExceptions(boolean) + * @param suppress + */ + public void setSuppressVerifyExceptions(boolean suppress) { + VerifyParameters.setSuppressVerify(suppress); + } + + public boolean isSuppressVerifyExceptions() { + return VerifyParameters.isSuppressVerifyExceptions(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java new file mode 100644 index 0000000..e7301dc --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyParameters.java @@ -0,0 +1,249 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + + protected boolean returnNonTextualObjects = false; + + private static ThreadLocal suppressVerifyExceptions = new ThreadLocal(); + + + public VerifyParameters() { + suppressVerifyExceptions.set(Boolean.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; + } + + public boolean isReturnNonTextualObjects() { + return this.returnNonTextualObjects; + } + + /** + * Tells if non text object of the signed pdf should be extracted and returned. + * One should show this to the user, especially in case of textual signature. + * Defaults to false + * + * @param returnNonTextualObjects + */ + public void setReturnNonTextualObjects(boolean returnNonTextualObjects) { + this.returnNonTextualObjects = returnNonTextualObjects; + } + + /** + * Set if verify exceptions (because of unknown signatures) are suppressed or not (default). + * Suppressing can be helpful for multiple signatures if you want to verify the working rest. Unsupported + * Signatures are reported without throwing an exception via {@link VerifyResult#getVerificationException()} + * @param suppress + */ + public void setSuppressVerifyExceptions(boolean suppress) { + setSuppressVerify(suppress); + } + + /** + * See {@link #setSuppressVerifyExceptions(boolean)} + * @return + */ + public static boolean isSuppressVerifyExceptions() { + if (suppressVerifyExceptions.get() == null) return false; + return ((Boolean) suppressVerifyExceptions.get()).booleanValue(); + } + + static void setSuppressVerify(boolean suppress) { + suppressVerifyExceptions.set(new Boolean(suppress)); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java new file mode 100644 index 0000000..fb48e5e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResult.java @@ -0,0 +1,179 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.verify; + +import java.util.Date; +import java.util.List; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; + +/** + * Encapsulates the data of a verification of one signature. + * + * @author wprinz + */ +public interface VerifyResult extends SignatureInformation +{ + /** + * Returns if the verification was possible or could not even be startet. see {@link #getVerificationException()} for details. + * @return + */ + public boolean isVerificationDone(); + + /** + * Returns a verification exception if any. Shows that the verification could not be started. See {@link #isVerificationDone()}. + * @return + */ + public PdfAsException getVerificationException(); + + /** + * 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 {@code true} if public authority is indicated. + * @return {@code true} if public authority. + */ + public boolean isPublicAuthority(); + + /** + * Returns the public authority code or {@code null}. + * @return The public authority code or {@code null}. + */ + public String getPublicAuthorityCode(); + + /** + * 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. + *

+ *

+ * If the verification device does not return a verification time and no + * verification time was set in the + * {@link VerifyParameters#setVerificationTime(Date)} or + * {@link VerifyAfterAnalysisParameters#setVerificationTime(Date)}, the time + * returned by this method will be equal to the signing time ( + * {@link SignatureInformation#getSigningTime()}). + *

+ * + * @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 as Base64-encoded String. + * + *

+ * This will only return a value other than null if the corresponding + * {@link VerifyParameters} has been set to true. + *

+ *

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

+ * + * @return Returns the base64 encoded hash input data as returned by MOA. + * + * @see SignatureInformation#getSignedData() + */ + public String getHashInputData(); + + /** + * Returns a list<{@link NonTextObjectInfo}> of non textual objects in the pdf document. + * Only available for textual signatures. Show this to the user who signed the textual content only! + * @return List<{@link NonTextObjectInfo} or null of not available (binary signature) + */ + public List getNonTextualObjects(); + + + /** + * Returns true if non textual objects have been found, false if not. + * @return true if non textual objects have been found, false if not. + */ + public boolean hasNonTextualObjects(); + + /** + * Get the reconstructed xmldsig XML data. The reconstruction is done during the verification process. + * + * @see PdfAs#reconstructXMLDSIG(at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigParameters) + * @see PdfAs#reconstructXMLDSIG(at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigAfterAnalysisParameters) + * @return + */ + public XMLDsigData getReconstructedXMLDsig(); + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java new file mode 100644 index 0000000..44b62a7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/verify/VerifyResults.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ExtendedSignatureInformation.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ExtendedSignatureInformation.java new file mode 100644 index 0000000..df12b52 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ExtendedSignatureInformation.java @@ -0,0 +1,69 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.xmldsig; + +import at.gv.egiz.pdfas.api.commons.SignatureInformation; + +/** + * A wrapper to combine {@link SignatureInformation} and {@link XMLDsigData} + * + * @author exthex + * + */ +public class ExtendedSignatureInformation { + + private final SignatureInformation signatureInformation; + + private final XMLDsigData xmlDsigData; + + /** + * Constructor. + * + * @param siginfo + * The signature information + * @param dsigData + * The matching xmldsig to the signature information. + */ + public ExtendedSignatureInformation(SignatureInformation siginfo, XMLDsigData dsigData) { + this.signatureInformation = siginfo; + this.xmlDsigData = dsigData; + } + + /** + * + * @return the signatureInformation + */ + public SignatureInformation getSignatureInformation() { + return signatureInformation; + } + + /** + * + * @return the xmlDsigData + */ + public XMLDsigData getXmlDsigData() { + return xmlDsigData; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigAfterAnalysisParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigAfterAnalysisParameters.java new file mode 100644 index 0000000..229fba0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigAfterAnalysisParameters.java @@ -0,0 +1,86 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.xmldsig; + +import at.gv.egiz.pdfas.api.analyze.AnalyzeResult; +import at.gv.egiz.pdfas.api.commons.Constants; + +/** + * Parameters for the reconstructXMLDsig method which is to be called after a analyze call. + * + * @author exthex + * + */ +public class ReconstructXMLDsigAfterAnalysisParameters { + + + /** + * 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; + + /** + * @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; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigParameters.java new file mode 100644 index 0000000..445d7ae --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigParameters.java @@ -0,0 +1,218 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.xmldsig; + +import java.util.Date; + +import at.gv.egiz.pdfas.api.PdfAs; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.io.DataSource; + +/** + * Parameters for the {@link PdfAs#reconstructXMLDSIG(ReconstructXMLDsigParameters)} method. + * No need to call analyze before calling this method. + * + * @author exthex + * + */ +public class ReconstructXMLDsigParameters { + + /** + * 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; + + protected boolean returnNonTextualObjects = 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; + } + + public boolean isReturnNonTextualObjects() { + return this.returnNonTextualObjects; + } + + /** + * Tells if non text object of the signed pdf should be extracted and returned. + * One should show this to the user, especially in case of textual signature. + * Defaults to false + * + * @param returnNonTextualObjects + */ + public void setReturnNonTextualObjects(boolean returnNonTextualObjects) { + this.returnNonTextualObjects = returnNonTextualObjects; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigResult.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigResult.java new file mode 100644 index 0000000..580f3af --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/ReconstructXMLDsigResult.java @@ -0,0 +1,74 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.xmldsig; + +import java.util.List; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; + +/** + * The result of a reconstructXMLDsig call.
+ * This is just a wrapper for a list of {@link ExtendedSignatureInformation}s + * + * + * @author exthex + */ +public class ReconstructXMLDsigResult { + + private List extendedSignatures; + + private String device; + + /** + * + * @param extendedSignatureInfos + * @param signatureDevice + */ + public ReconstructXMLDsigResult(List extendedSignatureInfos, String signatureDevice) { + this.extendedSignatures = extendedSignatureInfos; + this.device = signatureDevice; + } + + /** + * Get the signature device that was used to create this result. + * + * @return {@link Constants#SIGNATURE_DEVICE_MOA} or {@link Constants#SIGNATURE_DEVICE_BKU} + */ + public String getDevice() { + return device; + } + + /** + * Returns the list of found signatures. + * + * @return Returns a list of {@link ExtendedSignatureInformation} objects representing all + * found signatures + {@link XMLDsigData}. + * @see SignatureInformation + */ + public List getExtendedSignatures() { + return this.extendedSignatures; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/XMLDsigData.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/XMLDsigData.java new file mode 100644 index 0000000..0449cfa --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/api/xmldsig/XMLDsigData.java @@ -0,0 +1,83 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.api.xmldsig; + +/** + * A container for XMLDsig data. + * + * @author exthex + * + */ +public class XMLDsigData { + + private String xmlDsig; + + private boolean detached; + + /** + * Constructor. + * + * @param xmldsig the xml string of the xmldsig. + * @param detached true if detached, false otherwise + */ + public XMLDsigData(String xmldsig, boolean detached) { + this.xmlDsig = xmldsig; + this.detached = detached; + } + + /** + * Get the xmldsig string + * @return + */ + public String getXmlDsig() { + return xmlDsig; + } + + /** + * Set the xmldsig string. + * + * @param xmlDsig + */ + public void setXmlDsig(String xmlDsig) { + this.xmlDsig = xmlDsig; + } + + /** + * + * @return true if detached, false otherwise + */ + public boolean isDetached() { + return detached; + } + + /** + * Set the detached. + * + * @param detached + */ + public void setDetached(boolean detached) { + this.detached = detached; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java new file mode 100644 index 0000000..6c0c19c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/CommandlineConnectorChooser.java @@ -0,0 +1,199 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.commandline; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; + +/** + * Encapsulates the logic of choosing the correct connector for the commandline + * that can later be created using the ConnectorFactory. + * + * @author wprinz + */ +public class CommandlineConnectorChooser +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(CommandlineConnectorChooser.class); + + protected static final String BKU = "bku"; //$NON-NLS-1$ + + protected static final String MOA = "moa"; //$NON-NLS-1$ + + public static boolean needsSigId (String connectorId) + { + return !ConnectorFactory.isMOA(connectorId); + } + + public static String chooseCommandlineConnectorForSign(String connectorType) throws ConnectorException + { + log.debug("Choosing Connector for commandline signation..."); + + log.debug("connector type = " + connectorType); + + if (connectorType.equals(BKU)) + { + log.debug("sig_app is BKU ==> DetachedMultipartBKUConnector"); //$NON-NLS-1$ + + return ConnectorFactory.DETACHED_MULTIPART_BKU_CONNECTOR; + } + if (connectorType.equals(MOA)) + { + // TODO MOA detached signing is not allowed at the commandline + + // TR: wurde erweitert um detached MOA-Signaturen + // log.warn("Detached MOA is not supported on the commandline. -> choosing Base64 temporarily."); + // return ConnectorFactory.ENVELOPING_BASE64_MOA_CONNECTOR; + + return ConnectorFactory.DETACHED_LOCREF_MOA_CONNECTOR; + } + + throw new ConnectorException(300, "Unknown connector type '" + connectorType + "' specified."); + } + + public static String chooseCommandlineConnectorForVerify(String connectorType, PdfASID sig_kz, String sig_id, String profile) throws ConnectorException + { + log.debug("Choosing Connector for Commandline verification..."); + + log.debug("connector type = " + connectorType); + log.debug("sig_kz = " + sig_kz); //$NON-NLS-1$ + log.debug("sig_id = " + sig_id); //$NON-NLS-1$ + + if (sig_kz == null) + { + log.debug("sig_kz is null -> choosing an old enveloped base64 connector"); //$NON-NLS-1$ + + return chooseEnvelopingBase64ConnectorOld(connectorType); + } + + log.debug("sig_kz is not null -> one of the newer signatures"); + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + log.debug("Version is 1.0.0 -> Base64 Signatur (old or Hotfix)."); + + if (sig_id == null) + { + log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter)."); + + return chooseEnvelopingBase64ConnectorHotfix(connectorType); + } + + String[] sig_id_parts = sig_id.split("@"); + if (sig_id_parts.length == 2) + { + log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector"); + + return chooseEnvelopingBase64ConnectorOld(connectorType); + } + if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX)) + { + log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector"); + + return chooseEnvelopingBase64ConnectorHotfix(connectorType); + } + + throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); + } + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0)) + { + log.debug("Version is 1.1.0 -> chose a detached connector."); + + return chooseDetachedMultipartConnector(connectorType); + } + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_2_0)) + { + log.debug("Version is 1.2.0 -> chose a detached connector."); + + return chooseDetachedMultipartConnector(connectorType); + } + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown. Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + + protected static String chooseEnvelopingBase64ConnectorOld(String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> OldEnvelopingBase64BKUConnector"); //$NON-NLS-1$ + + return ConnectorFactory.OLD_ENVELOPING_BASE64_BKU_CONNECTOR; + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> EnvelopingBase64MOAConnector"); //$NON-NLS-1$ + + return ConnectorFactory.ENVELOPING_BASE64_MOA_CONNECTOR; + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + protected static String chooseEnvelopingBase64ConnectorHotfix(String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> EnvelopingBase64BKUConnector"); //$NON-NLS-1$ + + return ConnectorFactory.ENVELOPING_BASE64_BKU_CONNECTOR; + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> EnvelopingBase64MOAConnector"); //$NON-NLS-1$ + + return ConnectorFactory.ENVELOPING_BASE64_MOA_CONNECTOR; + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected static String chooseDetachedMultipartConnector(String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> DetachedMultipartBKUConnector"); //$NON-NLS-1$ + + return ConnectorFactory.DETACHED_MULTIPART_BKU_CONNECTOR; + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> DetachedMOAConnector"); //$NON-NLS-1$ + +// String msg = "A Detached signature cannot be verified with the MOA connector (yet)."; //$NON-NLS-1$ +// log.error(msg); +// throw new ConnectorException(ErrorCode.DETACHED_SIGNATURE_NOT_SUPPORTED, msg); + return ConnectorFactory.DETACHED_LOCREF_MOA_CONNECTOR; + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/Main.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/Main.java new file mode 100644 index 0000000..52355f8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/commandline/Main.java @@ -0,0 +1,1275 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $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.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +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.ConfigUtilsException; +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.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.gv.egiz.pdfas.utils.ConfigUtils; +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.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; + +/** + * The main program entry point of the commandline tool. + * + *

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

+ * + * @author wprinz + */ +public abstract class Main +{ +// 23.11.2010 changed by exthex - added parameters for placeholder handling + /** + * 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 signaling to search the source document for a placeholder for the signature + */ + protected static final String PARAMETER_PLACEHOLDER_SEARCH = "-searchplaceholder"; + + /** + * Command line parameter selecting the id of the placeholder to use + */ + protected static final String PARAMETER_PLACEHOLDER_ID = "-placeholder_id"; + + /** + * Command line parameter selecting the match mode for the placeholder + */ + protected static final String PARAMETER_PLACEHOLDER_MATCH_MODE = "-placeholder_matchmode"; + + /** + * Command line parameter selecting the signature which is going to be + * verified. + */ + protected static final String PARAMETER_VERIFY_WHICH = "-verify_which"; + + /** + * Command line parameter that starts the deployment of the default configuration to the current + * user's home folder. + * @see Constants#USERHOME_CONFIG_FOLDER + */ + protected static final String PARAMETER_DEPLOY_DEFAULT_CONFIGURATION = "-ddc"; + + /** + * 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 value for signature mode binary. + */ + public static final String VALUE_SIGNATURE_MODE_BINARY = Constants.SIGNATURE_TYPE_BINARY; + + /** + * The value for signature mode textual. + */ + public static final String VALUE_SIGNATURE_MODE_TEXTUAL = Constants.SIGNATURE_TYPE_TEXTUAL; + + /** + * The value for signature mode detached. + */ + public static final String VALUE_SIGNATURE_MODE_DETACHED = "detached"; + + /** + * The value for signature mode detachedtextual. + */ + public static final String VALUE_SIGNATURE_MODE_DETACHED_TEXT = Constants.SIGNATURE_TYPE_DETACHEDTEXTUAL; + + /** + * The placeholder match mode STRICT + */ + public static final String VALUE_PLACEHOLDER_MATCH_MODE_STRICT = "strict"; + + /** + * The placeholder match mode STRICT + */ + public static final String VALUE_PLACEHOLDER_MATCH_MODE_MODERATE = "moderate"; + + /** + * The placeholder match mode STRICT + */ + public static final String VALUE_PLACEHOLDER_MATCH_MODE_LENIENT = "lenient"; + + /** + * 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); + + // search for PARAMETER_DEPLOY_DEFAULT_CONFIGURATION before initializing the SettingsReader + for (int i = 0; i < args.length; i++) { + if (args[i].trim().equals(PARAMETER_DEPLOY_DEFAULT_CONFIGURATION)) { + try { + String defaultConfigurationDeployedTo = ConfigUtils.deployDefaultConfiguration(); + if (defaultConfigurationDeployedTo != null) { + System.out.println("Default configuration successfully deployed to \"" + defaultConfigurationDeployedTo + "\"."); + } else { + System.out.println("Default configuration has NOT been deployed. Maybe the configuration already exists."); + } + if (args.length == 1) { + // no other parameters supplied; exit application + System.exit(0); + } + } catch (ConfigUtilsException e) { + System.err.println("Deployment of default configuration failed: " + e.getMessage()); + System.exit(1); + } + } + } + + SettingsReader.initializeForCommandLine(); + ConfigUtils.initializeLogger(); + + // printUsage(System.out); + + String mode = null; + String signature_mode = Constants.DEFAULT_SIGNATURE_TYPE; + String connector = null; + + String signature_type = null; + String user_name = null; + String user_password = null; + String pos_string = null; + + boolean search_placeholder = true; + String placeholderId = null; + int placeholderMatchMode = Constants.PLACEHOLDER_MATCH_MODE_MODERATE; + + int verify_which = -1; + + String input = null; + String output = null; + + try + { + // force settings preload + SettingsReader.getInstance(); + + // 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_DEPLOY_DEFAULT_CONFIGURATION)) { + // already applied + continue; + } + + 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_PLACEHOLDER_SEARCH)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_PLACEHOLDER_SEARCH); + return; + } + search_placeholder = Boolean.valueOf(args[i]).booleanValue(); + continue; + } + + if (cur_arg.equals(PARAMETER_PLACEHOLDER_ID)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_PLACEHOLDER_ID); + return; + } + placeholderId = args[i]; + continue; + } + + if (cur_arg.equals(PARAMETER_PLACEHOLDER_MATCH_MODE)) + { + i++; + if (i >= args.length) + { + printNoValue(PARAMETER_PLACEHOLDER_MATCH_MODE); + return; + } + String matchMode = args[i]; + if (matchMode.equals(VALUE_PLACEHOLDER_MATCH_MODE_LENIENT)) + placeholderMatchMode = Constants.PLACEHOLDER_MATCH_MODE_LENIENT; + else if (matchMode.equals(VALUE_PLACEHOLDER_MATCH_MODE_MODERATE)) + placeholderMatchMode = Constants.PLACEHOLDER_MATCH_MODE_MODERATE; + else if (matchMode.equals(VALUE_PLACEHOLDER_MATCH_MODE_STRICT)) + placeholderMatchMode = Constants.PLACEHOLDER_MATCH_MODE_STRICT; + else + printUnrecognizedValue(PARAMETER_PLACEHOLDER_MATCH_MODE, args[i]); + 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, search_placeholder, placeholderId, placeholderMatchMode); + + } + catch (PdfAsException e) + { + printPresentableException(e); + + if (output != null) + { + File oFile = new File(output); + if (oFile.exists()) { + logger_.debug("Deleting output file on error."); + 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, boolean search_placeholder, String placeholderId, int placeholderMatchMode) 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, search_placeholder, placeholderId, placeholderMatchMode); + } + 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, boolean search_placeholder, String placeholderId, int placeholderMatchMode) throws PdfAsException + { + messageOutput.println("Signing " + input + "..."); + + // 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; + File outputFile = null; + try + { + outputFile = new File(output); + + dataSink = new FileBasedDataSink(outputFile); + } + catch (IOException e) + { + throw new PDFDocumentException(ErrorCode.CANNOT_WRITE_PDF, e); + } + + try { + processSign(dataSource, connector, signature_mode, signature_type, pos_string, search_placeholder, placeholderId, placeholderMatchMode, dataSink); + } catch (Exception e) { + // Exception caught in order to delete file based datasink + if (outputFile != null && outputFile.exists()) + { + logger_.debug("Deleting output file on error."); + boolean deleted = outputFile.delete(); + if (!deleted) + { + logger_.error("Couldn't delete output file " + output); + } + } + if (e instanceof PresentableException) { + throw (PresentableException)e; + } else { + logger_.error(e); + throw new PresentableException(ErrorCode.UNKNOWN_ERROR, e); + } + } + + // 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 (" + output + ")."); + } + + public static void carryOutVerify(String input, String connector, int verify_which, PrintWriter messageOutput) throws PdfAsException + { + messageOutput.println("Verifying " + input + "..."); + + // 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 = 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); + } + + } + + /** + * Extracts the extension from a file name string. + * + *

+ * The extension of a file name is whatever text follows the last '.'. + *

+ * + * @param file_name + * The file name. + * @return Returns the extension. If the file name ends with the '.', then an + * empty string is returned. If the file name doesn't contain any '.' + * or file_name is null, null is returned. + */ + public static String extractExtension(String file_name) + { + if (file_name == null) + { + return null; + } + + int dot_index = file_name.lastIndexOf('.'); + if (dot_index < 0) + { + return null; + } + return file_name.substring(dot_index + 1); + } + + public static void processSign(DataSource dataSource, String connector, String signature_mode, String signature_type, String pos_string, boolean search_placeholder, String placeholderId, int placeholderMatchMode, DataSink dataSink) throws PdfAsException + { + 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); + sp.setCheckForPlaceholder(search_placeholder); + sp.setPlaceholderId(placeholderId); + sp.setPlaceholderMatchMode(placeholderMatchMode); + 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) + { + String errorMessage = ErrorCodeHelper.formErrorMessage(e); + System.err.println(errorMessage); +// 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]|UTILOPTIONS]"); + 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(); + + // prepare list of connectors available for commandline + ArrayList ciList = new ArrayList(); + for (int i = 0; i < ci.length; i++) { + String id = ci[i].getIdentifier(); + if (ConnectorFactory.isAvailableForCommandline(id)) { + ciList.add(ci[i]); + } + } + + // list available connectors wrapped in <...|...> + Iterator ciIt = ciList.iterator(); + writer.print("<"); + while (ciIt.hasNext()) { + writer.print(((ConnectorInformation) ciIt.next()).getIdentifier()); + if (ciIt.hasNext()) { + writer.print("|"); + } + } + writer.print(">"); + writer.println(); + +// 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("|"); +// } +// } + ciIt = ciList.iterator(); + while (ciIt.hasNext()) { + ConnectorInformation cinf = (ConnectorInformation) ciIt.next(); + writer.println(" " + cinf.getIdentifier() + " ... " + cinf.getDescription()); + } + +// 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(" UTILity OPTIONS"); + + writer.println(" " + PARAMETER_DEPLOY_DEFAULT_CONFIGURATION + " ... deploys the default configuration to the current user's home"); + + writer.println(" OPTIONS for signation:"); + + writer.println(" " + PARAMETER_SIGNATURE_MODE + " <" + VALUE_SIGNATURE_MODE_BINARY + "|" + VALUE_SIGNATURE_MODE_TEXTUAL + "> [optional]"); + writer.println(" " + VALUE_SIGNATURE_MODE_BINARY + " ... signs the complete binary document" + (Constants.DEFAULT_SIGNATURE_TYPE.equals(VALUE_SIGNATURE_MODE_BINARY) ? " (default)" : "")); + writer.println(" " + VALUE_SIGNATURE_MODE_TEXTUAL + " ... signs only the textual portion of the document" + (Constants.DEFAULT_SIGNATURE_TYPE.equals(VALUE_SIGNATURE_MODE_TEXTUAL) ? " (default)" : "")); + writer.println(" " + VALUE_SIGNATURE_MODE_DETACHED_TEXT + " ... signs the document using the textual mode and returns the xml signature of it." + (Constants.DEFAULT_SIGNATURE_TYPE.equals(VALUE_SIGNATURE_MODE_DETACHED_TEXT) ? " (default)" : "")); + + writer.print(" " + PARAMETER_SIGNATURE_TYPE + " <"); + SignatureTypes sig_types = SignatureTypes.getInstance(); + SettingsReader settings = SettingsReader.getInstance(); + Set 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(" " + PARAMETER_PLACEHOLDER_SEARCH + " ... [optional] if set to true, the source document will be scanned for signature placeholder images. If not set, the enable_placeholder_search value in the config file decides whether or not a search for placeholder images will be performed."); + writer.println(" " + PARAMETER_PLACEHOLDER_ID + " ... [optional] search for signature placeholder images containing the given id"); + writer.println(" " + PARAMETER_PLACEHOLDER_MATCH_MODE + " <" + VALUE_PLACEHOLDER_MATCH_MODE_LENIENT + "|" + VALUE_PLACEHOLDER_MATCH_MODE_MODERATE + "|" + VALUE_PLACEHOLDER_MATCH_MODE_STRICT + "> ... [optional] specify the behavior if no matching placeholder could be found. Default is ."); + writer.println(" " + VALUE_PLACEHOLDER_MATCH_MODE_LENIENT + " ... sign in place of the first found placeholder, regardless if it matches exactly, or at the end of the document if none is found."); + writer.println(" " + VALUE_PLACEHOLDER_MATCH_MODE_MODERATE + " ... sign in place of the first found placeholder which has no explicit id set, or at the end of the document if none is found."); + writer.println(" " + VALUE_PLACEHOLDER_MATCH_MODE_STRICT + " ... throws a PlaceholderExtractionException."); + + 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 + " " + Constants.SIGNATURE_DEVICE_BKU + " " + PARAMETER_SIGNATURE_MODE + " " + VALUE_SIGNATURE_MODE_TEXTUAL + " some_document.pdf"); + writer.println(" pdf-as " + PARAMETER_MODE + " " + VALUE_MODE_VERIFY + " " + PARAMETER_CONNECTOR + " " + Constants.SIGNATURE_DEVICE_BKU + " some_document.pdf_out.pdf"); + writer.println(" pdf-as " + PARAMETER_DEPLOY_DEFAULT_CONFIGURATION); + } + + /** + * 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 (meaning if it exists) + * + * @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 + { + return SignatureTypes.getInstance().getSignatureTypes().contains(signature_type); + } + + /** + * 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 + { + + if (result.isVerificationDone()) { + writer.println(" Zertifikat:"); + writer.println(" Signator: " + result.getSignerCertificate().getSubjectDN().toString()); + writer.println(" Aussteller: " + result.getSignerCertificate().getIssuerDN().toString()); + 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()); + } else { + PdfAsException ex = result.getVerificationException(); + writer.println("\n Signaturpruefung fuer diese Signatur nicht moeglich: " + ErrorCodeHelper.formErrorMessage(ex)); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java new file mode 100644 index 0000000..df321df --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCode.java @@ -0,0 +1,101 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions; + +/** + * Contains constants for the error codes. + * + *

+ * In Java 1.5 this would be an enum. + *

+ * + * @author wprinz + */ +public final class ErrorCode +{ + public static final int EXTERNAL_ERROR = 0; + public static final int UNKNOWN_ERROR = 6; + public static final int OUT_OF_MEMORY_ERROR = 7; + + public static final int SETTING_NOT_FOUND = 100; + public static final int SETTINGS_EXCEPTION = 101; + public static final int KZ_SETTING_NOT_FOUND = 102; + public static final int NO_EMBEDABLE_TTF_CONFIGURED_FOR_PDFA = 103; + public static final int INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED = 104; + public static final int MISSING_HEADER_SERVER_USER_AGENT = 105; + + public static final int DOCUMENT_CANNOT_BE_READ = 201; + public static final int TEXT_EXTRACTION_EXCEPTION = 202; + public static final int CANNOT_WRITE_PDF = 205; + public static final int DOCUMENT_NOT_SIGNED = 206; + public static final int SIGNATURE_TYPES_EXCEPTION = 223; + public static final int FONT_NOT_FOUND = 230; + public static final int DOCUMENT_IS_PROTECTED = 231; + public static final int INVALID_SIGNATURE_DICTIONARY = 232; +//23.11.2010 changed by exthex - added error code for failed extraction + public static final int SIGNATURE_PLACEHOLDER_EXTRACTION_FAILED = 233; + + public static final int INVALID_SIGNATURE_POSITION = 224; + + public static final int SIGNATURE_COULDNT_BE_CREATED = 300; + public static final int SIGNED_TEXT_EMPTY = 301; + public static final int PROFILE_NOT_DEFINED = 302; + public static final int SERIAL_NUMBER_INVALID = 303; + public static final int SIG_CERTIFICATE_CANNOT_BE_READ = 304; + public static final int PROFILE_NOT_USABLE_FOR_TEXT = 305; + + public static final int COULDNT_VERIFY = 310; + + public static final int CERTIFICATE_NOT_FOUND = 313; + public static final int NOT_SEMANTICALLY_EQUAL = 314; + + public static final int MODIFIED_AFTER_SIGNATION = 316; + public static final int NON_BINARY_SIGNATURES_PRESENT = 317; + + public static final int UNSUPPORTED_REPLACES_NAME = 318; + public static final int UNSUPPORTED_SIGNATURE = 319; + + public static final int DETACHED_SIGNATURE_NOT_SUPPORTED = 370; + + public static final int SIGNATURE_VERIFICATION_NOT_SUPPORTED = 371; + public static final int INVALID_SIGNING_TIME = 372; + + public static final int BKU_NOT_SUPPORTED = 373; + + public static final int WEB_EXCEPTION = 330; + public static final int UNABLE_TO_RECEIVE_SUITABLE_RESPONSE = 340; + + + public static final int NORMALIZER_EXCEPTION = 400; + + public static final int SESSION_EXPIRED = 600; + + public static final int PLACEHOLDER_EXCEPTION = 700; + public static final int CAPTION_NOT_FOUND_EXCEPTION = 701; + + public static final int UNABLE_TO_PARSE_ID = 800; + public static final int CORRECTOR_EXCEPTION = 801; + public static final int EXTERNAL_CORRECTOR_TIMEOUT_REACHED = 802; + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java new file mode 100644 index 0000000..25644cd --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/ErrorCodeHelper.java @@ -0,0 +1,119 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.gv.egiz.pdfas.exceptions.pdf.CaptionNotFoundException; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author wprinz + * + */ +public class ErrorCodeHelper +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(ErrorCodeHelper.class); + + public static String getMessageForErrorCode(int errorCode) + { + try + { + SettingsReader settings = SettingsReader.getInstance(); + String message = settings.getSetting("error.code." + errorCode); + return message; + } + catch (SettingsException e) + { + log.warn(e.getMessage(), e); + } + catch (SettingNotFoundException e) + { + log.warn(e.getMessage(), e); + } + return null; + } + + /** + * Forms a speaking textual error message for the given PdfAsException. + * + * @param e + * The PdfAsException to be formed into a speaking text. + * @return Returns the speaking error message explaining the PdfAsException. + */ + public static String formErrorMessage(PdfAsException e) + { + String message = "Fehler " + e.getErrorCode() + ":"; + + if (e.getErrorCode() == ErrorCode.PLACEHOLDER_EXCEPTION) + { + PlaceholderException phe = null; + if (e instanceof PlaceholderException) + { + phe = (PlaceholderException) e; + } + else + { + phe = (PlaceholderException) e.getCause(); + } + + message += " Der Platzhalter des Feldes " + phe.getField() + " ist um " + phe.getMissing() + " Bytes zu kurz."; + } + + if (e.getErrorCode() == ErrorCode.CAPTION_NOT_FOUND_EXCEPTION) + { + CaptionNotFoundException cnfe = null; + if (e instanceof CaptionNotFoundException) + { + cnfe = (CaptionNotFoundException)e; + } + else + { + cnfe = (CaptionNotFoundException)e.getCause(); + } + + message += " Die Überschrift (Caption/Label) \"" + cnfe.getCaption() + "\" wurde nicht wiedergefunden."; + } + + message += " " + ErrorCodeHelper.getMessageForErrorCode(e.getErrorCode()); + + if (e instanceof ExternalErrorException) + { + ExternalErrorException eee = (ExternalErrorException) e; + message += " Externer Fehlergrund: " + eee.getExternalErrorCode() + ": " + eee.getExternalErrorMessage(); + } + + return message; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java new file mode 100644 index 0000000..56ae6b8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/external/ExternalErrorException.java @@ -0,0 +1,66 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.external; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; + +public class ExternalErrorException extends ConnectorException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 2108427722915583885L; + + protected String externalErrorCode; + + protected String externalErrorMessage; + + public ExternalErrorException(String externalErrorCode, String externalErrorMessage) + { + super(ErrorCode.EXTERNAL_ERROR, "External Error " + externalErrorCode + ": " + externalErrorMessage); + + this.externalErrorCode = externalErrorCode; + this.externalErrorMessage = externalErrorMessage; + } + + /** + * @return the externalErrorCode + */ + public String getExternalErrorCode() + { + return externalErrorCode; + } + + /** + * @return the externalErrorMessage + */ + public String getExternalErrorMessage() + { + return externalErrorMessage; + } + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/CorrectorException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/CorrectorException.java new file mode 100644 index 0000000..ed2329f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/CorrectorException.java @@ -0,0 +1,56 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.framework; + +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * Exceptions thrown by Correctors. + * + * @author wprinz + * + */ +public class CorrectorException extends PresentableException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -8646964226476111797L; + + public CorrectorException(int errorCode, String message, Throwable cause) + { + super(errorCode, message, cause); + } + + public CorrectorException(int errorCode, String message) + { + super(errorCode, message); + } + + public CorrectorException(int errorCode, Throwable cause) + { + super(errorCode, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/PlaceholderExtractionException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/PlaceholderExtractionException.java new file mode 100644 index 0000000..62792c8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/PlaceholderExtractionException.java @@ -0,0 +1,79 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.framework; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * Exceptions thrown if STRICT matching mode for placeholder extraction is set and no placeholder could be found. + * + * @author exthex + * + */ +public class PlaceholderExtractionException extends PresentableException +{ + private static final long serialVersionUID = 0L; + + /** + * Constructor. + * + * @param errorCode the error code + * @param message the additional message + * @param cause the causing exception + * + * @see ErrorCode#SIGNATURE_PLACEHOLDER_EXTRACTION_FAILED + */ + public PlaceholderExtractionException(int errorCode, String message, Throwable cause) + { + super(errorCode, message, cause); + } + + /** + * Constructor. + * + * @param errorCode the error code + * @param message the additional message + * + * @see ErrorCode#SIGNATURE_PLACEHOLDER_EXTRACTION_FAILED + */ + public PlaceholderExtractionException(int errorCode, String message) + { + super(errorCode, message); + } + + /** + * Constructor. + * + * @param errorCode the error code + * @param cause the causing exception + * + * @see ErrorCode#SIGNATURE_PLACEHOLDER_EXTRACTION_FAILED + */ + public PlaceholderExtractionException(int errorCode, Throwable cause) + { + super(errorCode, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java new file mode 100644 index 0000000..0e819eb --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/SignatorException.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.framework; + +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + + +/** + * Exception thrown by the Signators. + * @author wprinz + */ +public class SignatorException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 5051232904560832089L; + + public SignatorException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + public SignatorException(int error_code, String message) + { + super(error_code, message); + } + + public SignatorException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + public SignatorException(PresentableException pe) + { + super(pe.getErrorCode(), pe); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java new file mode 100644 index 0000000..92ef04d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificationFilterException.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.framework; + +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * Wrapper exception for the VerificationFilter. + * + * @author wprinz + */ +public class VerificationFilterException extends PresentableException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -3863253910537746742L; + + public VerificationFilterException(int errorCode, String message, Throwable cause) + { + super(errorCode, message, cause); + } + + public VerificationFilterException(int errorCode, String message) + { + super(errorCode, message); + } + + public VerificationFilterException(int errorCode, Throwable cause) + { + super(errorCode, cause); + } + + public VerificationFilterException(PresentableException cause) + { + super(cause.getErrorCode(), cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java new file mode 100644 index 0000000..93d26cc --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/framework/VerificatorFactoryException.java @@ -0,0 +1,69 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.framework; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * @author wprinz + * + */ +public class VerificatorFactoryException extends PresentableException +{ + + /** + * + */ + private static final long serialVersionUID = 8765156531863056335L; + + /** + * @param errorCode + * @param message + */ + public VerificatorFactoryException(String message) + { + super(ErrorCode.COULDNT_VERIFY, message); + } + + /** + * @param errorCode + * @param message + * @param cause + */ + public VerificatorFactoryException(String message, Throwable cause) + { + super(ErrorCode.COULDNT_VERIFY, message, cause); + } + + /** + * @param errorCode + * @param cause + */ + public VerificatorFactoryException(Throwable cause) + { + super(ErrorCode.COULDNT_VERIFY, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/CaptionNotFoundException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/CaptionNotFoundException.java new file mode 100644 index 0000000..9a89269 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/CaptionNotFoundException.java @@ -0,0 +1,75 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.pdf; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +/** + * Exception thrown when a caption ("label") is not found in the content stream + * when determining the placeholders. + * + *

+ * This usually happens when the space for a caption is too small. Then the + * caption is wrapped into two lines and usually the separating whitespace is + * lost thus the BinarySignature is unable to find the caption String. + *

+ * + * @author wprinz + */ +public class CaptionNotFoundException extends PDFDocumentException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -8959043531007857665L; + + /** + * The problematic caption. + */ + protected String caption = null; + + /** + * Constructor. + * + * @param caption + * The problematic caption. + */ + public CaptionNotFoundException(String caption) + { + super(ErrorCode.CAPTION_NOT_FOUND_EXCEPTION, "Caption not found in content stream. caption = " + caption); + this.caption = caption; + } + + /** + * Returns the problematic caption. + * + * @return Returns the problematic caption. + */ + public String getCaption() + { + return this.caption; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java new file mode 100644 index 0000000..81e52be --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/pdf/KZSettingNotFoundException.java @@ -0,0 +1,47 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.pdf; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; + +/** + * @author wprinz + * + */ +public class KZSettingNotFoundException extends SettingNotFoundException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 2516636821733440462L; + + public KZSettingNotFoundException(String message) + { + super(ErrorCode.KZ_SETTING_NOT_FOUND, message); + } + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java new file mode 100644 index 0000000..d19ae8a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/exceptions/web/SessionExpiredException.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.exceptions.web; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * @author wprinz + * + */ +public class SessionExpiredException extends PresentableException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -1877790545371341233L; + + /** + * @param errorCode + * @param message + */ + public SessionExpiredException(String message) + { + super(ErrorCode.SESSION_EXPIRED, message); + } + + /** + * @param errorCode + * @param message + * @param cause + */ + public SessionExpiredException(String message, Throwable cause) + { + super(ErrorCode.SESSION_EXPIRED, message, cause); + } + + /** + * @param errorCode + * @param cause + */ + public SessionExpiredException(Throwable cause) + { + super(ErrorCode.SESSION_EXPIRED, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java new file mode 100644 index 0000000..c9b6238 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorFactory.java @@ -0,0 +1,107 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.MultipartDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector; + +/** + * @author wprinz + */ +public class ConnectorFactory +{ + // TODO the functionality of the connector should be split into template + // handling and the actualy hardware access + + public static String DETACHED_MULTIPART_BKU_CONNECTOR = "DetachedMultipartBKUConnector"; + + public static String ENVELOPING_BASE64_BKU_CONNECTOR = "EnvelopingBase64BKUConnector"; + + public static String OLD_ENVELOPING_BASE64_BKU_CONNECTOR = "OldEnvelopingBase64BKUConnector"; + + public static String DETACHED_LOCREF_MOA_CONNECTOR = "DetachedLocRefMOAConnector"; + + public static String ENVELOPING_BASE64_MOA_CONNECTOR = "EnvelopingBase64MOAConnector"; + + + + public static Connector createConnector (String connectorId, ConnectorParameters connectorParameters) throws ConnectorFactoryException, ConnectorException + { + if (connectorId.equals(DETACHED_MULTIPART_BKU_CONNECTOR)) + { + return new MultipartDetachedBKUConnector(connectorParameters); + } + + if (connectorId.equals(ENVELOPING_BASE64_BKU_CONNECTOR)) + { + return new EnvelopedBase64BKUConnector(connectorParameters.getProfileId()); + } + + if (connectorId.equals(OLD_ENVELOPING_BASE64_BKU_CONNECTOR)) + { + 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(connectorParameters); + } + + if (connectorId.equals(ENVELOPING_BASE64_MOA_CONNECTOR)) + { +// TODO Hier wird NICHT der neue Connector verwendet + return new EnvelopingBase64MOAConnector(connectorParameters); +// return new MOASoapWithAttachmentConnector(profile); + } + + throw new ConnectorFactoryException("The connector Id " + connectorId + " couldn't be found by the ConnectorFactory."); + } + + public static boolean isMOA (String connectorId) + { + if (connectorId.equals(DETACHED_LOCREF_MOA_CONNECTOR) || connectorId.equals(ENVELOPING_BASE64_MOA_CONNECTOR)) + { + return true; + } + + return false; + } + +// public static Connector createConnectorForCommandline (String connectorId) throws ConnectorFactoryException +// { +// } +// +// public static Connector createConnectorForCommandline (String connectorId) throws ConnectorFactoryException +// { +// } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java new file mode 100644 index 0000000..a0b7ceb --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/ConnectorParameters.java @@ -0,0 +1,118 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + + /** + * The signature key identifier to be used or null if it should be read from + * the profile. + * + *

+ * Currently this is only used by MOA connectors and identifies the MOA key + * group to be used when signing. If null, the MOA connector reads the key + * from the profile. + *

+ */ + protected String signatureKeyIdentifier = 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 String getSignatureKeyIdentifier() { + return this.signatureKeyIdentifier; + } + + public void setSignatureKeyIdentifier(String signatureKeyIdentifier) { + this.signatureKeyIdentifier = signatureKeyIdentifier; + } + + 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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java new file mode 100644 index 0000000..4f0641a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataManager.java @@ -0,0 +1,55 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +/** + * The DataManager is a mediator for all components that need to allocate large + * data elements. + * + *

+ * The DataManager uses a certain DataStrategy to perform the actual tasks. The + * strategy may be different in different environments. E.g. The commandline may + * implement a strategy to keep all data in memory, whereas the web might + * implement one that puts as many data onto the disk as possible to save + * memory. + *

+ * + * @author wprinz + * + */ +public class DataManager +{ + protected static DataStrategy dataStrategy = null; + + public static void initialize(DataStrategy ds) + { + dataStrategy = ds; + } + + public static DataStrategy getDataStrategy() + { + return dataStrategy; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataSourceHolder.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataSourceHolder.java new file mode 100644 index 0000000..355da37 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataSourceHolder.java @@ -0,0 +1,45 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +import at.gv.egiz.pdfas.framework.input.DataSource; + +public class DataSourceHolder { + private DataSource dataSource; + + public DataSourceHolder(DataSource dataSource) { + this.dataSource = dataSource; + } + + public DataSource getDataSource() { + return dataSource; + } + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java new file mode 100644 index 0000000..659ba1d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/DataStrategy.java @@ -0,0 +1,57 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +import java.io.InputStream; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; + +/** + * Factory for creating DataSources. + * + * @author wprinz + */ +public interface DataStrategy +{ + + public TextDataSource createTextDataSource (String text); + + public PdfDataSource createPdfDataSource (InputStream is); + + public PdfDataSource createPdfDataSource (DataSource other, int length); + + /** + * @deprecated - use streaming. + * @param pdf + * @return + */ + public PdfDataSource createPdfDataSource (byte [] pdf); + + public void destroyDataSource (DataSource dataSource); + + public DataSink createDataSink (); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java new file mode 100644 index 0000000..891551c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatorFactory.java @@ -0,0 +1,131 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.SignatorFactoryException; +import at.gv.egiz.pdfas.impl.signator.binary.BinarySignator_1_0_0; +import at.gv.egiz.pdfas.impl.signator.binary.BinarySignator_1_1_0; +import at.gv.egiz.pdfas.impl.signator.detached.DetachedTextualSignator_1_0_0; +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_0_0; +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_1_0; +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_2_0; +import at.gv.egiz.pdfas.framework.signator.Signator; + +/** + * @author wprinz + * + */ +public class SignatorFactory +{ + /** + * The Vendor. + */ + public static final String VENDOR = "bka.gv.at"; //$NON-NLS-1$ + + /** + * The binary Signator algorithm. + */ + public static final String TYPE_BINARY = "binaer"; //$NON-NLS-1$ + + /** + * The textual Signator algorithm. + */ + public static final String TYPE_TEXTUAL = "text"; //$NON-NLS-1$ + + /** + * Detached Signator. + */ + public static final String TYPE_DETACHED_TEXTUAL = "detachedtext"; //$NON-NLS-1$ + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_0_0 = "v1.0.0"; //$NON-NLS-1$ + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_1_0 = "v1.1.0"; //$NON-NLS-1$ + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_2_0 = "v1.2.0"; //$NON-NLS-1$ + + + public static Signator createSignator (PdfASID id) throws SignatorFactoryException + { + if (!id.getVendor().equals(VENDOR)) + { + throw new SignatorFactoryException("The vendor '" + id.getVendor() + "' is unrecognized by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + if (id.getType().equals(TYPE_BINARY)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new BinarySignator_1_0_0(); + } + if (id.getVersion().equals(VERSION_1_1_0)) + { + return new BinarySignator_1_1_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + if (id.getType().equals(TYPE_TEXTUAL)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new TextualSignator_1_0_0(); + } + if (id.getVersion().equals(VERSION_1_1_0)) + { + return new TextualSignator_1_1_0(); + } + if (id.getVersion().equals(VERSION_1_2_0)) + { + return new TextualSignator_1_2_0(); + } + + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + if (id.getType().equals(TYPE_DETACHED_TEXTUAL)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new DetachedTextualSignator_1_0_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + throw new SignatorFactoryException("The type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java new file mode 100644 index 0000000..7aaa285 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/SignatureHolderHelper.java @@ -0,0 +1,57 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.pdf.EGIZDate; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; + +public final class SignatureHolderHelper +{ + + /** + * Sorts the List of SignatureHolders by date. + * + * @param signatureHolders + * The List of SignatureHolders. + */ + public static void sortByDate(List signatureHolders) + { + Collections.sort(signatureHolders, new Comparator() { + public int compare(Object o1, Object o2) + { + SignatureHolder sh1 = (SignatureHolder) o1; + SignatureHolder sh2 = (SignatureHolder) o2; + + EGIZDate date1 = EGIZDate.parseFromString(sh1.getSignatureObject().getSignationDate()); + EGIZDate date2 = EGIZDate.parseFromString(sh2.getSignatureObject().getSignationDate()); + + return date1.compareTo(date2); + } + }); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java new file mode 100644 index 0000000..2cc964b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/VerificatorFactory.java @@ -0,0 +1,65 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework; + +import at.gv.egiz.pdfas.exceptions.framework.VerificatorFactoryException; +import at.gv.egiz.pdfas.framework.verificator.Verificator; +import at.gv.egiz.pdfas.impl.verificator.binary.BinaryVerificator_1_0_0; +import at.gv.egiz.pdfas.impl.verificator.binary.BinaryVerificator_1_1_0; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * @author wprinz + * + */ +public class VerificatorFactory +{ + + public static Verificator createVerificator(PdfASID kz) throws VerificatorFactoryException + { + if (kz.getType().equals(SignatorFactory.TYPE_BINARY)) + { + return createBinaryVerificator(kz); + } + + return null; + } + + public static Verificator createBinaryVerificator(PdfASID kz) throws VerificatorFactoryException + { + assert kz.getType().equals(SignatorFactory.TYPE_BINARY); + + if (kz.equals(BinaryVerificator_1_0_0.MY_ID)) + { + return new BinaryVerificator_1_0_0(); + } + if (kz.equals(BinaryVerificator_1_1_0.MY_ID)) + { + return new BinaryVerificator_1_1_0(); + } + + throw new VerificatorFactoryException("kz is not a known binary signator " + kz); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java new file mode 100644 index 0000000..fc9860a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/config/SettingsHelper.java @@ -0,0 +1,81 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.config; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterParametersImpl; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * Contains helpful Settings functions. + * + * @author wprinz + */ +public final class SettingsHelper +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(SettingsHelper.class); + + public static VerificationFilterParameters readVerificationFilterParametersFromSettings() throws SettingsException + { + boolean binaryOnly = getFlag("binary_only"); + boolean assumeOnlySB = getAssumeSB(); + boolean checkOld = getFlag("check_old_textual_sigs"); + + VerificationFilterParameters vfp = new VerificationFilterParametersImpl(binaryOnly, assumeOnlySB, checkOld); + return vfp; + } + + protected static boolean getFlag(String settingsKey) throws SettingsException + { + String flag = SettingsReader.getInstance().getSetting(settingsKey, "false"); + boolean b = true; + if (flag.equals("false")) + { + b = false; + } + return b; + } + + protected static boolean getAssumeSB() throws SettingsException + { + // backward compatibility for typo + String setting_with_typo = SettingsReader.getInstance().getSetting("assume_only_signauture_blocks", null); + if (setting_with_typo != null) + { + log.warn("You still have the typo in your configuration file. Please change 'assume_only_signauture_blocks' to 'assume_only_signature_blocks'. Thanks."); + boolean assumeOnlySB_typo = getFlag("assume_only_signauture_blocks"); + return assumeOnlySB_typo; + } + + boolean assumeOnlySB = getFlag("assume_only_signature_blocks"); + return assumeOnlySB; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java new file mode 100644 index 0000000..f834622 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/DataSource.java @@ -0,0 +1,70 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input; + +import java.io.InputStream; + +/** + * The input document data source. + * + *

+ * Usually this is a PdfDataSource, but it may be a TextDataSource as well. + *

+ * + * @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. + * + *

+ * Calling this method indicates that you need a byte array for random read 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. + *

+ * + * @return + */ + public byte [] getAsByteArray(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java new file mode 100644 index 0000000..19065b0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/ExtractionStage.java @@ -0,0 +1,90 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException; +import at.gv.egiz.pdfas.framework.DataSourceHolder; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilter; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; +import at.gv.egiz.pdfas.impl.input.IncrementalUpdateParser; +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterImpl; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; + +/** + * Extracts all signatures from a given input DataSource. + * + * @author wprinz + */ +public class ExtractionStage +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(ExtractionStage.class); + + public List extractSignatureHolders(final DataSourceHolder dataSource, VerificationFilterParameters parameters) throws PresentableException + { + if (dataSource.getDataSource() instanceof PdfDataSource) + { + PdfDataSource pdfDataSource = (PdfDataSource) dataSource.getDataSource(); + + PdfDataSourceHolder pdsh = new PdfDataSourceHolder(pdfDataSource); + List blocks = parsePdfIntoBlocks(pdsh); + dataSource.setDataSource(pdsh.getDataSource()); + parameters.setBeenCorrected(pdsh.hasChanged()); + + VerificationFilter vf = new VerificationFilterImpl(); + List signatures = vf.extractSignatureHolders(pdsh.getDataSource(), blocks, parameters); + + return signatures; + } + + if (dataSource.getDataSource() instanceof TextDataSource) + { + TextDataSource textDataSource = (TextDataSource) dataSource.getDataSource(); + + VerificationFilter vf = new VerificationFilterImpl(); + List signatures = vf.extractSignaturHolders(textDataSource, parameters); + + return signatures; + } + + String msg = "The input DataSource is neither pdf nor text. class.name = " + dataSource.getClass().getName(); + log.error(msg); + throw new VerificationFilterException(ErrorCode.DOCUMENT_CANNOT_BE_READ, msg); + } + + protected List parsePdfIntoBlocks(PdfDataSourceHolder pdfDataSource) throws PDFDocumentException + { + List blocks = IncrementalUpdateParser.parsePdfIntoIUBlocks(pdfDataSource); + return blocks; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java new file mode 100644 index 0000000..ce3d658 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSource.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input; + + +/** + * Represents the binary data of a PDF document. + * + *

+ * This interface allows Pdf data to be handled in an abstract way so that the + * storage (byta array, disk etc.) of pdf documents can be separated from the + * algorithms. + *

+ * + * @author wprinz + */ +public interface PdfDataSource extends DataSource +{ + // jsut a marker interface +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSourceHolder.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSourceHolder.java new file mode 100644 index 0000000..14a4ff4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/PdfDataSourceHolder.java @@ -0,0 +1,49 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input; + +public class PdfDataSourceHolder { + private PdfDataSource dataSource; + private boolean hasChanged = false; + + public PdfDataSourceHolder(PdfDataSource dataSource) { + this.dataSource = dataSource; + } + + public PdfDataSource getDataSource() { + return dataSource; + } + + public void setDataSource(PdfDataSource dataSource) { + this.dataSource = dataSource; + this.hasChanged = true; + } + + public boolean hasChanged() { + return this.hasChanged; + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java new file mode 100644 index 0000000..7623896 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/TextDataSource.java @@ -0,0 +1,39 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input; + +/** + * Represents a free-text input text to be processed. + * + * @author wprinz + */ +public interface TextDataSource extends DataSource +{ + /** + * Returns the text to be processed. + * @return Returns the text to be processed. + */ + public String getText(); + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/Corrector.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/Corrector.java new file mode 100644 index 0000000..71f3ded --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/Corrector.java @@ -0,0 +1,61 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input.correction; + +import at.gv.egiz.pdfas.exceptions.framework.CorrectorException; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +/** + * Interface for PDF corretors. + * + *

+ * Often PDF documents generated by various document to PDF converters have an + * invalid structure that upsets PDF-AS. The correction mechanism allows these + * documents to be corrected before being signed. + *

+ *

+ * A PDF corrector takes an incorrect PDF document and transforms it into a + * correct one. + *

+ *

+ * Note that correcting a document destroys all signatures in that document, so + * never correct an already signed document. + *

+ * + * @author wprinz + */ +public interface Corrector +{ + /** + * Corrects the given PDF document to a form that PDF-AS can use. + * + * @param document + * The (incorrect) PDF document. + * @return Returns the corrected PDF document. + * @throws CorrectorException + * Exception thrown if the document couldn't be corrected. + */ + public PdfDataSource correctDocument(PdfDataSource document) throws CorrectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/CorrectorFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/CorrectorFactory.java new file mode 100644 index 0000000..8c954f7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/input/correction/CorrectorFactory.java @@ -0,0 +1,63 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.input.correction; + +import at.gv.egiz.pdfas.impl.input.correction.ExternalCorrector; +import at.gv.egiz.pdfas.impl.input.correction.InternalCorrector; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * Factory for creating Correctors. + * + * @author wprinz + */ +public class CorrectorFactory +{ + public static final String INTERNAL_CORRECTOR = "internal"; + + public static final String EXTERNAL_CORRECTOR = "external"; + + public static final String CORRECTOR_KEY = "corrector"; + + public static Corrector createCorrector(String id) throws SettingsException + { + if (id.equals(INTERNAL_CORRECTOR)) + { + return new InternalCorrector(); + } + if (id.equals(EXTERNAL_CORRECTOR)) + { + return new ExternalCorrector(); + } + throw new SettingsException("The connector id '" + id + "' is not a valid corrector id."); + } + + public static Corrector createCorrector() throws SettingsException + { + String id = SettingsReader.getInstance().getSetting(CORRECTOR_KEY, INTERNAL_CORRECTOR); + return createCorrector(id); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java new file mode 100644 index 0000000..52959a9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/output/DataSink.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.output; + +import java.io.OutputStream; + +/** + * Output document data sink. + * + * @author wprinz + */ +public interface DataSink +{ + public OutputStream createOutputStream(String mimeType); + + public OutputStream createOutputStream(String mimeType, String characterEncoding); + + public String getMimeType(); + + public String getCharacterEncoding(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java new file mode 100644 index 0000000..4edc435 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SequentialSignatureDevice.java @@ -0,0 +1,45 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.sigdevice; + +/** + * A SignatureDevice that can be accessed in a sequential manner. + * + *

+ * A sequential device handles all necessary steps in sequence. E.g. all the + * data is transformed into a http request and sent to a server. The server + * processes the request and answers. The response from the server is then + * analyzed and returned. + *

+ * + * @author wprinz + */ +public interface SequentialSignatureDevice extends SignatureDevice +{ + // This is just a concept how it could be realized in future. + public void sign(); + + public void verify(); + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java new file mode 100644 index 0000000..eb7656a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/sigdevice/SignatureDevice.java @@ -0,0 +1,36 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.sigdevice; + +/** + * Performs the task of passing the signature XML and data from the application + * to an external signature device and return the response in an form that the + * application can use. + * + * @author wprinz + */ +public interface SignatureDevice +{ + // Marker interface +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java new file mode 100644 index 0000000..073af4d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/Signator.java @@ -0,0 +1,71 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Signator.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.gv.egiz.pdfas.framework.signator; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.exceptions.framework.SignatorException; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; + +/** + * The basic interface for signator algorithms. + * + * @author wprinz + */ +public interface Signator +{ + /** + * Returns the PdfASID of this Connector. + * + *

+ * This should always return the MY_ID static field of the connector. Dont't + * forget to override this. + *

+ *

+ * Within connector code always use this method so that code reuse through + * derivation can take place correctly. + *

+ * + * @return Returns the PdfASID of this Connector. + */ + public PdfASID getMyId(); + + /** + * Suppies encoding for text extraction + * @return + */ + public String getEncoding(); + + // dferbas no more has_SIG_ID + + public SignatorInformation prepareSign(PdfDataSource pdfDataSource, + String profile, TablePos pos, TimeStamper timestamper) throws SignatorException; + + + public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException; +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java new file mode 100644 index 0000000..f9efcbe --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/signator/SignatorInformation.java @@ -0,0 +1,99 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.signator; + +import java.util.List; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +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; + +/** + * Encapsulates the Signator dependant information that needs to be passed from + * prepareSign to finishSign. + * + *

+ * This supersedes the IncrementalUpdateInformation. + *

+ * + * @author wprinz + */ +public interface SignatorInformation +{ + /** + * Returns the SignatureData to be signed. + *

+ * This is passed on to the Connector and signature device for signing. + *

+ * + * @return Returns the SignatureData to be signed. + */ + public SignatureData getSignatureData(); + + /** + * Sets the SignSignatureObject with the signature data. + * + *

+ * This is called by the framework to provide the finishSign with the + * signature data. + *

+ * + * @param signSignatureObject + * 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(); + + /** + * Returns a list<{@link NonTextObjectInfo} of non textual objects in the pdf document. + * Only available for textual signatures. Show this to the user who signed the textual content only! + * @return List<{@link NonTextObjectInfo} or null of not available (binary signature) + */ + public List getNonTextualObjects(); + + /** + * Set a list<{@link NonTextObjectInfo} of non textual objects in the pdf document. + * Only available for textual signatures. Show this to the user who signed the textual content only! + */ + public void setNonTextualObjects(List nonTextObjects); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java new file mode 100644 index 0000000..78d6a2a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/verificator/Verificator.java @@ -0,0 +1,61 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Verificator.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.gv.egiz.pdfas.framework.verificator; + +import java.util.List; + +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + + +/** + * Given an Incremental Update Block and the corresponding PDF, a verificator + * extracts all Signatures of its type and returns them as valitatable + * SignatureHolders. + * + * @author wprinz + */ +public interface Verificator +{ + /** + * Parses the given document/Block for signatures of this type. + * + * @param pdf + * The whole pdf document. A Verificator must only access the + * document up to its given block (block.next_index) and must not + * modify any byte in the pdf array. + * @param block + * The incremental update block. + * @param start_of_whole_block + * The start of the incremental update block (the end of the previous + * block) - If 0, this is the first block (the original Document). + * @return Returns the List of SignatureHolder objects found for this block. + */ + public List parseBlock(PdfDataSource pdfDataSource, byte [] pdf, final FooterParseResult block, + int start_of_whole_block) throws PresentableException; + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java new file mode 100644 index 0000000..58422d2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilter.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.vfilter; + +import java.util.List; + +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; + +/** + * Extracts all signatures from a given PDF document or text. + * + * @see VerificationFilterParameters + * + * @author wprinz + */ +public interface VerificationFilter +{ + + /** + * Extracts the signatures from the given PDF. + * + * @param pdf + * The PDF. + * @param blocks + * The List of Incremental Update blocks. Usually this comes from a + * preprocessing step. + * @param parameters + * The algorithm parameters. + * @return Returns a List of SignatureHolders containing the signatures. May + * be empty in case no signatures have been found. + * @throws VerificationFilterException + * Thrown if something goes wrong. + */ + public List extractSignatureHolders(PdfDataSource pdf, List blocks, VerificationFilterParameters parameters) throws VerificationFilterException; + + /** + * Extracts the text signatures from the given free-text. + * + * @param text + * The free-text. + * @param parameters + * The algorithm parameters. + * @return Returns a List of SignatureHolders containing the signatures. May + * be empty in case no signatures have been found. + * @throws VerificationFilterException + * Thrown if something goes wrong. + */ + public List extractSignaturHolders(TextDataSource text, VerificationFilterParameters parameters) throws VerificationFilterException; +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java new file mode 100644 index 0000000..cf99086 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/framework/vfilter/VerificationFilterParameters.java @@ -0,0 +1,105 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.framework.vfilter; + +/** + * The parameters of the VerificationFilter algorithm. + * + * @author wprinz + */ +public interface VerificationFilterParameters +{ + + /** + * Tells the VerificationFilter to extract binary signatures only. + * + *

+ * Not scanning for textual signatures allows the algorithm to skip text + * extraction and signature extraction, which are both time and memory + * intensive processes. + *

+ * + * @return Returns true if the VerificationFilter should extract binary + * signatures only. + */ + public boolean extractBinarySignaturesOnly(); + + /** + * Tells the VerificationFilter to assume that there are only singatures (and + * their Incremental Update blocks) younger than the original document. + * + *

+ * This is equivalent to saying that the document was not updated using an + * Incremental update block other than a signature after being singed. The + * incremental update blocks after the original document contain only + * signatures (either text or binary). + *

+ *

+ * This is equivalent to saying that there exists no Incremental Update block + * that would render a text signature before it invalid. + *

+ *

+ * Under this assumption, the process of finding all text signatures + * simplifies to one text extraction of the whole document and one signature + * extraction. This is of course a massive performance gain. + *

+ *

+ * Actually the algorithm performs a text extraction of the whole document not + * including trailing binary signature Incremental Update blocks. This means + * that if a the last n Incremental Update blocks of a document are binary, + * there is no use extract text from them. + *

+ *

+ * Note that if there are Incremental Update blocks with text after a + * signature thus this assumption does not hold the signatures older than this + * block will break. + *

+ * + * @return Returns true if the Verification filter should assume that there + * are only signature blocks after the original document. + */ + public boolean assumeOnlySignatureUpdateBlocks(); + + /** + * Tells the VerificationFilter so scan for old signatures in the rest text. + * + *

+ * The rest text is the text of the oldest text signature or the original + * document text if there is no text signature. + *

+ * + * @return Returns true if the VerificationFilter should scan for old text + * signatures in the rest text. + */ + public boolean scanForOldSignatures(); + + /** + * Return value that tell if the document has been corrected before verification. + * + * @return + */ + public boolean hasBeenCorrected(); + + public void setBeenCorrected(boolean corrected); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java new file mode 100644 index 0000000..ee2166e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/CheckHelper.java @@ -0,0 +1,284 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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.SignatureDetailInformation; +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.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.api.sign.SignatureDetailInformationImpl; +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. + * This is a shortcut to {@link CheckHelper#checkSignParameters(SignParameters, false)} + * + * @param sp + * The {@link SignParameters} + */ + public static void checkSignParameters(SignParameters sp){ + checkSignParameters(sp, false); + } + + /** + * Checks the SignParameters for integrity. + * + * @param sp + * The {@link SignParameters} + * @param allowAllDevices if true, no check for non local BKUs will be done + */ + public static void checkSignParameters(SignParameters sp, boolean allowAllDevices) + { + 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()); + if (!allowAllDevices) + checkSignatureDevice(sp.getSignatureDevice()); + if (sp.getSignatureProfileId() != null) + { + checkProfileId(sp.getSignatureProfileId()); + } + if (sp.getSignaturePositioning() != null) + { + checkSignaturePositioning(sp.getSignaturePositioning()); + } + checkSignatureKeyIdentifier(sp.getSignatureKeyIdentifier(), sp.getSignatureDevice()); + checkTimestampHandler(sp); + } + + /** + * 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 checkTimestampHandler(SignParameters params) { + if (params.getTimeStamperImpl() != null && !Constants.SIGNATURE_TYPE_BINARY.equals(params.getSignatureType())) { + throw new IllegalArgumentException("timestamping is only allowed for binary signatures "); + } + } + + 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 \"" + profileId + "\" must be defined (code or configuration file.)"); + } + } + 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 is not valid. Please check the provided parameters."; + log.error(msg, e); + throw new IllegalArgumentException(msg); + } + } + + protected static void checkSignatureKeyIdentifier (String signatureKeyIdentifier, String signatureDevice) + { + if (signatureKeyIdentifier != null && !Constants.SIGNATURE_DEVICE_MOA.equals(signatureDevice)) + { + log.warn("A signatureKeyIdentifier (" + signatureKeyIdentifier + ") was provided although the signatureDevice (" + signatureDevice + ") is not moa. Currently only the moa signature device evaluates the signatureKeyIdentifier parameter."); + } + } + + 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); + } + } + + protected static void checkSignParametersForSignAfterPrepare(SignParameters signParameters, boolean allowAllDevices) { + checkSignParameters(signParameters, allowAllDevices); + checkProfileId(signParameters.getSignatureProfileId()); + } + + public static void checkSignatorInformation(SignatorInformation signatorInfo) { + if (signatorInfo.getSignSignatureObject() == null) + { + throw new IllegalArgumentException("The signatorInformation.getSignSignatureObject() must not be null."); + } + } + + public static void checkSignatureDetailInformation(SignatureDetailInformation signatureDetailInformation) { + if (!(signatureDetailInformation instanceof SignatureDetailInformationImpl)){ + throw new IllegalArgumentException("SignatureDetailInformation is of unsupported type. Must be " + SignatureDetailInformationImpl.class.getName()); + } + + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java new file mode 100644 index 0000000..eda94c0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PdfAsObject.java @@ -0,0 +1,865 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Vector; + +import org.apache.commons.lang.math.NumberUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +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.DynamicSignatureLifetimeEnum; +import at.gv.egiz.pdfas.api.commons.DynamicSignatureProfile; +import at.gv.egiz.pdfas.api.commons.DynamicSignatureProfileImpl; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +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.sign.SignatureDetailInformation; +import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.verify.VerifyAfterReconstructXMLDsigParameters; +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.api.xmldsig.ExtendedSignatureInformation; +import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigAfterAnalysisParameters; +import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigParameters; +import at.gv.egiz.pdfas.api.xmldsig.ReconstructXMLDsigResult; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.commandline.CommandlineConnectorChooser; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.PlaceholderExtractionException; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.gv.egiz.pdfas.framework.DataSourceHolder; +import at.gv.egiz.pdfas.framework.config.SettingsHelper; +import at.gv.egiz.pdfas.framework.input.ExtractionStage; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.signator.Signator; +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.sign.SignatureDetailInformationImpl; +import at.gv.egiz.pdfas.impl.api.verify.VerifyResultAdapter; +import at.gv.egiz.pdfas.impl.api.verify.VerifyResultsImpl; +import at.gv.egiz.pdfas.impl.input.DelimitedPdfDataSource; +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterParametersImpl; +import at.gv.egiz.pdfas.impl.xmldsig.XMLDsigReconstructor; +import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderContext; +import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderData; +import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderExtractor; +import at.gv.egiz.pdfas.utils.ConfigUtils; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.OutOfMemoryException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.AdobeSignatureHelper; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.NoSignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.ObjectExtractor; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * Implementation of the {@link PdfAs} interface. + * + * @author wprinz + */ +public class PdfAsObject implements PdfAs +{ +//23.11.2010 changed by exthex - added methods for reconstructXMLDsig + + /** + * The log. + */ + private static Log log = LogFactory.getLog(PdfAsObject.class); + + private static final String ENABLE_PLACEHOLDER_SEARCH_KEY = "enable_placeholder_search"; + + /** + * Configuration key for minimal signature block width threshold. Any width below this certain value will lead to a warning log entry." + */ + private static final String SIGNATURE_BLOCK_WIDTH_THRESHOLD_FOR_WARNING_KEY = "signature_block_width_warning_threshold"; + + /** + * Minimal signature block width. If a width below that value is defined (by parameter, by placeholder or by configuration) a warning log entry is created. + */ + public static final float DEFAULT_SIGNATURE_BLOCK_WIDTH_THRESHOLD = 150; + + + /** + * This constructor is for internal use only - use + * {@link at.gv.egiz.pdfas.PdfAsFactory} instead. + * Note: IAIK JCE and IAIK ECC security providers are automatically registered. + * + * @param workDirectory + * The work directory. + * @throws PdfAsException + * Thrown, if the configuration cannot be processed. + */ + public PdfAsObject(File workDirectory) throws PdfAsException + { + this(workDirectory, SettingsReader.REGISTER_IAIK_PROVIDERS_ON_DEFAULT); + } + + /** + * This constructor is for internal use only - use + * {@link at.gv.egiz.pdfas.PdfAsFactory} instead. + * + * @param workDirectory + * The work directory. + * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; + * false: providers will NOT be automatically registered, providers + * needed have to be registered by the API user + * @throws PdfAsException + * Thrown, if the configuration cannot be processed. + */ + public PdfAsObject(File workDirectory, boolean registerProvider) throws PdfAsException + { + String path = workDirectory != null ? workDirectory.getPath() : null; + SettingsReader.initialize(path, path); + reloadConfig(registerProvider); + } + + /** + * This constructor is for internal use only - use + * {@link at.gv.egiz.pdfas.PdfAsFactory} instead. + * Note: IAIK JCE and IAIK ECC security providers are automatically registered. + * + * @throws PdfAsException + * Thrown, if the configuration cannot be processed. + */ + public PdfAsObject() throws PdfAsException + { + this(null); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#reloadConfig() + */ + public void reloadConfig() throws PdfAsException + { + ConfigUtils.initializeLogger(); + SettingsReader.createInstance(); + SignatureTypes.createInstance(); + } + + /** + * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; + * false: providers will NOT be automatically registered, providers + * needed have to be registered by the API user + * @see at.gv.egiz.pdfas.api.PdfAs#reloadConfig() + */ + private void reloadConfig(boolean registerProvider) throws PdfAsException + { + ConfigUtils.initializeLogger(); + SettingsReader.createInstance(registerProvider); + SignatureTypes.createInstance(); + } + + /** + * @see at.gv.egiz.pdfas.api.PdfAs#getProfileInformation() + */ + public List getProfileInformation() throws PdfAsException + { + log.debug("Collecting profile information."); + 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()); + + String default_type = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + + Iterator it = profiles.iterator(); + while (it.hasNext()) + { + SignatureTypeDefinition profile = (SignatureTypeDefinition) it.next(); + + final String profileId = profile.getType(); + log.debug("Processing profile \"" + profileId + "\"."); + final String moaKeyIdentifier = settings.getSetting("sig_obj." + profileId + "." + MOA_SIGN_KEY_IDENTIFIER_KEY, defaultMoaKeyIdentifiert); + final String profileDescription = settings.getSetting("sig_obj." + profileId + "." + SignatureTypes.SIG_DESCR, null); + + boolean isDefault = (default_type != null && default_type.equals(profileId)); + // modified by tknall + SignatureProfileImpl signatureProfile = new SignatureProfileImpl(profileId, profileDescription, moaKeyIdentifier, isDefault); + + // start - added by tknall + + // signature entries relevant to the search algorithm + Properties signatureEntries = new Properties(); + + // search for table entries + String parentPropertyKey = "sig_obj." + profileId + ".table"; + log.debug("Looking for subkeys of \"" + parentPropertyKey + "\"."); + Vector keysVector = settings.getSettingKeys(parentPropertyKey); + if (keysVector != null) { + Iterator keyIt = keysVector.iterator(); + while (keyIt.hasNext()) { + String subKey = (String) keyIt.next(); + if (subKey != null && subKey.length() > 0) { + String fullKey = parentPropertyKey + "." + subKey; + String value = settings.getValueFromKey(fullKey); + int lastIndex = fullKey.lastIndexOf("."); + if (lastIndex != -1) { + String endsWith = fullKey.substring(lastIndex + 1); + if (value != null && value.length() > 0) { + if (NumberUtils.isDigits(endsWith)) { + signatureEntries.setProperty(fullKey, value); + } else { + log.debug("Ignoring table entry \"" + fullKey + "\" because it does not end with a digit. Therefore it is not relevant for the seach algorithm."); + } + } else { + log.warn("Problem detected with key \"" + fullKey + "\". The value is empty."); + } + } + } + } + } + + // search for table entries + parentPropertyKey = "sig_obj." + profileId + ".key"; + log.debug("Looking for subkeys of \"" + parentPropertyKey + "\"."); + keysVector = settings.getSettingKeys(parentPropertyKey); + if (keysVector != null) { + Iterator keyIt = keysVector.iterator(); + while (keyIt.hasNext()) { + String subKey = (String) keyIt.next(); + if (subKey != null && subKey.length() > 0) { + String fullKey = parentPropertyKey + "." + subKey; + String value = settings.getValueFromKey(fullKey); + if (value != null && value.length() > 0) { + signatureEntries.setProperty(fullKey, value); + } else { + log.warn("Problem detected with key \"" + fullKey + "\". The value is empty."); + } + } + } + } + + // set properties + signatureProfile.setSignatureBlockEntries(signatureEntries); + + // stop - added by tknall + + 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, false); + + try { + SignatureDetailInformation signatorInfo = prepareSign(signParameters); + + return sign(signParameters, signatorInfo); + + } catch (java.lang.OutOfMemoryError e) { + throw new OutOfMemoryException(ErrorCode.OUT_OF_MEMORY_ERROR, "Insufficient memory allocated to virtual machine. Start Java with parameters \"-Xms128m -Xmx786m -XX:MaxPermSize=256m\".", e); + } + + } + + /** + * @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); + VerifyResults res = verify(vaap); + + return res; + + } + + + /** + * 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()); + ap.setReturnNonTextualObjects(vp.isReturnNonTextualObjects()); + } + + protected void fillAnalyzeParametersWithReconstructXMLDsigParameters(AnalyzeParameters ap, ReconstructXMLDsigParameters rxp) + { + ap.setDocument(rxp.getDocument()); + ap.setVerifyMode(rxp.getVerifyMode()); + ap.setReturnNonTextualObjects(rxp.isReturnNonTextualObjects()); + } + + /** + * 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()); + } + + + protected void fillReconstructXMLDsigAfterAnalysisParametersWithVerifyAfterAnalysisParameters( + ReconstructXMLDsigAfterAnalysisParameters reconstructParams, + VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) { + reconstructParams.setAnalyzeResult(verifyAfterAnalysisParameters.getAnalyzeResult()); + reconstructParams.setSignatureDevice(verifyAfterAnalysisParameters.getSignatureDevice()); + } + + /** + * @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; + + try { + ExtractionStage es = new ExtractionStage(); + DataSourceHolder dsh = new DataSourceHolder(inputDataSource); + List signature_holders = es.extractSignatureHolders(dsh, parameters); + + + // List sigInfs = new ArrayList(signature_holders.size()); + List sigInfs = new ArrayList(); + List noSigs = new ArrayList(); + Iterator it = signature_holders.iterator(); + while (it.hasNext()) + { + SignatureHolder sh = (SignatureHolder)it.next(); + + if(sh instanceof NoSignatureHolder) { + noSigs.add(sh); + } else { + + SignatureInformation si = new SignatureInformationAdapter(sh); + sigInfs.add(si); + if (analyzeParameters.isReturnNonTextualObjects()) { + si.setNonTextualObjects(doExtractNonTexualObjects(sh, (PdfDataSource) dsh.getDataSource())); + } + + } + } + return new AnalyzeResultImpl(sigInfs, noSigs, parameters.hasBeenCorrected()); + } catch (java.lang.OutOfMemoryError e) { + throw new OutOfMemoryException(ErrorCode.OUT_OF_MEMORY_ERROR, "Insufficient memory allocated to virtual machine. Start Java with parameters \"-Xms128m -Xmx786m -XX:MaxPermSize=256m\".", e); + } + + } + + private List doExtractNonTexualObjects(SignatureHolder sh, PdfDataSource pdfDataSource) { + if (sh == null) return null; + if (sh instanceof BinarySignatureHolder) { + BinarySignatureHolder bsh = (BinarySignatureHolder)sh; + return ObjectExtractor.extractNonTextInfo(bsh.getSignedPdf()); + } else if (sh instanceof TextualSignatureHolder) { + TextualSignatureHolder tsh = (TextualSignatureHolder)sh; + if (tsh.getUiBlockEndPos() == 0) { + log.warn("uiblockendpos not available. Extract objects from final pdf document"); + return ObjectExtractor.extractNonTextInfo(pdfDataSource); + } + DelimitedPdfDataSource dpds = new DelimitedPdfDataSource(pdfDataSource, tsh.getUiBlockEndPos()); + return ObjectExtractor.extractNonTextInfo(dpds); + } else { + return null; + } + } + +/** + * @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(); + + // added by tknall + if (signatures == null || signatures.isEmpty()) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_NOT_SIGNED, "PDF document not signed."); //$NON-NLS-1$ + } + + ReconstructXMLDsigAfterAnalysisParameters rxaap = new ReconstructXMLDsigAfterAnalysisParameters(); + fillReconstructXMLDsigAfterAnalysisParametersWithVerifyAfterAnalysisParameters(rxaap, verifyAfterAnalysisParameters); + ReconstructXMLDsigResult reconstructResult = reconstructXMLDSIG(rxaap); + + VerifyAfterReconstructXMLDsigParameters varxp = new VerifyAfterReconstructXMLDsigParameters(); + fillVerifyAfterReconstructXMLDsigParametersWithVerifyAfterAnalysisParameters(varxp, verifyAfterAnalysisParameters); + varxp.setReconstructXMLDsigResult(reconstructResult); + + return verify(varxp); + + } + + protected void fillVerifyAfterReconstructXMLDsigParametersWithVerifyAfterAnalysisParameters( + VerifyAfterReconstructXMLDsigParameters varxp, + VerifyAfterAnalysisParameters verifyAfterAnalysisParameters) { + varxp.setReturnHashInputData(verifyAfterAnalysisParameters.isReturnHashInputData()); + varxp.setSignatureDevice(verifyAfterAnalysisParameters.getSignatureDevice()); + varxp.setVerificationTime(verifyAfterAnalysisParameters.getVerificationTime()); + varxp.setVerifySignatureIndex(verifyAfterAnalysisParameters.getVerifySignatureIndex()); + } + + /** + * @see PdfAs#reconstructXMLDSIG(ReconstructXMLDsigParameters) + */ + public ReconstructXMLDsigResult reconstructXMLDSIG( + ReconstructXMLDsigParameters reconstructXMLDsigParameters) + throws PdfAsException { + + AnalyzeParameters analyzeParameters = new AnalyzeParameters(); + fillAnalyzeParametersWithReconstructXMLDsigParameters(analyzeParameters, reconstructXMLDsigParameters); + AnalyzeResult ar = analyze(analyzeParameters); + + ReconstructXMLDsigAfterAnalysisParameters rxaap = new ReconstructXMLDsigAfterAnalysisParameters(); + rxaap.setSignatureDevice(reconstructXMLDsigParameters.getSignatureDevice()); + rxaap.setAnalyzeResult(ar); + + return reconstructXMLDSIG(rxaap); + } + + /** + * @see PdfAs#reconstructXMLDSIG(ReconstructXMLDsigAfterAnalysisParameters) + */ + public ReconstructXMLDsigResult reconstructXMLDSIG( + ReconstructXMLDsigAfterAnalysisParameters reconstructXMLDsigParameters) + throws PdfAsException { + + AnalyzeResult ar = reconstructXMLDsigParameters.getAnalyzeResult(); + List extendedSignatureInfos = new Vector(); + for (int i = 0; i < ar.getSignatures().size(); i++) + { + SignatureInformation si = (SignatureInformation)ar.getSignatures().get(i); + XMLDsigData dsigData; + try { + dsigData = XMLDsigReconstructor.reconstruct(si, reconstructXMLDsigParameters.getSignatureDevice()); + extendedSignatureInfos.add(new ExtendedSignatureInformation(si, dsigData)); + } catch (ConnectorException e) { + // don't care for connector exceptions because of mutli signs. they are handled during verify + extendedSignatureInfos.add(new ExtendedSignatureInformation(si, null)); + } + + } + return new ReconstructXMLDsigResult(extendedSignatureInfos, reconstructXMLDsigParameters.getSignatureDevice()); + } + + /** + * @see PdfAs#verify(VerifyAfterReconstructXMLDsigParameters) + */ + public VerifyResults verify( + VerifyAfterReconstructXMLDsigParameters verifyAfterReconstructXMLDsigParameters) + throws PdfAsException { + + try { + List extSignatures = verifyAfterReconstructXMLDsigParameters.getReconstructXMLDsigResult().getExtendedSignatures(); + String signatureDevice = verifyAfterReconstructXMLDsigParameters.getSignatureDevice(); + if (signatureDevice == null){ + signatureDevice = verifyAfterReconstructXMLDsigParameters.getReconstructXMLDsigResult().getDevice(); + } + List results = PdfAS.verifyExtendedSignatureHolders(extSignatures, + signatureDevice, + verifyAfterReconstructXMLDsigParameters.isReturnHashInputData(), + verifyAfterReconstructXMLDsigParameters.getVerificationTime(), verifyAfterReconstructXMLDsigParameters.getVerifySignatureIndex()); + + List vrs = new ArrayList(results.size()); + + int verifySignatureIndex = verifyAfterReconstructXMLDsigParameters.getVerifySignatureIndex(); + if (verifySignatureIndex < 0) + { + for (int i = 0; i < extSignatures.size(); i++) + { + SignatureResponse response = (SignatureResponse) results.get(i); + ExtendedSignatureInformation extSigInfo = (ExtendedSignatureInformation)extSignatures.get(i); + SignatureHolder holder = (SignatureHolder) extSigInfo.getSignatureInformation().getInternalSignatureInformation(); + + VerifyResult vr = new VerifyResultAdapter(response, holder, verifyAfterReconstructXMLDsigParameters.getVerificationTime(), extSigInfo.getXmlDsigData()); + vr.setNonTextualObjects( extSigInfo.getSignatureInformation().getNonTextualObjects()); + + vrs.add(vr); + } + }else{ + SignatureResponse response = (SignatureResponse) results.get(0); + ExtendedSignatureInformation extSigInfo = (ExtendedSignatureInformation)extSignatures.get(verifySignatureIndex); + SignatureHolder holder = (SignatureHolder) extSigInfo.getSignatureInformation().getInternalSignatureInformation(); + + VerifyResult vr = new VerifyResultAdapter(response, holder, verifyAfterReconstructXMLDsigParameters.getVerificationTime(), extSigInfo.getXmlDsigData()); + vr.setNonTextualObjects( extSigInfo.getSignatureInformation().getNonTextualObjects()); + + vrs.add(vr); + } + + VerifyResultsImpl verifyResults = new VerifyResultsImpl(vrs); + return verifyResults; + } catch (java.lang.OutOfMemoryError e) { + throw new OutOfMemoryException(ErrorCode.OUT_OF_MEMORY_ERROR, "Insufficient memory allocated to virtual machine. Start Java with parameters \"-Xms128m -Xmx786m -XX:MaxPermSize=256m\".", e); + } + } + + public DynamicSignatureProfile createDynamicSignatureProfile(String parentProfile, DynamicSignatureLifetimeEnum mode) { + return DynamicSignatureProfileImpl.createFromParent(null, parentProfile, mode); + } + + public DynamicSignatureProfile createEmptyDynamicSignatureProfile(DynamicSignatureLifetimeEnum mode) { + return DynamicSignatureProfileImpl.createEmptyProfile(null, mode); + } + + public DynamicSignatureProfile loadDynamicSignatureProfile(String name) { + return DynamicSignatureProfileImpl.loadProfile(name); + } + + public DynamicSignatureProfile createDynamicSignatureProfile(String myUniqueName, + String parentProfile, DynamicSignatureLifetimeEnum mode) { + return DynamicSignatureProfileImpl.createFromParent(myUniqueName, parentProfile, mode); + } + + public DynamicSignatureProfile createEmptyDynamicSignatureProfile(String myUniqueName, + DynamicSignatureLifetimeEnum mode) { + return DynamicSignatureProfileImpl.createEmptyProfile(myUniqueName, mode); + } + + /** + * @see PdfAs#prepareSign(SignParameters) + */ + public SignatureDetailInformation prepareSign(SignParameters signParameters) throws PdfAsException { + CheckHelper.checkSignParameters(signParameters, true); + + if (signParameters.getProfileOverrideProperties() != null) { + OverridePropertyHolder.setOverrideProps(signParameters.getProfileOverrideProperties()); + } + + signParameters.setDocument(PdfAS.applyStrictMode(signParameters.getDocument())); + + SettingsReader settings = SettingsReader.getInstance(); + String defaultProfile = settings.getValueFromKey(SignatureTypes.DEFAULT_TYPE); + + SignaturePlaceholderData spd = getSignaturePlaceholder(signParameters, defaultProfile); + if (spd != null){ + if (spd.getProfile() != null) + signParameters.setSignatureProfileId(spd.getProfile()); + if (spd.getType() != null) + signParameters.setSignatureType(spd.getType()); + if (spd.getKey() != null) + signParameters.setSignatureKeyIdentifier(spd.getKey()); + // check again, we might have destroyed something + CheckHelper.checkSignParameters(signParameters, true); + } + + if (signParameters.getSignatureProfileId() == null) + { + signParameters.setSignatureProfileId(defaultProfile); + } + + boolean fromPlaceholder = false; + boolean fromSignParameters = false; + boolean fromConfig = false; + TablePos pos = null; + if (spd != null && spd.getTablePos() != null){ + // position and width is determined by placeholder image + fromPlaceholder = true; + pos = spd.getTablePos(); + } else { + // position and width is determined by api sign parameters + pos = PosHelper.formTablePos(signParameters.getSignaturePositioning()); + if (pos != null) { + fromSignParameters = true; + } + } + + TablePos effectivePos = pos; + if (effectivePos == null) { + String pos_string = settings.getSetting(SignatureTypes.SIG_OBJ + signParameters.getSignatureProfileId() + ".pos", null); + if (pos_string != null) { + // position and width is determined by profile configuration + effectivePos = PdfAS.parsePositionFromPosString(pos_string); + fromConfig = true; + } + } + if (effectivePos != null) { + // check if width is lower than the smallest meaningful width + String thresholdString = AdobeSignatureHelper.getDefaultableConfigProperty(signParameters.getSignatureProfileId(), SIGNATURE_BLOCK_WIDTH_THRESHOLD_FOR_WARNING_KEY, String.valueOf(DEFAULT_SIGNATURE_BLOCK_WIDTH_THRESHOLD)); + float threshold = DEFAULT_SIGNATURE_BLOCK_WIDTH_THRESHOLD; + try { + threshold = Float.parseFloat(thresholdString); + } catch (NumberFormatException e) { + if (log.isDebugEnabled()) { + log.debug("Unable to parse threshold value (\"" + thresholdString + "\") of configuration value \"" + SIGNATURE_BLOCK_WIDTH_THRESHOLD_FOR_WARNING_KEY + "\". Using default value: " + DEFAULT_SIGNATURE_BLOCK_WIDTH_THRESHOLD); + } + } + if (!effectivePos.isWauto() && effectivePos.getWidth() < threshold) { + String msg = "The {0} for the signature block is very small ({1}). The signature block might not get placed correcty."; + String[] arguments = new String[]{ "given width", "" + effectivePos.getWidth()}; + // very small, warn user + if (fromPlaceholder) { + arguments[0] = "width given by the placeholder image"; + } else if (fromSignParameters) { + arguments[0] = "width defined by the sign parameters"; + } else if (fromConfig) { + arguments[0] = "width defined by the profile " + signParameters.getSignatureProfileId(); + } + log.warn(MessageFormat.format(msg, arguments)); + } + } + + Signator signator = createSignator(signParameters.getSignatureType()); + + SignatorInformation signatorInfo = signator.prepareSign( + new PdfDataSourceAdapter(signParameters.getDocument()), + signParameters.getSignatureProfileId(), + pos, + signParameters.getTimeStamperImpl()); + + SignatureDetailInformationImpl ret = new SignatureDetailInformationImpl(); + ret.setSignatorInformation(signatorInfo); + return ret; + + } + + private SignaturePlaceholderData getSignaturePlaceholder(SignParameters signParameters, + String defaultProfile) throws SettingsException, PDFDocumentException, PlaceholderExtractionException { + SignaturePlaceholderData spd = null; + SignaturePlaceholderContext.setSignaturePlaceholderData(null); + + SettingsReader settings = SettingsReader.getInstance(); + + // check sig_obj.PROFILEID.enable_placeholder_search + String profile = signParameters.getSignatureProfileId(); + if (profile == null) + profile = defaultProfile; + String key = SignatureTypes.SIG_OBJ + profile + "." + ENABLE_PLACEHOLDER_SEARCH_KEY; + String configFileActivedString = settings.getValueFromKey(key); + + if (configFileActivedString == null){ + // check global enable_placeholder_search + configFileActivedString = settings.getValueFromKey(ENABLE_PLACEHOLDER_SEARCH_KEY); + } + + Boolean configFileActived = null; + if (configFileActivedString != null) + configFileActived = Boolean.valueOf(configFileActivedString); + + Boolean signParamsActivated = signParameters.isCheckForPlaceholder(); + + boolean enableSearch; + + if (signParamsActivated != null) + { + enableSearch = signParamsActivated.booleanValue(); + } else { + if (configFileActived != null) + enableSearch = configFileActived.booleanValue(); + else + enableSearch = false; + } + + if (enableSearch) + { + spd = SignaturePlaceholderExtractor.extract( + signParameters.getDocument().createInputStream(), + signParameters.getPlaceholderId(), + signParameters.getPlaceholderMatchMode()); + } + return spd; + } + + private Signator createSignator(String signatureType) throws SignatorFactoryException { + PdfASID signatorId = null; + if (signatureType.equals(Constants.SIGNATURE_TYPE_BINARY)) + { + signatorId = SignatorFactory.MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signatureType.equals(Constants.SIGNATURE_TYPE_TEXTUAL)) + { + signatorId = SignatorFactory.MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signatureType.equals(Constants.SIGNATURE_TYPE_DETACHEDTEXTUAL)) + { + signatorId = SignatorFactory.MOST_RECENT_DETACHEDTEXT_SIGNATOR_ID; + } + + return at.gv.egiz.pdfas.framework.SignatorFactory.createSignator(signatorId); + + } + + public SignResult sign(SignParameters signParameters, SignatureDetailInformation signatorInfo) + throws PdfAsException { + CheckHelper.checkSignParametersForSignAfterPrepare(signParameters, false); + + if (signParameters.getProfileOverrideProperties() != null) { + OverridePropertyHolder.setOverrideProps(signParameters.getProfileOverrideProperties()); + } + + String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForSign(signParameters.getSignatureDevice()); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(signParameters.getSignatureProfileId()); + cp.setSignatureKeyIdentifier(signParameters.getSignatureKeyIdentifier()); + Connector c = at.gv.egiz.pdfas.framework.ConnectorFactory.createConnector(connectorId, cp); + + SignatureData sd = new SignatureDataImpl(new PdfDataSourceAdapter(signatorInfo.getSignatureData()), signatorInfo.getSignatureData().getMimeType()); + SignSignatureObject sso = PdfAS.sign(sd, c, signParameters.getTimeStamperImpl()); + ((SignatureDetailInformationImpl)signatorInfo).setSignSignatureObject(sso); + + return finishSign(signParameters, signatorInfo); + } + + public SignResult finishSign(SignParameters signParameters, SignatureDetailInformation signatureDetailInformation) + throws PdfAsException { + try { + CheckHelper.checkSignParametersForSignAfterPrepare(signParameters, true); + CheckHelper.checkSignatureDetailInformation(signatureDetailInformation); + + if (signParameters.getProfileOverrideProperties() != null) { + OverridePropertyHolder.setOverrideProps(signParameters.getProfileOverrideProperties()); + } + + Signator signator = createSignator(signParameters.getSignatureType()); + + SignatorInformation signatorInfo = ((SignatureDetailInformationImpl)signatureDetailInformation).getSignatorInfo(); + signator.finishSign(signatorInfo, new DataSinkAdapter(signParameters.getOutput())); + + return new SignResultImpl( + signParameters.getOutput(), + signatorInfo.getSignSignatureObject().getX509Certificate(), + new ActualSignaturePositionAdapter(signatorInfo.getActualTablePos()), + signatorInfo.getNonTextualObjects()); + } finally { + OverridePropertyHolder.removeProperties(); + DynamicSignatureProfileImpl.disposeLocalProfile(); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java new file mode 100644 index 0000000..cfb811e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/PosHelper.java @@ -0,0 +1,99 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java new file mode 100644 index 0000000..5e25ced --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/analyze/AnalyzeResultImpl.java @@ -0,0 +1,116 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + + /** + * The found non-signature update blocks. + */ + protected List noSignatures = null; + + protected boolean hasBeenCorrected = false; + + + /** + * Constructor. + * + * @param signatures + * The found signatures. + * @param noSignatures + * The found non-signature update blocks. + */ + public AnalyzeResultImpl(List signatures, List noSignatures, boolean hasBeenCorrected) + { + if (signatures == null) + { + throw new IllegalArgumentException("The list of found signatures must not be null."); + } + + this.signatures = signatures; + this.noSignatures = noSignatures; + this.hasBeenCorrected = hasBeenCorrected; + } + + + /** + * 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; + } + + public List getNoSignatures() { + + return this.noSignatures; + } + + /** + * Tells if the document has been corrected before verification. The correction maybe done + * after a first failing parse to repair a document (if enabled in the configuration + * correct_document_on_verify_if_necessary). The correction can only work for textual + * signatures. Binary signatures are lost anyhow. + * @return + */ + public boolean hasBeenCorrected() { + return hasBeenCorrected; + } + + public void setHasBeenCorrected(boolean hasBeenCorrected) { + this.hasBeenCorrected = hasBeenCorrected; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java new file mode 100644 index 0000000..2aee44f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSinkAdapter.java @@ -0,0 +1,103 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java new file mode 100644 index 0000000..8db3fcf --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/DataSourceApiAdapter.java @@ -0,0 +1,105 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java new file mode 100644 index 0000000..6336071 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/PdfDataSourceAdapter.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java new file mode 100644 index 0000000..34c706b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureInformationAdapter.java @@ -0,0 +1,133 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.List; + +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.BinarySignatureHolder; +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; + + protected String timeStamp = null; + + protected List nonTextualObjects = null; + + /** + * Constructor. + * + * @param signatureHolder + * The framework SignatureHolder to be adapted to an API + * SignatureInformation. + */ + public SignatureInformationAdapter(SignatureHolder signatureHolder) + { + this.signatureHolder = signatureHolder; + if (signatureHolder instanceof BinarySignatureHolder) { + this.timeStamp = ((BinarySignatureHolder)signatureHolder).getSignatureObject().getTimeStamp(); + } + } + + /** + * @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; + } + + public String getTimeStampValue() { + return this.timeStamp; + } + + public List getNonTextualObjects() { + return this.nonTextualObjects; + } + + public boolean hasNonTextualObjects() { + return this.nonTextualObjects != null && this.nonTextualObjects.size() > 0; + } + + public void setNonTextualObjects(List nonTextualObjects) { + this.nonTextualObjects = nonTextualObjects; + } + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java new file mode 100644 index 0000000..35d8c17 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/SignatureProfileImpl.java @@ -0,0 +1,158 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.util.Properties; + +import org.apache.commons.lang.builder.ToStringBuilder; + +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; + + /** + * Properties containing the layout settings relevant to the search algorithm + * for signature blocks. + */ + protected Properties signatureBlockEntries; + + /** + * Short description of the profile. + */ + protected String profileDescription; + + /** + * true if this is the default profile, false otherwise. + */ + protected boolean defaultProfile = false; + + /** + * Constructor. + * + * @param profileId + * The profile identifier. + * @param moaKeyIdentifier + * The MOA key identifier of this profile. + */ + public SignatureProfileImpl(String profileId, String moaKeyIdentifier) { + this.profileId = profileId; + this.moaKeyIdentifier = moaKeyIdentifier; + this.signatureBlockEntries = new Properties(); + } + + /** + * Constructor. + * + * @param profileId + * The profile identifier. + * @param profileDescription + * The profile description. + * @param moaKeyIdentifier + * The MOA key identifier of this profile. + * @param isDefault + */ + public SignatureProfileImpl(String profileId, String profileDescription, String moaKeyIdentifier, boolean isDefault) { + this.profileId = profileId; + this.moaKeyIdentifier = moaKeyIdentifier; + this.profileDescription = profileDescription; + this.signatureBlockEntries = new Properties(); + this.defaultProfile = isDefault; + } + + /** + * @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; + } + + /** + * @see at.gv.egiz.pdfas.api.commons.SignatureProfile#getSignatureBlockEntries() + */ + public Properties getSignatureBlockEntries() { + return this.signatureBlockEntries; + } + + /** + * Sets the entries relevant to the search algorithm for signature blocks.
+ * e.g. properties starting with sig_obj.PROFILE.key. and + * properties of the form sig_obj.PROFILE.table.TABLENAME.NUMBER + * where PROFILE is the name of the current profile, + * TABLENAME is the name of a table and NUMBER + * is the number of the specific row within the table TABLENAME. + * + * @param signatureBlockEntries + * The entries relevant to the signature block search algorithm as + * Java properties. + */ + public void setSignatureBlockEntries(Properties signatureBlockEntries) { + this.signatureBlockEntries = signatureBlockEntries; + } + + /** + * Returns the profile description. + * @return The profile description. + */ + public String getProfileDescription() { + return this.profileDescription; + } + + public String toString() { + return new ToStringBuilder(this) + .append("profileId", this.profileId) + .append("profileDescription", this.profileDescription) + .append("moaKeyIdentifier", this.moaKeyIdentifier) + .toString(); + } + + /** + * + */ + public boolean isDefault() { + return this.defaultProfile; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextBasedDataSourceApiAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextBasedDataSourceApiAdapter.java new file mode 100644 index 0000000..5685490 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextBasedDataSourceApiAdapter.java @@ -0,0 +1,92 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api.commons; + +import java.io.InputStream; + +import at.gv.egiz.pdfas.api.io.TextBased; +import at.gv.egiz.pdfas.framework.input.TextDataSource; + +/** + * Adapter that converts a framework DataSource to an API PdfDataSource. + * + * @author wprinz + */ +public class TextBasedDataSourceApiAdapter implements at.gv.egiz.pdfas.api.io.DataSource, TextBased +{ + /** + * The framework DataSource to be adapted to an API DataSource. + */ + protected TextDataSource frameworkDataSource = null; + + /** + * Constructor. + * + * @param frameworkDataSource + * The framework DataSource to be adapted to an API DataSource. + */ + public TextBasedDataSourceApiAdapter(TextDataSource 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() + { + return "UTF-8"; + } + + public String getMimeType() + { + return "text/plain"; + } + + public String getText() { + return this.frameworkDataSource.getText(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java new file mode 100644 index 0000000..39f88e2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/commons/TextDataSourceAdapter.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/internal/PdfAsInternalObject.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/internal/PdfAsInternalObject.java new file mode 100644 index 0000000..b817ea9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/internal/PdfAsInternalObject.java @@ -0,0 +1,362 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api.internal; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.PdfAs; +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.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.internal.LocalBKUParams; +import at.gv.egiz.pdfas.api.internal.PdfAsInternal; +import at.gv.egiz.pdfas.api.internal.SignatureEntry; +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.api.sign.SignResult; +import at.gv.egiz.pdfas.api.sign.SignatureDetailInformation; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.impl.api.CheckHelper; +import at.gv.egiz.pdfas.impl.api.analyze.AnalyzeResultImpl; +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.sign.SignatureDetailInformationImpl; +import at.gv.egiz.pdfas.impl.api.verify.VerifyResultAdapter; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +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.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.LocRefDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.MultipartDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper; + +/** + * @see PdfAsInternal + * + * @author exthex + * + */ +public class PdfAsInternalObject implements PdfAsInternal { + /** + * The log. + */ + private static Log log = LogFactory.getLog(CheckHelper.class); + + /** + * @see PdfAsInternal#verifyBKUSupport(LocalBKUParams) + */ + public void verifyBKUSupport(LocalBKUParams bkuParams) throws ConnectorException, SettingsException { + String bkuIdentifier = BKUHelper.getBKUIdentifier(bkuParams); + SignatureLayoutHandlerFactory.verifyBKUSupport(bkuIdentifier); + } + + /** + * @see PdfAsInternal#finishLocalSign(PdfAs, SignParameters, SignatureDetailInformation, LocalBKUParams, String) + */ + public SignResult finishLocalSign(PdfAs pdfAs, SignParameters signParameters, SignatureDetailInformation sdi, LocalBKUParams bkuParams, boolean multipart, String xmlResponse) throws PdfAsException { + LocalConnector c = chooseLocalConnectorForSign(signParameters.getSignatureDevice(), signParameters.getSignatureProfileId(), "not needed", multipart); + SignSignatureObject sso = c.analyzeSignResponse(buildResponseProperties(bkuParams, xmlResponse)); + ((SignatureDetailInformationImpl)sdi).setSignSignatureObject(sso); + + return pdfAs.finishSign(signParameters, sdi); + } + + private Properties buildResponseProperties(LocalBKUParams bkuParams, String xmlResponse) { + Properties ret = new Properties(); + if (bkuParams.getServer() != null) + ret.setProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY, bkuParams.getServer()); + if (bkuParams.getUserAgent() != null) + ret.setProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY, bkuParams.getUserAgent()); + if (bkuParams.getSignatureLayout() != null) + ret.setProperty(BKUPostConnection.BKU_SIGNATURE_LAYOUT_HEADER_KEY, bkuParams.getSignatureLayout()); + ret.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, xmlResponse); + return ret; + } + + private LocalConnector chooseLocalConnectorForSign(String device, String profile, String loc_ref_url, boolean multipart) throws ConnectorException{ + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + + if (Constants.SIGNATURE_DEVICE_MOC.equals(device)) { + if (!multipart) { + return new LocRefDetachedMOCCAConnector(cp, loc_ref_url); + } + } else if (Constants.SIGNATURE_DEVICE_BKU.equals(device)){ + if (multipart) { + return new MultipartDetachedBKUConnector(cp); + } else { + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + } else if (Constants.SIGNATURE_DEVICE_MOBILE.equals(device)){ + if (multipart) { + return new MultipartDetachedBKUConnector(cp); + } else { + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + } else if (Constants.SIGNATURE_DEVICE_MOBILETEST.equals(device)){ + if (multipart) { + return new MultipartDetachedBKUConnector(cp); + } else { + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + } + + + log.error("Currently only the BKU connector is fully implemented."); + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + + private LocalConnector chooseLocalConnectorForVerify(String connector, + PdfASID sig_kz, String sig_id, String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing LocalConnector for verification..."); + + log.debug("connector type = " + connector); + log.debug("sig_kz = " + sig_kz); + log.debug("sig_id = " + sig_id); + + if (!connector.equals("bku")) + { + log.error("Currently only the BKU connector is fully implemented."); + } + + if (sig_kz == null) + { + log.debug("sig_kz is null -> must be old signature -> choosing old Base64 connector."); + + return new OldEnvelopingBase64BKUConnector(profile); + } + + log.debug("sig_kz is not null -> must be one of the newer ... base64, base64 hotfix, or detached"); + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + log.debug("sig_kz version is 1.0.0 -> choosing base64 (old or hotfix)"); + + if (sig_id == null) + { + log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter)."); + + return new EnvelopedBase64BKUConnector(profile); + } + + String[] sig_id_parts = sig_id.split("@"); + if (sig_id_parts.length == 2) + { + log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector"); + + return new OldEnvelopingBase64BKUConnector(profile); + } + if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX)) + { + log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector"); + + return new EnvelopedBase64BKUConnector(profile); + } + + throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); + } + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0) || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_2_0)) + { + log.debug("sig_kz version is 1.1.0/1.2.0 -> choosing detached (loc ref) connector."); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown."); + } + + /** + * @see PdfAsInternal#getLocalServiceAddress(String, String) + */ + public String getLocalServiceAddress(String profile, String device) throws SettingsException { + SettingsReader settings = SettingsReader.getInstance(); + + String key = device + ".sign.url"; + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + /** + * @see PdfAsInternal#prepareLocalSignRequest(SignParameters, String, SignatureDetailInformation) + */ + public String prepareLocalSignRequest(SignParameters signParameters, boolean multipart, String loc_ref_url, + SignatureDetailInformation sdi) throws ConnectorException { + LocalConnector c = chooseLocalConnectorForSign(signParameters.getSignatureDevice(), signParameters.getSignatureProfileId(), loc_ref_url, multipart); + SignatureData sd = new SignatureDataImpl(new PdfDataSourceAdapter(sdi.getSignatureData()), sdi.getSignatureData().getMimeType(), sdi.getSignatureData().getCharacterEncoding()); + String sign_request = c.prepareSignRequest(sd); + return sign_request; + } + + /** + * @see PdfAsInternal#analyzeFromRawText(String, Map) + */ + public AnalyzeResult analyzeFromRawText(String rawText, Map sigValues) throws SignatureException, SettingsException, SignatureTypesException, NormalizeException { + String normalizedText = PdfAS.normalizeText(rawText); + + SignatureObject signature_object = new SignatureObject(); + + String default_type = SettingsReader.getInstance().getValueFromKey(SignatureTypes.DEFAULT_TYPE); + signature_object.setSigType(default_type); + signature_object.initByType(); + + Iterator sigKeys = sigValues.keySet().iterator(); + while (sigKeys.hasNext()){ + String key = (String)sigKeys.next(); + signature_object.setSigValue(key, (String)sigValues.get(key)); + } + + TextDataSource tds = new TextDataSourceImpl(normalizedText); + SignatureHolder new_holder = new TextualSignatureHolder(tds, signature_object); + + SignatureInformation si = new SignatureInformationAdapter(new_holder); + List signatures = new Vector(); + signatures.add(si); + AnalyzeResult ret = new AnalyzeResultImpl(signatures); + return ret; + } + + /** + * @see PdfAsInternal#prepareLocalVerifyRequest(SignatureInformation, String, String, String) + */ + public String prepareLocalVerifyRequest(SignatureInformation sigInfo, String connector, String profile, String loc_ref_url) throws SignatureException, ConnectorException { + + SignatureHolder holder = (SignatureHolder)sigInfo.getInternalSignatureInformation(); + SignatureObject s = holder.getSignatureObject(); + + SignatureData sd = PdfAS.convertSignatureHolderToSignatureData(holder); + + SignSignatureObject so = SignatureObjectHelper.convertSignatureObjectToSignSignatureObject(s); + + LocalConnector local_conn = chooseLocalConnectorForVerify(connector, s.getKZ(), so.id, profile, loc_ref_url); + + String request_string = local_conn.prepareVerifyRequest(sd, so, null); + return request_string; + } + + /** + * @see PdfAsInternal#finishLocalVerify(SignatureInformation, String, String, String, String) + */ + public VerifyResult finishLocalVerify(SignatureInformation sigInfo, String connector, String profile, String loc_ref_url, String xmlResponse) throws SignatureException, ConnectorException { + SignatureHolder holder = (SignatureHolder)sigInfo.getInternalSignatureInformation(); + SignatureObject s = holder.getSignatureObject(); + + SignSignatureObject so = SignatureObjectHelper.convertSignatureObjectToSignSignatureObject(s); + + LocalConnector local_conn = chooseLocalConnectorForVerify(connector, s.getKZ(), so.id, profile, loc_ref_url); + + Properties props = new Properties(); + props.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, xmlResponse); + SignatureResponse sigResponse = local_conn.analyzeVerifyResponse(props); + return new VerifyResultAdapter(sigResponse, holder, null, null); // timestamp and xmldsig not needed here + } + + /** + * @see PdfAsInternal#getSignatureEntryFromSignatureInformation(String, SignatureInformation) + */ + public SignatureEntry getSignatureEntryFromSignatureInformation(String key, + SignatureInformation sigInfo) { + + SignatureHolder holder = (SignatureHolder)sigInfo.getInternalSignatureInformation(); + SignatureObject s = holder.getSignatureObject(); + at.knowcenter.wag.egov.egiz.sig.SignatureEntry internalEntry = s.getSigEntry(key); + if (internalEntry == null) + return null; + SignatureEntry ret = new SignatureEntry(key); + ret.setCaption(internalEntry.getCaption()); + ret.setValue(internalEntry.getValue()); + return ret; + } + + /** + * @see PdfAsInternal#getSignedText(SignatureInformation) + */ + public String getSignedText(SignatureInformation sigInfo) { + SignatureHolder holder = (SignatureHolder)sigInfo.getInternalSignatureInformation(); + if (holder instanceof TextualSignatureHolder) + return ((TextualSignatureHolder)holder).getSignedText(); + return null; + } + + /** + * @see PdfAsInternal#getConnectorsAvailableForWeb() + */ + public Map getConnectorsAvailableForWeb() throws ConnectorFactoryException { + ConnectorInformation ci[] = ConnectorFactory.getConnectorInformationArray(); + + Map ret = new HashMap(); + for (int i = 0; i < ci.length; i++) + { + String id = ci[i].getIdentifier(); + if (ConnectorFactory.isAvailableForWeb(id)) + { + ret.put(id, ci[i].getDescription()); + } + } + return ret; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java new file mode 100644 index 0000000..1cc5699 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/ActualSignaturePositionAdapter.java @@ -0,0 +1,93 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java new file mode 100644 index 0000000..163d1d2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignResultImpl.java @@ -0,0 +1,115 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api.sign; + +import java.security.cert.X509Certificate; +import java.util.List; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +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; + + /** + * List {@link NonTextObjectInfo} + */ + protected List nonTextObjects; + + /** + * 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, List nonTextObjects) + { + this.outputDocument = outputDocument; + this.signerCertificate = signerCertificate; + this.signaturePosition = signaturePosition; + this.nonTextObjects = nonTextObjects; + } + + /** + * @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; + } + + + /** + * List {@link NonTextObjectInfo} + */ + public List getNonTextualObjects() { + return this.nonTextObjects; + } + + public boolean hasNonTextualObjects() { + return this.nonTextObjects != null && this.nonTextObjects.size() > 0; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignatureDetailInformationImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignatureDetailInformationImpl.java new file mode 100644 index 0000000..18b88ed --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/sign/SignatureDetailInformationImpl.java @@ -0,0 +1,190 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.api.sign; + +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import at.gv.egiz.pdfas.api.io.DataSource; +import at.gv.egiz.pdfas.api.sign.SignatureDetailInformation; +import at.gv.egiz.pdfas.api.sign.pos.SignaturePosition; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.api.commons.DataSourceApiAdapter; +import at.gv.egiz.pdfas.impl.api.commons.TextBasedDataSourceApiAdapter; +import at.knowcenter.wag.egov.egiz.pdf.EGIZDate; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * + * @author exthex + * + */ +public class SignatureDetailInformationImpl implements SignatureDetailInformation { + + private DataSource signatureData; + private SignaturePosition signaturePosition; + private List nonTextualObjects; + private String dateString; + private Date signDate; + private String issuer; + private Map issuerDNMap; + private String name; + private String serialNumber; + private String sigAlgorithm; + private String sigID; + private String sigKZ; + private String signatureValue; + private String sigTimeStamp; + private Map subjectDNMap; + private X509Certificate x509Certificate; + private boolean textual; + private Properties responseProperties; + private SignatorInformation signatorInfo; + + public DataSource getSignatureData() { + return this.signatureData; + } + + public SignaturePosition getSignaturePosition() { + return this.signaturePosition; + } + + public List getNonTextualObjects() { + return this.nonTextualObjects; + } + + public Date getSignDate() { + return this.signDate; + } + + public String getIssuer() { + return this.issuer; + } + + public Map getIssuerDNMap() { + return this.issuerDNMap; + } + + public String getSubjectName() { + return this.name; + } + + public String getSerialNumber() { + return this.serialNumber; + } + + public String getSigAlgorithm() { + return this.sigAlgorithm; + } + + public String getSigID() { + return this.sigID; + } + + public String getSigKZ() { + return this.sigKZ; + } + + public String getSignatureValue() { + return this.signatureValue; + } + + public String getSigTimeStamp() { + return this.sigTimeStamp; + } + + public Map getSubjectDNMap() { + return this.subjectDNMap; + } + + public X509Certificate getX509Certificate() { + return this.x509Certificate; + } + + public boolean isTextual() { + return textual; + } + + public boolean isBinary() { + return !textual; + } + + public void setSignSignatureObject(SignSignatureObject sso) { + this.dateString = sso.getDate(); + if (this.dateString != null){ + this.signDate = EGIZDate.parseDateFromString(this.dateString); + } + this.issuer = sso.getIssuer(); + this.issuerDNMap = sso.getIssuerDNMap(); + this.name = sso.getName(); //extracted from x509Certificate + this.serialNumber = sso.getSerialNumber(); //extracted from x509Certificate + this.sigAlgorithm = sso.getSigAlgorithm(); + this.sigID = sso.getSigID(); + this.sigKZ = sso.getSigKZ(); + this.signatureValue = sso.getSignatureValue(); + this.sigTimeStamp = sso.getSigTimeStamp(); + this.subjectDNMap = sso.getSubjectDNMap(); + this.x509Certificate = sso.getX509Certificate(); + this.responseProperties = sso.response_properties; + if (this.signatorInfo != null){ + this.signatorInfo.setSignSignatureObject(sso); + } + } + + public SignSignatureObject getSignSignatureObject() { + SignSignatureObject ret = new SignSignatureObject(); + ret.date = this.dateString; + ret.id = this.sigID; + ret.issuer = this.issuer; + ret.issuerDNMap = this.issuerDNMap; + ret.kz = this.sigKZ; + ret.response_properties = this.responseProperties; + ret.sigAlgorithm = this.sigAlgorithm; + ret.signatureValue = this.signatureValue; + ret.sigTimeStamp = this.sigTimeStamp; + ret.subjectDNMap = this.subjectDNMap; + ret.x509Certificate = this.x509Certificate; + + return ret; + } + + public SignatorInformation getSignatorInfo() { + return this.signatorInfo; + } + + public void setSignatorInformation(SignatorInformation signatorInformation){ + this.signatorInfo = signatorInformation; + this.signaturePosition = new ActualSignaturePositionAdapter(signatorInformation.getActualTablePos()); + this.nonTextualObjects = signatorInformation.getNonTextualObjects(); + at.gv.egiz.pdfas.framework.input.DataSource dataSource = signatorInformation.getSignatureData().getDataSource(); + if (dataSource instanceof TextDataSource) + this.signatureData = new TextBasedDataSourceApiAdapter((TextDataSource)dataSource); + else + this.signatureData = new DataSourceApiAdapter(dataSource); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java new file mode 100644 index 0000000..84df2a5 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/SignatureCheckImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java new file mode 100644 index 0000000..09d247d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultAdapter.java @@ -0,0 +1,205 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.gv.egiz.pdfas.api.verify.SignatureCheck; +import at.gv.egiz.pdfas.api.verify.VerifyResult; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.impl.api.commons.SignatureInformationAdapter; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +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; + + /** + * The log. + */ + private static final Log logger_ = LogFactory.getLog(VerifyResultAdapter.class); + + protected Date vTime = null; + + private String timestamp; + + private XMLDsigData xmlDsigData; + + + /** + * Constructor. + * + * @param sigRes + * The SignatureResponse. + * @param sh + * The SignatureHolder. + * @param verificationTime + * The time of verification. This is directly returned by {@link #getVerificationTime()} + * @param xmlDsigData + */ + public VerifyResultAdapter(SignatureResponse sigRes, SignatureHolder sh, Date verificationTime, XMLDsigData xmlDsigData) + { + super(sh); + this.sigRes = sigRes; + this.vTime = verificationTime; + this.xmlDsigData = xmlDsigData; + if (sh instanceof BinarySignatureHolder) { + this.timestamp = ((BinarySignatureHolder)sh).getSignatureObject().getTimeStamp(); + } + // [tknall] start: missing time of verification fixed + if (this.vTime == null) { + // verification time not been set (= null) therefore signingtime equals verificationtime + this.vTime = super.getSigningTime(); + } + // [tknall] stop: missing time of verification fixed + } + + /** + * @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) + { + logger_.error(e.getMessage(), e); + 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(); + } + + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#getPublicAuthorityCode() + */ + public String getPublicAuthorityCode() { + return this.sigRes.getPublicAuthorityCode(); + } + + /** + * @see at.gv.egiz.pdfas.api.verify.VerifyResult#isPublicAuthority() + */ + public boolean isPublicAuthority() { + return this.sigRes.isPublicAuthority(); + } + + public PdfAsException getVerificationException() { + return this.sigRes.getVerificationImpossibleEx(); + } + + public boolean isVerificationDone() { + return this.sigRes.getVerificationImpossibleEx() == null; + } + + /** + * @see VerifyResult#getReconstructedXMLDsig() + */ + public XMLDsigData getReconstructedXMLDsig() { + return this.xmlDsigData; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java new file mode 100644 index 0000000..c5ce3ba --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/api/verify/VerifyResultsImpl.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java new file mode 100644 index 0000000..edcb1d4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/ByteArrayPdfDataSourceImpl.java @@ -0,0 +1,85 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import at.gv.egiz.pdfas.performance.PerformanceCounters; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +/** + * Implements a PdfDataSource that holds the whole PDF document in a byte array. + * + *

+ * Note that holding the data in a byte array is very memory consuming for large + * documents. + *

+ * + * @author wprinz + */ +public class ByteArrayPdfDataSourceImpl implements PdfDataSource +{ + protected byte[] pdf = null; + + public ByteArrayPdfDataSourceImpl(byte[] pdf) + { + PerformanceCounters.byteArrays.increment(); + + this.pdf = pdf; + } + + public ByteArrayPdfDataSourceImpl(byte[] pdf, int length) + { + PerformanceCounters.byteArrays.increment(); + + if (pdf.length == length) + { + this.pdf = pdf; + } + else + { + this.pdf = new byte [length]; + System.arraycopy(pdf, 0, this.pdf, 0, length); + } + } + + + public InputStream createInputStream() + { + ByteArrayInputStream bais = new ByteArrayInputStream(this.pdf); + return bais; + } + + public int getLength() + { + return this.pdf.length; + } + + public byte[] getAsByteArray() + { + return this.pdf; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java new file mode 100644 index 0000000..f5e9b76 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/CompoundPdfDataSourceImpl.java @@ -0,0 +1,85 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.SequenceInputStream; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +/** + * @author wprinz + * + */ +public class CompoundPdfDataSourceImpl implements PdfDataSource +{ + protected DataSource originalDataSource = null; + + protected byte[] appendix = null; + + public CompoundPdfDataSourceImpl (PdfDataSource original, byte [] appendix) + { + this.originalDataSource = original; + this.appendix = appendix; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + ByteArrayInputStream bais = new ByteArrayInputStream(this.appendix); + SequenceInputStream sis = new SequenceInputStream(this.originalDataSource.createInputStream(), bais); + return sis; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength() + */ + public int getLength() + { + return this.originalDataSource.getLength() + this.appendix.length; + } + + byte [] cache = null; + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + if (cache != null) + { + return cache; + } + + cache = new byte [getLength()]; + System.arraycopy(originalDataSource.getAsByteArray(), 0, cache, 0, originalDataSource.getLength()); + System.arraycopy(appendix, 0, cache, originalDataSource.getLength(), appendix.length); + + return cache; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java new file mode 100644 index 0000000..f10b546 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedInputStream.java @@ -0,0 +1,125 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.IOException; +import java.io.InputStream; + +/** + * An input stream that has a delimited length. + * + * @author wprinz + */ +public class DelimitedInputStream extends InputStream +{ + /** + * The underlying InputStream. + */ + protected InputStream is = null; + + /** + * The number of bytes that can be read from the stream. + */ + protected int bytes_to_read = -1; + + /** + * Constructs the DelimitedInputStream from which a maximum of length bytes + * can be read. + */ + public DelimitedInputStream(InputStream is, int length) + { + this.is = is; + this.bytes_to_read = length; + } + + /** + * @see java.io.InputStream#read() + */ + public int read() throws IOException + { + if (this.bytes_to_read <= 0) + { + return -1; + } + int read = this.is.read(); + if (read > 0) + { + this.bytes_to_read--; + } + return read; + } + + /** + * @see java.io.InputStream#read(byte[], int, int) + */ + public int read(byte[] b, int off, int len) throws IOException + { + int btr = Math.min(len, this.bytes_to_read); + int read = this.is.read(b, off, btr); + if (read > 0) + { + this.bytes_to_read -= read; + } + return read; + } + + /** + * @see java.io.InputStream#read(byte[]) + */ + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + /** + * @see java.io.InputStream#skip(long) + */ + public long skip(long n) throws IOException + { + long bts = Math.min(n, this.bytes_to_read); + long skipped = this.is.skip(bts); + if (skipped > 0) + { + this.bytes_to_read -= skipped; + } + return skipped; + } + + /** + * @see java.io.InputStream#close() + */ + public void close() throws IOException + { + this.is.close(); + } + + /** + * @see java.io.InputStream#available() + */ + public int available() throws IOException + { + int avail = this.is.available(); + return Math.min(this.bytes_to_read, avail); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java new file mode 100644 index 0000000..ca73f37 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/DelimitedPdfDataSource.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.InputStream; + +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +/** + * @author wprinz + * + */ +public class DelimitedPdfDataSource implements PdfDataSource +{ + + protected PdfDataSource dataSource = null; + protected int len = -1; + + public DelimitedPdfDataSource (PdfDataSource original, int length) + { + this.dataSource = original; + this.len = length; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + InputStream originalIS = this.dataSource.createInputStream(); + DelimitedInputStream dis = new DelimitedInputStream(originalIS, this.len); + return dis; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength() + */ + public int getLength() + { + return this.len; + } + + byte [] cache = null; + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + if (cache != null) + { + return cache; + } + + cache = new byte [getLength()]; + System.arraycopy(dataSource.getAsByteArray(), 0, cache, 0, getLength()); + + return cache; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java new file mode 100644 index 0000000..65ee416 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBased.java @@ -0,0 +1,40 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.File; + +/** + * Interface that reveals the underlying data file. + * + * @author wprinz + */ +public interface FileBased +{ + /** + * Returns the underlying data file. + * @return Returns the underlying data file. + */ + public File getFile(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java new file mode 100644 index 0000000..a710c3c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedPdfDataSourceImpl.java @@ -0,0 +1,150 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; + +/** + * @author wprinz + * + */ +public class FileBasedPdfDataSourceImpl implements PdfDataSource, FileBased +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(FileBasedPdfDataSourceImpl.class); + + /** + * The underlying file. + */ + protected File inputFile = null; + + protected int length = -1; + + /** + * Constructor that creates this PdfDataSource backed by a file in the file + * system. + * + * @param file + * The input File. + * @param length + * The length of the InputStream. The is the maximum number of bytes + * that can be read from the stream. + * @throws IOException + * Thrown if the file cannot be read properly. + */ + public FileBasedPdfDataSourceImpl(File file, int length) throws IOException + { + + if (!file.exists()) + { + throw new FileNotFoundException("The file '" + file + "' does not exist."); + } + // for some reason the isFile is not always correct... + // if (file.isFile()) + // { + // throw new IOException("The file '" + file + "' is not a normal file."); + // } + if (!file.canRead()) + { + throw new IOException("The file '" + file + "' cannot be read."); + } + + this.inputFile = file; + this.length = length; + } + + /** + * @see at.gv.egiz.pdfas.impl.input.FileBased#getFile() + */ + public File getFile() + { + return this.inputFile; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.PdfDataSource#createInputStream() + */ + public InputStream createInputStream() + { + if (cache == null) + { + getAsByteArray(); + } + return new ByteArrayInputStream(cache); + } + + protected InputStream createFileInputStream() + { + try + { + FileInputStream fis = new FileInputStream(getFile()); + DelimitedInputStream dis = new DelimitedInputStream(fis, getLength()); + return dis; + } + catch (IOException e) + { + log.error("Couldn't create InputStream for file " + getFile() + ". Returning null.", e); + + return null; + } + } + /** + * @see at.gv.egiz.pdfas.framework.input.PdfDataSource#getLength() + */ + public int getLength() + { + return this.length; + } + + byte [] cache = null; + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + if (cache != null) + { + return cache; + } + + cache = DataSourceHelper.convertInputStreamToByteArray(createFileInputStream()); + + return cache; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java new file mode 100644 index 0000000..5a84ce2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/FileBasedTextDataSourceImpl.java @@ -0,0 +1,160 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; + +/** + * @author wprinz + * + */ +public class FileBasedTextDataSourceImpl implements TextDataSource, FileBased +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(FileBasedTextDataSourceImpl.class); + + protected File file = null; + + protected String characterEncoding = null; + + public FileBasedTextDataSourceImpl(File file, String characterEncoding) throws IOException + { + 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.characterEncoding = characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.impl.input.FileBased#getFile() + */ + public File getFile() + { + return this.file; + } + + /** + * Returns the character encoding. + * + * @return Returns the character encoding. + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.TextDataSource#getText() + */ + public String getText() + { + try + { + InputStream is = createInputStream(); + byte[] data = new byte[getLength()]; + int read = 0; + int n = 0; + while ((n = is.read(data, read, data.length - read)) > 0) + { + read += n; + } + is.close(); + + String text = new String(data, getCharacterEncoding()); + + data = null; + + return text; + } + catch (IOException e) + { + log.error("Couldn't read text for file " + getFile() + ". Returning null.", e); + + return null; + } + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + try + { + FileInputStream fis = new FileInputStream(getFile()); + return fis; + } + catch (IOException e) + { + log.error("Couldn't create InputStream for file " + getFile() + ". Returning null.", e); + + return null; + } + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength() + */ + public int getLength() + { + return (int) getFile().length(); + } + + byte [] cache = null; + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + if (cache != null) + { + return cache; + } + + cache = DataSourceHelper.convertInputStreamToByteArray(createInputStream()); + + return cache; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java new file mode 100644 index 0000000..c1dcc03 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/IncrementalUpdateParser.java @@ -0,0 +1,92 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSourceHolder; +import at.gv.egiz.pdfas.framework.input.correction.Corrector; +import at.gv.egiz.pdfas.framework.input.correction.CorrectorFactory; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.exactparser.ParseDocument; + +/** + * Parses the given PDF document into a list of Incremental Update blocks. + * @author wprinz + */ +public class IncrementalUpdateParser +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(IncrementalUpdateParser.class); + + public static List parsePdfIntoIUBlocks (PdfDataSourceHolder pdfDataSource) throws PDFDocumentException + { + log.trace("parsePdfIntoIUBlocks:"); + + List blocks = null; + try + { + byte [] pdf = DataSourceHelper.convertDataSourceToByteArray(pdfDataSource.getDataSource()); + blocks = ParseDocument.parseDocument(pdf); + } + catch (Exception e) { + try { + log.debug("Error while parsing Document.", e); + boolean tryToCorrect = SettingsReader.getInstance().getSetting("correct_document_on_verify_if_necessary", "false").equals("true"); + if (tryToCorrect) { + log.info("Correcting document..."); + Corrector cor = CorrectorFactory.createCorrector(); + PdfDataSource correctedDS = cor.correctDocument(pdfDataSource.getDataSource()); + log.info("Correction finished."); + byte [] pdf = DataSourceHelper.convertDataSourceToByteArray(correctedDS); + blocks = ParseDocument.parseDocument(pdf); + pdfDataSource.setDataSource(correctedDS); + } else { + makeError(e); + } + + } catch (Exception e1) { + makeError(e); + } + } + + log.trace("parsePdfIntoIUBlocks finished."); + return blocks; + } + + private static void makeError(Exception e) throws PDFDocumentException { + log.error("Error while parsing Document into IU blocks.", e); + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java new file mode 100644 index 0000000..fa5ab04 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/TextDataSourceImpl.java @@ -0,0 +1,120 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.pdfas.framework.input.TextDataSource; + +/** + * A TextDataSource that keeps the text in memory. + * + *

+ * Keeping the text in memory is fast as long as the text is short, but may + * result in bad memory performance when the text is longer. Use a FileBased + * TextDataSource instead if memory is an issue. + *

+ * + * @author wprinz + */ +public class TextDataSourceImpl implements TextDataSource +{ + /** + * The text. + */ + protected String text = null; + + private final static String CHARSET = "UTF-8"; + + /** + * Constructor that sets the text. + * + * @param text + * The text. + */ + public TextDataSourceImpl(String text) + { + this.text = text; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.TextDataSource#getText() + */ + public String getText() + { + return this.text; + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#createInputStream() + */ + public InputStream createInputStream() + { + try + { + byte[] data = getText().getBytes(CHARSET); + // PERF: if memory is an issue (e.g. in web), use a FileBased TextDataSource instead. + return new ByteArrayInputStream(data); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException(e); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getLength() + */ + public int getLength() + { + try + { + byte[] data = getText().getBytes(CHARSET); + return data.length; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException(e); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.input.DataSource#getAsByteArray() + */ + public byte[] getAsByteArray() + { + try + { + byte[] data = getText().getBytes(CHARSET); + return data; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException(e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/ExternalCorrector.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/ExternalCorrector.java new file mode 100644 index 0000000..efd094a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/ExternalCorrector.java @@ -0,0 +1,283 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input.correction; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.CorrectorException; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.correction.Corrector; +import at.gv.egiz.pdfas.impl.input.FileBased; +import at.gv.egiz.pdfas.impl.input.FileBasedPdfDataSourceImpl; +import at.gv.egiz.pdfas.utils.TempDirHelper; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * Corrects the document using an extrenal commandline tool. + * + *

+ * Process.destroy after a certain timeout does not work if the executable is a + * Windows batch file. + *

+ * + * @author wprinz + */ +public class ExternalCorrector implements Corrector +{ + public static final String INPUT_DOCUMENT_REPLACE = "##input_document##"; + + public static final String OUTPUT_DOCUMENT_REPLACE = "##output_document##"; + + public static final String COMMANDLINE_KEY = "external_corrector_commandline"; + + public static final String TIMEOUT_KEY = "external_corrector_timeout"; + + protected static final int DEFAULT_TIMEOUT = 1000; + + /** + * The log. + */ + private static final Log log = LogFactory.getLog(ExternalCorrector.class); + + /** + * @see at.gv.egiz.pdfas.framework.input.correction.Corrector#correctDocument(at.gv.egiz.pdfas.framework.input.PdfDataSource) + */ + public PdfDataSource correctDocument(PdfDataSource document) throws CorrectorException + { + + try + { + String outName = null; + File in = null; + if (document instanceof FileBased) + { + FileBased fb = (FileBased) document; + in = fb.getFile(); + outName = in.getName() + "_correction_outfile.pdf"; + } + else + { + in = TempDirHelper.placeInputIntoTempDirFile(document.createInputStream(), "correction_infile.pdf"); + outName = "correction_outfile.pdf"; + } + + File out = TempDirHelper.formTempFile(outName); + + String commandline = SettingsReader.getInstance().getSetting(COMMANDLINE_KEY); + long timeout = SettingsReader.getInstance().getIntSetting(TIMEOUT_KEY, DEFAULT_TIMEOUT); + + String inF = in.getAbsolutePath(); + commandline = commandline.replaceFirst(INPUT_DOCUMENT_REPLACE, inF.replaceAll("\\\\", "\\\\\\\\")); + String outF = out.getAbsolutePath(); + commandline = commandline.replaceFirst(OUTPUT_DOCUMENT_REPLACE, outF.replaceAll("\\\\", "\\\\\\\\")); + + log.info(commandline); + + Process p = Runtime.getRuntime().exec(commandline); + + Thread outT = null; + Thread errT = null; + TimeoutThread tt = null; + BufferedReader outReader = null; + BufferedReader errReader = null; + + try + { + outReader = new BufferedReader(new InputStreamReader(p.getInputStream())); + errReader = new BufferedReader(new InputStreamReader(p.getErrorStream())); + + outT = new Thread(new ReaderPrinter(outReader, "STDOUT")); + errT = new Thread(new ReaderPrinter(errReader, "STDERR")); + + tt = new TimeoutThread(p, timeout, new Thread[] { outT, errT }); + + tt.start(); + outT.start(); + errT.start(); + + log.trace("Joining the STDOUT thread..."); + outT.join(); + log.trace("STDOUT thread joined."); + log.trace("Joining the STDERR thread..."); + errT.join(); + log.trace("STDERR thread joined."); + + log.trace("Waiting for process to end..."); + p.waitFor(); + log.trace("process has ended."); + + log.trace("Interrupting timeout thread..."); + tt.interrupt(); + log.trace("timeout thread has been interrupted."); + + int exitValue = p.exitValue(); + log.info("External Corrector exited with: " + exitValue); + + if (tt.isTimedOut()) + { + throw new CorrectorException(ErrorCode.EXTERNAL_CORRECTOR_TIMEOUT_REACHED, "The external corrector process timed out. timeout = " + timeout); + } + + PdfDataSource ds = new FileBasedPdfDataSourceImpl(out, (int) out.length()); + return ds; + } + finally + { + if (outT != null) + { + outT.interrupt(); + } + if (errT != null) + { + errT.interrupt(); + } + if (tt != null) + { + tt.interrupt(); + } + if (outReader != null) + { + outReader.close(); + } + if (errReader != null) + { + errReader.close(); + } + } + + } + catch (IOException e) + { + throw new CorrectorException(ErrorCode.CORRECTOR_EXCEPTION, e); + } + catch (InterruptedException e) + { + throw new CorrectorException(ErrorCode.CORRECTOR_EXCEPTION, e); + } + catch (SettingNotFoundException e) + { + throw new CorrectorException(ErrorCode.CORRECTOR_EXCEPTION, e); + } + catch (SettingsException e) + { + throw new CorrectorException(ErrorCode.CORRECTOR_EXCEPTION, e); + } + } + + protected static class ReaderPrinter implements Runnable + { + protected BufferedReader reader = null; + + protected String streamName = null; + + public ReaderPrinter(BufferedReader reader, String streamName) + { + this.reader = reader; + this.streamName = streamName; + } + + public void run() + { + try + { + String line = null; + + while ((line = this.reader.readLine()) != null) + { + if (line != null) + { + log.info(streamName + ": " + line); + } + } + } + catch (IOException e) + { + log.error(e.getMessage(), e); + } + } + } + + protected static class TimeoutThread extends Thread + { + protected Process proc = null; + + protected long timeout = -1; + + protected boolean ranIntoTimeout = false; + + protected Thread[] threads; + + protected BufferedReader errReader; + + public TimeoutThread(Process proc, long timeout, Thread[] threadsToInterrupt) + { + this.proc = proc; + this.timeout = timeout; + this.threads = threadsToInterrupt; + } + + public void run() + { + try + { + Thread.sleep(this.timeout); + log.info("The timeout was reached. Destroying the process."); + proc.destroy(); + ranIntoTimeout = true; + log.trace("destroy has been called."); + log.trace("Interrupting threads..."); + for (int i = 0; i < this.threads.length; i++) + { + this.threads[i].interrupt(); + } + log.trace("threads have been interrupted."); + } + catch (InterruptedException e) + { + log.debug("Timeout thread interrupted. This means that the process finished successfully."); + } + } + + /** + * Tells, if the process ran into the timeout. + * + * @return Returns true if the timeout was reached. Returns false if the + * timeout was not reached. + */ + public boolean isTimedOut() + { + return this.ranIntoTimeout; + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/InternalCorrector.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/InternalCorrector.java new file mode 100644 index 0000000..eaa6b7f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/correction/InternalCorrector.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input.correction; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.CorrectorException; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.correction.Corrector; +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.utils.PDFASUtils; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +import com.lowagie.text.DocumentException; +import com.lowagie.text.pdf.PdfReader; +import com.lowagie.text.pdf.PdfStamper; + +/** + * Corrects a document using iText. + * + * @author wprinz + */ +public class InternalCorrector implements Corrector +{ + + /** + * @see at.gv.egiz.pdfas.framework.input.correction.Corrector#correctDocument(at.gv.egiz.pdfas.framework.input.PdfDataSource) + */ + public PdfDataSource correctDocument(PdfDataSource document) throws CorrectorException + { + try + { + byte[] pdf = document.getAsByteArray(); + PdfReader reader = new PdfReader(pdf); + PDFASUtils.checkReaderPermissions(reader); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(pdf.length); + + PdfStamper stamper = new PdfStamper(reader, baos, '\0', false); + stamper.close(); + + baos.close(); + byte[] corrected_pdf = baos.toByteArray(); + + return new ByteArrayPdfDataSourceImpl(corrected_pdf); + } + catch (DocumentException e) + { + throw new CorrectorException(ErrorCode.CORRECTOR_EXCEPTION, e); + } + catch (IOException e) + { + throw new CorrectorException(ErrorCode.CORRECTOR_EXCEPTION, e); + } catch (PDFDocumentException e) { + throw new CorrectorException(e.getErrorCode(), e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java new file mode 100644 index 0000000..76a5f99 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/input/helper/DataSourceHelper.java @@ -0,0 +1,148 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.input.helper; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import at.gv.egiz.pdfas.performance.PerformanceCounters; +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author wprinz + * + */ +public class DataSourceHelper +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(DataSourceHelper.class); + + /** + * Converts a PdfDataSource to a byte array. + * + *

+ * Note that this function is very memory intensive. Use the Streams whereever + * possible. + *

+ * + * @deprecated + * + * @param pdfDataSource + * @return + * @throws IOException + */ + public static byte[] convertDataSourceToByteArray(DataSource pdfDataSource) + { + return pdfDataSource.getAsByteArray(); +// try +// { +// PerformanceCounters.byteArrays.increment(); +// +// byte[] data = new byte[pdfDataSource.getLength()]; +// +// int bytes_written = 0; +// +// InputStream is = pdfDataSource.createInputStream(); +// int n = 0; +// while ((n = is.read(data, bytes_written, data.length - bytes_written)) > 0) +// { +// bytes_written += n; +// } +// is.close(); +// +// assert bytes_written == data.length; +// +// return data; +// } +// catch (IOException e) +// { +// log.error(e); +// throw new RuntimeException(e); +// } + } + + public static byte [] convertInputStreamToByteArray(InputStream inputStream) + { + 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); + + byte[] temp = new byte[4096]; + + int n = 0; + while ((n = inputStream.read(temp)) > 0) + { + baos.write(temp, 0, n); + } + inputStream.close(); + + baos.close(); + byte [] data = baos.toByteArray(); + + return data; + } + + public static void debugDataSourceToFile(DataSource dataSource, File file) + { + try + { + InputStream is = dataSource.createInputStream(); + FileOutputStream fos = new FileOutputStream(file); + byte[] data = new byte[2048]; + int n = -1; + while ((n = is.read(data)) > 0) + { + fos.write(data, 0, n); + } + is.close(); + fos.close(); + } + catch (IOException e) + { + log.error(e); + } + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java new file mode 100644 index 0000000..d1de405 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/ByteArrayDataSink.java @@ -0,0 +1,106 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.output; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.performance.PerformanceCounters; + +/** + * @author wprinz + * + */ +public class ByteArrayDataSink implements DataSink +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(ByteArrayDataSink.class); + + protected String mimeType = null; + protected String characterEncoding = null; + + protected ByteArrayOutputStream baos = null; + + + public ByteArrayDataSink() + { + PerformanceCounters.byteArrays.increment(); + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String) + */ + public OutputStream createOutputStream(String mimeType) + { + return createOutputStream(mimeType, null); + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String, java.lang.String) + */ + public OutputStream createOutputStream(String mimeType, String characterEncoding) + { + this.mimeType = mimeType; + this.characterEncoding = characterEncoding; + + if (this.baos != null) + { + log.warn("An output stream is created twice. The old one will be rendered useless."); + } + this.baos = new ByteArrayOutputStream(4096); + return this.baos; + } + + /** + * Returns the byte array. + * @return Returns the byte array. + */ + public byte [] getByteArray () + { + return this.baos.toByteArray(); + } + + /** + * @return the mimeType + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @return the characterEncoding + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java new file mode 100644 index 0000000..0880af0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/output/FileBasedDataSink.java @@ -0,0 +1,145 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.output; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.impl.input.FileBased; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author wprinz + * + */ +public class FileBasedDataSink implements DataSink, FileBased +{ + /** + * The log. + */ + private static final Log log = LogFactory.getLog(FileBasedDataSink.class); + + protected String mimeType = null; + protected String characterEncoding = null; + + /** + * The output file. + */ + protected File outputFile = null; + + /** + * Creates a file based PdfDataSink. + * + * @param file + * The file. + * @throws IOException + * F.e. + */ + 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.outputFile = file; + } + + /** + * @see at.gv.egiz.pdfas.impl.input.FileBased#getFile() + */ + public File getFile() + { + return this.outputFile; + } + + + + protected OutputStream createOutputStream() + { + try + { + FileOutputStream fos = new FileOutputStream(getFile()); + return fos; + } + catch (IOException e) + { + log.error("Couldn't create OutputStream for file " + getFile() + ". Returning null.", e); + + return null; + + } + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String) + */ + public OutputStream createOutputStream(String mimeType) + { + return createOutputStream(mimeType, null); + } + + /** + * @see at.gv.egiz.pdfas.framework.output.DataSink#createOutputStream(java.lang.String, java.lang.String) + */ + public OutputStream createOutputStream(String mimeType, String characterEncoding) + { + this.mimeType = mimeType; + this.characterEncoding = characterEncoding; + + return createOutputStream(); + } + + /** + * @return the mimeType + */ + public String getMimeType() + { + return mimeType; + } + + /** + * @return the characterEncoding + */ + public String getCharacterEncoding() + { + return characterEncoding; + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java new file mode 100644 index 0000000..53ee2db --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/IncrementalUpdateHelper.java @@ -0,0 +1,74 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.signator; + +import java.util.List; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.output.ByteArrayDataSink; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +import com.lowagie.text.pdf.PdfPTable; + +/** + * @author wprinz + */ +public final class IncrementalUpdateHelper +{ + public static IncrementalUpdateInformation writeIncrementalUpdate(PdfDataSource pdfDataSource, PdfPTable pdf_table, String profile, PositioningInstruction pi, List variable_field_definitions, + List all_field_definitions, TimeStamper timeStamper, SignatorInformation si, SignatureObject so) throws PresentableException + { + return writeIncrementalUpdate(pdfDataSource, pdf_table, profile, pi, variable_field_definitions, all_field_definitions, null, null, timeStamper, si, so); + } + + public static IncrementalUpdateInformation writeIncrementalUpdate(PdfDataSource pdfDataSource, PdfPTable pdf_table, String profile, PositioningInstruction pi, List variable_field_definitions, + List all_field_definitions, List invisible_field_definitions, String invisibleKZString, TimeStamper timeStamper, SignatorInformation si, SignatureObject so) throws PresentableException + { + // PERF: binary sig needs the signed_pdf as byte array + ByteArrayDataSink bads = new ByteArrayDataSink(); + IncrementalUpdateInformation iui = BinarySignature.writeIncrementalUpdate(pdfDataSource, bads, pdf_table, profile, pi, variable_field_definitions, all_field_definitions, invisible_field_definitions, invisibleKZString, timeStamper, si, so); + iui.signed_pdf = bads.getByteArray(); + bads = null; + + return iui; + } + + public static IncrementalUpdateInformation writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, String profile, PositioningInstruction pi, TimeStamper timeStamper, SignatorInformation si, SignatureObject so) throws PresentableException + { + return writeIncrementalUpdateToDataSink(pdfDataSource, dataSink, pdf_table, profile, pi, null, null, null, null, timeStamper, si, so); + } + + public static IncrementalUpdateInformation writeIncrementalUpdateToDataSink(PdfDataSource pdfDataSource, DataSink dataSink, PdfPTable pdf_table, String profile, PositioningInstruction pi, List variable_field_definitions, + List all_field_definitions, List invisible_field_definitions, String invisibleKZString, TimeStamper timeStamper, SignatorInformation si, SignatureObject so) throws PresentableException + { + return BinarySignature.writeIncrementalUpdate(pdfDataSource, dataSink, pdf_table, profile, pi, variable_field_definitions, all_field_definitions, invisible_field_definitions, invisibleKZString, timeStamper, si, so); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java new file mode 100644 index 0000000..0bc3039 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/SignatorInformationImpl.java @@ -0,0 +1,40 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.signator; + +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; + +/** + * @author wprinz + */ +public abstract class SignatorInformationImpl implements SignatorInformation +{ + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData() + */ + public abstract SignatureData getSignatureData(); + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java new file mode 100644 index 0000000..746d8e8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignatorInformation.java @@ -0,0 +1,104 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; + +/** + * @author wprinz + * + */ +public class BinarySignatorInformation implements SignatorInformation +{ + protected PdfDataSource originalDocument = null; + + protected byte [] incrementalUpdateBlock = null; + + protected SignatureData signatureData = null; + + protected List replaces = null; + + protected int cert_start = -1; + protected int cert_length = -1; + + protected int timestamp_start = -1; + protected int timestamp_length = -1; + + protected int enc_start = -1; + protected int enc_length = -1; + + protected SignSignatureObject signSignatureObject = null; + + protected ActualTablePos atp = null; + + protected String signProfile = null; + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData() + */ + public SignatureData getSignatureData() + { + return this.signatureData; + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#setSignSignatureObject(at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public void setSignSignatureObject(SignSignatureObject signSignatureObject) + { + 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; + } + + public List getNonTextualObjects() { + // not available for binary signature + return null; + } + + public void setNonTextualObjects(List nonTextObjects) { + // not available for binary signature + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java new file mode 100644 index 0000000..7f18f0a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_0_0.java @@ -0,0 +1,598 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinarySignator_1_0_0.java,v 1.1 2006/08/25 17:07:35 wprinz Exp $ + */ +package at.gv.egiz.pdfas.impl.signator.binary; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.SignatorException; +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.signator.Signator; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.signator.IncrementalUpdateHelper; +import at.gv.egiz.pdfas.utils.OgnlUtil; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +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.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; +import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureFieldDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +import com.lowagie.text.pdf.PdfPTable; + +/** + * Signs the document binary. + * + *

+ * In prepareSign, an Incremental Update is created that contains the Signature + * block and the egiz dictionary. For formatting the layout, variable values are + * filled with placeholders. After the layout has been fixed, all variable + * fields (all holes in the byte ranges) are replaced with 0. This document is + * then base64 encoded and signed. + *

+ *

+ * In finishSign, the variable fields (values, /Cert) are replaced with the + * values according to the encoding. + *

+ * + * @author wprinz + */ +public class BinarySignator_1_0_0 implements Signator { + // 04.11.2010 changed by exthex - fillReplacesWithValue no longer removes + // multiple newlines from values + + private static Log log = LogFactory.getLog(BinarySignator_1_0_0.class); + + /** + * Settings key for baik enables signatures + */ + public static final String SIG_BAIK_ENABLED = "SIG_BAIK_ENABLED"; + + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, + SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0); + + private Normalizer normalizer; + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() { + return MY_ID; + } + + /** + * Default constructor. + */ + public BinarySignator_1_0_0() { + try { + this.normalizer = new Normalizer(); + } catch (NormalizeException e) { + String msg = "Normalizer can not be initialized"; + throw new RuntimeException(msg, new SignatureException(400, msg, e)); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.Signator#prepareSign(PdfDataSource, + * String, TablePos, TimeStamper) + */ + public SignatorInformation prepareSign(PdfDataSource pdfDataSource, + String profile, TablePos pos, TimeStamper timeStamper) + throws SignatorException { + try { + // dferbas: has to be true everytime + boolean has_SIG_ID = true; + + String baikStr = SettingsReader.getInstance().getSetting( + "sig_obj." + profile + ".key." + SIG_BAIK_ENABLED, + "default." + SIG_BAIK_ENABLED, "false"); + boolean baikEnabled = "true".equalsIgnoreCase(baikStr); + + if (baikEnabled) { + log.debug("BAIK enabled signature"); + } + + SignatureObject signature_object = PdfAS + .createSignatureObjectFromType(profile); + signature_object.fillValues( + (char) BinarySignature.LAYOUT_PLACEHOLDER, has_SIG_ID, + baikEnabled); + + signature_object.setKZ(getMyId()); + + PdfPTable pdf_table = PdfAS + .createPdfPTableFromSignatureObject(signature_object); + + PositioningInstruction pi = PdfAS.determineTablePositioning(pos, + profile, pdfDataSource, pdf_table); + + List all_field_definitions = signature_object + .getSignatureTypeDefinition().getFieldDefinitions(); + List variable_field_definitions = new ArrayList(); + for (int i = 0; i < all_field_definitions.size(); i++) { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) all_field_definitions + .get(i); + if (sfd.placeholder_length > 0) { + if (sfd.field_name.equals(SignatureTypes.SIG_ID) + && has_SIG_ID == false) { + continue; + } + + if (sfd.field_name.equals(SignatureTypes.SIG_ALG) + && baikEnabled == false) { + continue; + } + + variable_field_definitions.add(sfd); + } + } + + List all_invisible_field_definitions = signature_object + .getSignatureTypeDefinition() + .getInvisibleFieldDefinitions(); + List invisible_field_definitions = new ArrayList(); + boolean isKZInvisible = false; + String invKZString = null; + + for (int i = 0; i < all_invisible_field_definitions.size(); i++) { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) all_invisible_field_definitions + .get(i); + if (sfd.field_name.equals(SignatureTypes.SIG_KZ)) { + isKZInvisible = true; + invKZString = signature_object.getKZ().toString(); + continue; + } + if (sfd.field_name.equals(SignatureTypes.SIG_ID) + && has_SIG_ID == false) { + continue; + } + + if (sfd.field_name.equals(SignatureTypes.SIG_ALG) + && baikEnabled == false) { + continue; + } + invisible_field_definitions.add(sfd); + } + + // check if signature block is invisible, and if so and if also + // signature block is positioned + // on a new page, prevent pdf-as to do that, because why should make + // a new page just for an invisible block + // added by rpiazzi + if (signature_object.getSignatureTypeDefinition() + .getInvisibleFieldDefinitions().size() == SignatureTypes.REQUIRED_SIG_KEYS.length) { + if (pi.isMakeNewPage()) { + int pageNumber = pi.getPage(); + pi = new PositioningInstruction(false, pageNumber - 1, 0, 0); + } + } + // end added + + IncrementalUpdateInformation iui = IncrementalUpdateHelper + .writeIncrementalUpdate(pdfDataSource, pdf_table, profile, + pi, variable_field_definitions, + all_field_definitions, invisible_field_definitions, + invKZString, timeStamper, null, signature_object); + + iui.invisible_field_definitions = invisible_field_definitions; + + iui.invisibleKZString = invKZString; + + String temp_string = iui.temp_ir_number + + " " + iui.temp_ir_generation + " obj"; //$NON-NLS-1$//$NON-NLS-2$ + byte[] temp_bytes = ArrayUtils.add( + temp_string.getBytes("US-ASCII"), 0, (byte) 0x0A); + int temp_start = ByteArrayUtils.lastIndexOf(iui.signed_pdf, + temp_bytes); + byte[] stream_bytes = new byte[] { '>', '>', 's', 't', 'r', 'e', + 'a', 'm', 0x0A }; + int stream_start = ByteArrayUtils.indexOf(iui.signed_pdf, + temp_start, stream_bytes); + iui.content_stream_start = stream_start + stream_bytes.length; + + // update the stream indices + Iterator it = iui.replaces.iterator(); + while (it.hasNext()) { + ReplaceInfo ri = (ReplaceInfo) it.next(); + + Iterator sit = ri.replaces.iterator(); + while (sit.hasNext()) { + StringInfo si = (StringInfo) sit.next(); + si.string_start += iui.content_stream_start; + } + } + // update KZ list indices: + if (!isKZInvisible) { + it = iui.kz_list.iterator(); + while (it.hasNext()) { + StringInfo si = (StringInfo) it.next(); + si.string_start += iui.content_stream_start; + } + } + + BinarySignature.markByteRanges(iui); + + // byte [] old_signed_pdf = iui.signed_pdf; + iui.signed_pdf = BinarySignature.prepareDataToSign(iui.signed_pdf, + iui.byte_ranges); + + BinarySignatorInformation bsi = compressIUI(iui); + return bsi; + + } catch (UnsupportedEncodingException e) { + throw new SignatorException(201, e); + } catch (PDFDocumentException e) { + throw new SignatorException(e.getErrorCode(), e); + } catch (PresentableException e) { + throw new SignatorException(201, e); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.Signator#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation, + * at.gv.egiz.pdfas.framework.output.DataSink) + */ + public void finishSign(SignatorInformation signatorInformation, + DataSink dataSink) throws SignatorException { + try { + IncrementalUpdateInformation iui = uncompressIUI((BinarySignatorInformation) signatorInformation); + + // PERF: need to keep the whole pdf in mem for processing + + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.BINARY_ID); + fillReplacesWithValues(iui); + + // This is needed so that certificates are stored + try { + iui.signed_signature_object.kz = getMyId().toString(); + SignatureObjectHelper + .convertSignSignatureObjectToSignatureObject( + iui.signed_signature_object, iui.signProfile); + } catch (PresentableException e) { + throw new SignatorException(e); + } + + BinarySignature.replaceCertificate(iui); + BinarySignature.replaceTimestamp(iui); + BinarySignature.replacePlaceholders(iui); + // dferbas: alternative sign attrib creation + // PdfReader reader = new PdfReader(iui.signed_pdf); + // + // OutputStream os = + // dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE); + // + // try { + // PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', + // null, true); + // + // BinarySignature.createAdobeSigAttrib(stamper, + // signatorInformation, signatorInformation.getActualTablePos()); + // + // } catch (DocumentException e) { + // log.error("pdf error", e); + // throw new SignatorException(ErrorCode.CANNOT_WRITE_PDF, e); + // } + + OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE); + os.write(iui.signed_pdf); + os.close(); + } catch (PDFDocumentException e) { + throw new SignatorException(e.getErrorCode(), e); + } catch (IOException e) { + throw new SignatorException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + } + + /** + * Reads the signature values from the signed signature object and fills the + * corresponding value in the Replaces array. + * + * @param iui + * The IncrementalUpdateInformation. + */ + protected void fillReplacesWithValues(final IncrementalUpdateInformation iui) { + try { + Iterator it = iui.replaces.iterator(); + HashMap ognlCtx = new HashMap(); + ognlCtx.put("iui", iui); + ognlCtx.put("sso", iui.signed_signature_object); + ognlCtx.put("issuer", iui.signed_signature_object.getIssuerDNMap()); + ognlCtx.put("subject", + iui.signed_signature_object.getSubjectDNMap()); + OgnlUtil ognl = new OgnlUtil(ognlCtx); + + OverridePropertyHolder.setOgnlUtil(ognl); + while (it.hasNext()) { + ReplaceInfo ri = (ReplaceInfo) it.next(); + String overrideVal = OverridePropertyHolder + .getProperty(ri.sfd.field_name); + if (overrideVal != null) { + ri.sfd.value = overrideVal; + ri.value = overrideVal; + } else if (ognl.containsExpression(ri.sfd.value)) { // dferbas + // evaluate expression + String res = ognl.compileMessage(ri.sfd.value); + ri.value = this.normalizer.normalize(res, true); + // Workaround added by rpiazzi + // a-trust wrongly encodes since July 2011, therefore some + // special characters (e.g. Umlaute) have + // to replaced by their right character + /*if ((ri.value.contains("ü") + || ri.value.contains("ä") + || ri.value.contains("ö") + || ri.value.contains("á") + || ri.value.contains("ß") + || ri.value.contains("Ö") + || ri.value.contains("à") + || ri.value.contains("é") + || ri.value.contains("ú") || ri.value + .contains("ç")) + && (ri.sfd.field_name + .equals(SignatureTypes.SIG_SUBJECT))) { + if (ri.value.contains("ü")) { + ri.sfd.value = ri.sfd.value.replace("ü", "�"); + ri.value = ri.value.replace("ü", "�"); + } + if (ri.value.contains("ä")) { + ri.sfd.value = ri.sfd.value.replace("ä", "�"); + ri.value = ri.value.replace("ä", "�"); + } + if (ri.value.contains("ö")) { + ri.sfd.value = ri.sfd.value.replace("ö", "�"); + ri.value = ri.value.replace("ö", "�"); + } + if (ri.value.contains("á")) { + ri.sfd.value = ri.sfd.value.replace("á", "�"); + ri.value = ri.value.replace("á", "�"); + } + if (ri.value.contains("ß")) { + ri.sfd.value = ri.sfd.value.replace("ß", "�"); + ri.value = ri.value.replace("ß", "�"); + } + if (ri.value.contains("Ö")) { + ri.sfd.value = ri.sfd.value.replace("Ö", "�"); + ri.value = ri.value.replace("Ö", "�"); + } + if (ri.value.contains("à")) { + ri.sfd.value = ri.sfd.value.replace("à", "�"); + ri.value = ri.value.replace("à", "�"); + } + if (ri.value.contains("é")) { + ri.sfd.value = ri.sfd.value.replace("é", "�"); + ri.value = ri.value.replace("é", "�"); + } + if (ri.value.contains("ú")) { + ri.sfd.value = ri.sfd.value.replace("ú", "�"); + ri.value = ri.value.replace("ú", "�"); + } + if (ri.value.contains("ç")) { + ri.sfd.value = ri.sfd.value.replace("ç", "�"); + ri.value = ri.value.replace("ç", "�"); + } + }*/ + FixHandyAnsiEncoding(ri); + // end added + } else if (overrideVal == null) { + // If SUBJECT is not overridden and and also isn't an + // expression + // check whether a set value for subject exists. + // In this case take the value from the config file. + // Added by rpiazzi to make a static signator possible + // without having + // to override it any time + if (ri.sfd.field_name.equals(SignatureTypes.SIG_SUBJECT)) { + if (ri.sfd.value.length() != 0) { + ri.value = ri.sfd.value; + } else { + ri.value = iui.signed_signature_object + .retrieveStringValue(ri.sfd.field_name); + } + } else { + ri.value = iui.signed_signature_object + .retrieveStringValue(ri.sfd.field_name); + } + } + } + } finally { + OverridePropertyHolder.removeOgnlUtil(); + } + } + + private void FixHandyAnsiEncoding(ReplaceInfo ri) { + Pattern p = Pattern.compile("&#([0-9]+);"); + Matcher m = p.matcher(ri.value); + + int value = -1; + + while (m.find()) { + value = Integer.parseInt(m.group(1)); + + if (value > 0 && value < 256) { + + log.debug("Replacing Encoding &#" + m.group(1) + ";"); + + byte[] buffer = new byte[1]; + + buffer[0] = (byte) value; + + ByteBuffer bb = ByteBuffer.wrap(buffer); + + CharBuffer cb = Charset.forName("CP1252").decode(bb); + + String str = cb.toString(); + + ri.value = ri.value.replace("&#" + m.group(1) + ";", str); + } + } + } + + /** + * Forms the SignatureData to be used for signing. + * + * @param iui + * The IncrementalUpdateInformation. + * @return Returns the SignatureData to be used for signing. + */ + protected SignatureData formSignatureData(IncrementalUpdateInformation iui) { + // String document_text = + // BinarySignature.retrieveSignableTextFromData(iui.signed_pdf, + // iui.signed_pdf.length); // signed_pdf.length); + // + // byte[] data; + // try + // { + // data = document_text.getBytes("UTF-8"); //$NON-NLS-1$ + // } + // catch (UnsupportedEncodingException e) + // { + // throw new RuntimeException("Very strange: UTF-8 character encoding + // not + // supported.", e); //$NON-NLS-1$ + // } + DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, + iui.sign_iui_block); + SignatureData signature_data = new SignatureDataImpl(ds, + PdfAS.PDF_MIME_TYPE); + + return signature_data; + } + + protected BinarySignatorInformation compressIUI( + IncrementalUpdateInformation iui) { + iui.sign_iui_block = new byte[iui.signed_pdf.length + - iui.original_document.getLength()]; + System.arraycopy(iui.signed_pdf, iui.original_document.getLength(), + iui.sign_iui_block, 0, iui.sign_iui_block.length); + + iui.signature_data = formSignatureData(iui); + + // remove the signed pdf from memory + iui.signed_pdf = null; + + BinarySignatorInformation bsi = new BinarySignatorInformation(); + bsi.originalDocument = iui.original_document; + bsi.incrementalUpdateBlock = iui.sign_iui_block; + bsi.signatureData = iui.signature_data; + bsi.replaces = iui.replaces; + bsi.cert_start = iui.cert_start; + bsi.cert_length = iui.cert_length; + bsi.enc_start = iui.enc_start; + bsi.enc_length = iui.enc_length; + bsi.atp = iui.actualTablePos; + bsi.signProfile = iui.signProfile; + bsi.timestamp_length = iui.timestamp_length; + bsi.timestamp_start = iui.timestamp_start; + + return bsi; + } + + protected IncrementalUpdateInformation uncompressIUI( + BinarySignatorInformation bsi) { + IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + + iui.original_document = bsi.originalDocument; + iui.sign_iui_block = bsi.incrementalUpdateBlock; + iui.signature_data = bsi.signatureData; + iui.replaces = bsi.replaces; + iui.cert_start = bsi.cert_start; + iui.cert_length = bsi.cert_length; + iui.enc_start = bsi.enc_start; + iui.enc_length = bsi.enc_length; + iui.actualTablePos = bsi.atp; + iui.signProfile = bsi.signProfile; + iui.timestamp_length = bsi.timestamp_length; + iui.timestamp_start = bsi.timestamp_start; + + iui.signed_signature_object = bsi.signSignatureObject; + + restoreSignedPdf(iui); + + return iui; + } + + protected void restoreSignedPdf(IncrementalUpdateInformation iui) { + iui.signed_pdf = new byte[iui.original_document.getLength() + + iui.sign_iui_block.length]; + + try { + InputStream is = iui.original_document.createInputStream(); + is.read(iui.signed_pdf, 0, iui.original_document.getLength()); + is.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + System.arraycopy(iui.sign_iui_block, 0, iui.signed_pdf, + iui.original_document.getLength(), iui.sign_iui_block.length); + } + + public String getEncoding() { + // not used for binary signature + return "utf-8"; + + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java new file mode 100644 index 0000000..acbc15e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/binary/BinarySignator_1_1_0.java @@ -0,0 +1,77 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinarySignator_1_0_0.java,v 1.1 2006/08/25 17:07:35 wprinz Exp $ + */ +package at.gv.egiz.pdfas.impl.signator.binary; + +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl; +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; + +/** + * Signs the document binary. + * + *

+ * This just differs from version 1.0.0 in the fact that the signature data is + * the actual binary PDF instead of a Base64 encoding. + *

+ * + * @see BinarySignator_1_0_0 + * + * @author wprinz + */ +public class BinarySignator_1_1_0 extends BinarySignator_1_0_0 +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_1_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * Overrides the SignatureData generation of the BinarySignator 1.0.0 so that + * the SignatureData is the actual binary PDF instead of a Base64 encoding. + * + * @see BinarySignator_1_0_0#formSignatureData(IncrementalUpdateInformation) + */ + protected SignatureData formSignatureData(IncrementalUpdateInformation iui) + { + DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, iui.sign_iui_block); + SignatureData signature_data = new SignatureDataImpl(ds, PdfAS.PDF_MIME_TYPE); + + return signature_data; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java new file mode 100644 index 0000000..7fcdb2a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/detached/DetachedTextualSignator_1_0_0.java @@ -0,0 +1,150 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $ + */ +package at.gv.egiz.pdfas.impl.signator.detached; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.SignatorException; +import at.gv.egiz.pdfas.framework.SignatorFactory; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignatorInformation; +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; + +/** + * Signs a document textually. + * + *

+ * In prepareSign, the document text is extracted and normalized. + *

+ *

+ * In finishSign, the signed SignatureObject is transformed into a Signature + * block, which is then written as an Incremental Update. + *

+ * + * @author wprinz + */ +public class DetachedTextualSignator_1_0_0 extends TextualSignator_1_0_0 +{ + /** + * The Mime Type. + */ + public static final String MIME_TYPE = "text/xml"; //$NON-NLS-1$ + + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_DETACHED_TEXTUAL, SignatorFactory.VERSION_1_0_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + // /** + // *

+ // * The parameter has_SIG_ID is not used by this Signator because it doesn't + // * pre-format the signature block. + // *

+ // * + // * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + // * String, TablePos, boolean) + // */ + // public IncrementalUpdateInformation prepareSign(PdfDataSource pdf, + // String signature_type, TablePos pos, boolean has_SIG_ID) throws + // PresentableException + // { + // IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + // iui.original_document = pdf; + // iui.signature_type = signature_type; + // iui.pos = pos; + // + // String document_text = + // PdfAS.extractNormalizedTextTextual(pdf.createInputStream()); + // // logger_.debug("signed_text = " + document_text); + // + // DataSource ds = new TextDataSourceImpl(document_text); + // iui.signature_data = new SignatureDataImpl(ds, MIME_TYPE, "UTF-8"); + // //$NON-NLS-1$ //$NON-NLS-2$ + // + // return iui; + // } + // + // /** + // * @see + // at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + // */ + // public SignResult finishSign(IncrementalUpdateInformation iui) throws + // PresentableException + // { + // try + // { + // String response = + // iui.signed_signature_object.response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + // byte[] response_bytes = response.getBytes("UTF-8"); //$NON-NLS-1$ + // + // SignResult sign_result = new SignResult(MIME_TYPE, response_bytes); + // return sign_result; + // } + // catch (UnsupportedEncodingException e) + // { + // e.printStackTrace(); + // throw new PDFDocumentException(300, e); + // } + // } + + /** + * @see at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_0_0#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation, + * at.gv.egiz.pdfas.framework.output.DataSink) + */ + public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException + { + try + { + TextualSignatorInformation tsi = (TextualSignatorInformation) signatorInformation; + + String response = tsi.signSignatureObject.response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + OutputStream os = dataSink.createOutputStream(MIME_TYPE, "UTF-8"); + OutputStreamWriter osw = new OutputStreamWriter(os); + osw.write(response); + osw.close(); + } + catch (IOException e) + { + throw new SignatorException(ErrorCode.SIGNATURE_COULDNT_BE_CREATED, e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java new file mode 100644 index 0000000..7a4835c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignatorInformation.java @@ -0,0 +1,96 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.signator.textual; + +import java.util.ArrayList; +import java.util.List; + +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; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; + +/** + * @author wprinz + * + */ +public class TextualSignatorInformation implements SignatorInformation +{ + protected PdfDataSource originalDocument = null; + + protected SignatureData signatureData = null; + + protected String profile = null; + + protected TablePos pos = null; + + public SignSignatureObject signSignatureObject = null; + + protected ActualTablePos atp = null; + + protected List nonTextualObjects = new ArrayList(); + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#getSignatureData() + */ + public SignatureData getSignatureData() + { + return this.signatureData; + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.SignatorInformation#setSignSignatureObject(at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public void setSignSignatureObject(SignSignatureObject signSignatureObject) + { + 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; + } + + public List getNonTextualObjects() { + return this.nonTextualObjects; + } + + public void setNonTextualObjects(List nonTextObjects) { + this.nonTextualObjects = nonTextObjects; + + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java new file mode 100644 index 0000000..d0793d6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_0_0.java @@ -0,0 +1,212 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $ + */ +package at.gv.egiz.pdfas.impl.signator.textual; + +import java.util.HashMap; +import java.util.Iterator; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.SignatorException; +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.signator.Signator; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.gv.egiz.pdfas.impl.signator.IncrementalUpdateHelper; +import at.gv.egiz.pdfas.utils.OgnlUtil; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +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.ObjectExtractor; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureEntry; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper; + +import com.lowagie.text.pdf.PdfPTable; + +/** + * Signs a document textually. + * + *

+ * In prepareSign, the document text is extracted and normalized. + *

+ *

+ * In finishSign, the signed SignatureObject is transformed into a Signature + * block, which is then written as an Incremental Update. + *

+ * + * @author wprinz + */ +public class TextualSignator_1_0_0 implements Signator +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_0_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * Default constructor. + */ + public TextualSignator_1_0_0() + { + // Default constructor. + } + + /** + *

+ * The parameter has_SIG_ID is not used by this Signator because it doesn't + * pre-format the signature block. + *

+ * + * @see at.gv.egiz.pdfas.framework.signator.Signator#prepareSign(at.gv.egiz.pdfas.framework.input.PdfDataSource, + * java.lang.String, at.knowcenter.wag.egov.egiz.pdf.TablePos, boolean) + */ + public SignatorInformation prepareSign(PdfDataSource pdfDataSource, String profile, TablePos pos, TimeStamper timestamper) throws SignatorException + { + try + { + + SignatureTypeDefinition std = SignatureTypes.getInstance().getSignatureTypeDefinition(profile); + if (!std.isTextExtractable()) + { + throw new SignatorException(ErrorCode.PROFILE_NOT_USABLE_FOR_TEXT, "The signature profile " + profile + " is not text extractable and thereby cannot be used for textual signature."); + } + + TextualSignatorInformation tsi = new TextualSignatorInformation(); + tsi.originalDocument = pdfDataSource; + tsi.profile = profile; + tsi.pos = pos; + + String document_text = PdfAS.extractNormalizedTextTextual(pdfDataSource, this.getEncoding()); + tsi.setNonTextualObjects(ObjectExtractor.extractNonTextInfo(pdfDataSource)); + // logger_.debug("signed_text = " + document_text); + + DataSource ds = new TextDataSourceImpl(document_text); + tsi.signatureData = new SignatureDataImpl(ds, "text/plain", "UTF-8"); + + return tsi; + } + catch (PresentableException pe) + { + throw new SignatorException(pe); + } + } + + /** + * @see at.gv.egiz.pdfas.framework.signator.Signator#finishSign(at.gv.egiz.pdfas.framework.signator.SignatorInformation, + * at.gv.egiz.pdfas.framework.output.DataSink) + */ + public void finishSign(SignatorInformation signatorInformation, DataSink dataSink) throws SignatorException + { + try + { + TextualSignatorInformation tsi = (TextualSignatorInformation) signatorInformation; + + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.TEXT_ID); + + // iui.signed_signature_object.kz = getMyId().toString(); + tsi.signSignatureObject.kz = getMyId().toString(); + // TODO what is this for? + + SignatureObject so = SignatureObjectHelper.convertSignSignatureObjectToSignatureObject(tsi.signSignatureObject, tsi.profile); + + evaluteOgnl(so, tsi); + + PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(so); + + PositioningInstruction pi = PdfAS.determineTablePositioning(tsi.pos, tsi.profile, tsi.originalDocument, pdf_table); + + IncrementalUpdateInformation iui = IncrementalUpdateHelper.writeIncrementalUpdateToDataSink(tsi.originalDocument, dataSink, pdf_table, tsi.profile, pi, null, signatorInformation, so); + tsi.atp = iui.actualTablePos; + +// OutputStream os = dataSink.createOutputStream(PdfAS.PDF_MIME_TYPE); +// os.write(signed_iui.signed_pdf); +// os.close(); + +// SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, signed_iui.signed_pdf); +// return sign_result; + } + catch (PresentableException pe) + { + throw new SignatorException(pe); + } + finally { + OverridePropertyHolder.removeOgnlUtil(); + } +// catch (IOException e) +// { +// throw new SignatorException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); +// } + } + + private void evaluteOgnl(SignatureObject so, TextualSignatorInformation tsi) { + HashMap ognlCtx = new HashMap(); + //ognlCtx.put("iui", tsi.); + ognlCtx.put("sso", tsi.signSignatureObject); + ognlCtx.put("issuer", tsi.signSignatureObject.getIssuerDNMap()); + ognlCtx.put("subject", tsi.signSignatureObject.getSubjectDNMap()); + OgnlUtil ognl = new OgnlUtil(ognlCtx); + OverridePropertyHolder.setOgnlUtil(ognl); + + Iterator it = so.getSigEntries().values().iterator(); + while (it.hasNext()) + { + SignatureEntry se = (SignatureEntry) it.next(); + + if (ognl.containsExpression(se.getValue())) { + // evaluate expression + String res = ognl.compileMessage(se.getValue()); + se.setValue(res); + //ri.value = this.normalizer.normalize(res, true); + + } + } + } + + public String getEncoding() { + // old signatures used this encoding implicit most of the time (windows default) + return "cp1252"; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java new file mode 100644 index 0000000..fde9ae0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_1_0.java @@ -0,0 +1,53 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $ + */ +package at.gv.egiz.pdfas.impl.signator.textual; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * Signs a document textually. + * + * @see TextualSignator_1_0_0 + * + * @author wprinz + */ +public class TextualSignator_1_1_0 extends TextualSignator_1_0_0 +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_1_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_2_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_2_0.java new file mode 100644 index 0000000..3d0d200 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/signator/textual/TextualSignator_1_2_0.java @@ -0,0 +1,53 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.signator.textual; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * + * @author dferbas + * + */ +public class TextualSignator_1_2_0 extends TextualSignator_1_1_0 { + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_2_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + public String getEncoding() { + // nail encoding to utf8 from this version on + return "utf8"; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java new file mode 100644 index 0000000..9d67f0b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_0_0.java @@ -0,0 +1,453 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinaryVerificator_1_0_0.java,v 1.3 2006/10/11 08:03:22 wprinz Exp $ + */ +package at.gv.egiz.pdfas.impl.verificator.binary; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.verificator.Verificator; +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.DelimitedPdfDataSource; +import at.gv.egiz.pdfas.impl.vfilter.helper.VerificationFilterBinaryHelper; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.framework.VerificationFilter; +import at.knowcenter.wag.egov.egiz.pdf.BinaryBlockInfo; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.Placeholder; +import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference; +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NameParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ParseResult; + +/** + * The BinaryVerificator parses the EGIT Dictionary and extracts the signature + * holder from it. + * + * @author wprinz + */ +public class BinaryVerificator_1_0_0 implements Verificator +{ + /** + * The Pdf-AS ID of this Verificator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0); + + /** + * Use this to override the MY_ID field. + * + * @return Returns the Id of this Verificator. + */ + protected PdfASID getMyId() + { + return MY_ID; + } + + /** + * The /ODS key in the EGIZ Dict. + */ + public static final byte[] EGIZ_ODS_NAME = new byte[] { 'O', 'D', 'S' }; + + /** + * The /ID key in the EGIZ Dict. + */ + public static final byte[] EGIZ_KZ_NAME = VerificationFilter.EGIZ_KZ_NAME; + + /** + * The /ByteRange key in the EGIZ Dict. + */ + public static final byte[] EGIZ_BYTE_RANGE_NAME = new byte[] { 'B', 'y', 't', 'e', 'R', 'a', 'n', 'g', 'e' }; + + /** + * The /replaces key in the EGIZ Dict. + */ + public static final byte[] EGIZ_REPLACES_NAME = new byte[] { 'r', 'e', 'p', 'l', 'a', 'c', 'e', 's' }; + + /** + * The /encodings key in the EGIZ Dict. + */ + public static final byte[] EGIZ_ENCODINGS_NAME = new byte[] { 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g', 's' }; + + /** + * The /Cert key in the EGIZ Dict. + */ + public static final byte[] EGIZ_CERT_NAME = new byte[] { 'C', 'e', 'r', 't' }; + + /** + * The /TimeStamp key in the EGIZ Dict. + */ + public static final byte[] EGIZ_TIMESTAMP_NAME = new byte[] { 'T', 'i', 'm', 'e', 'S', 't', 'a', 'm', 'p' }; + + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BinaryVerificator_1_0_0.class); + + /** + * Default constructor. + */ + public BinaryVerificator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.gv.egiz.pdfas.framework.verificator.Verificator#parseBlock(at.gv.egiz.pdfas.framework.input.PdfDataSource, + * byte[], + * at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(PdfDataSource pdfDataSource, byte [] pdf, FooterParseResult block, int start_of_whole_block) throws PresentableException + { + // PERF: BinaryVerificator needs byte array. + + int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, VerificationFilter.EGIZ_DICT_NAME); + if (egiz_index < 0) + { + throw new PDFDocumentException(ErrorCode.COULDNT_VERIFY, "egiz_index = " + egiz_index); + } + + IndirectObjectReferenceParseResult egiz_dict_iorpr = (IndirectObjectReferenceParseResult) block.tpr.dpr.values.get(egiz_index); + + IndirectObjectReference ior = egiz_dict_iorpr.ior; + + final int egiz_dict_offset = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(block.xpr, ior); + + ObjectParseResult obj = PDFUtils.parseObject(pdf, egiz_dict_offset); + DictionaryParseResult egiz_dict = (DictionaryParseResult) obj.object; + + NumberParseResult ods_npr = (NumberParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_ODS_NAME); + + ArrayParseResult kz_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_KZ_NAME); + PdfASID kz = null; +// String kz_string = VerificationFilter.restoreKZ(pdf, kz_apr); + String kz_string = VerificationFilterBinaryHelper.restoreKZ(pdf, kz_apr); // dferbas hack baik test + // TODO baik hack kz_string = "urn:pdfsigfilter:bka.gv.at:binaer:v1.0.0"; + kz = new PdfASID(kz_string); + if (!kz_string.equals(getMyId().toString())) + { + logger_.warn("Warning: Kennzeichnung not recognized:" + kz_string); + } + + ArrayParseResult byte_ranges_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_BYTE_RANGE_NAME); + + ArrayParseResult replaces_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_REPLACES_NAME); + + ArrayParseResult encodings_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_ENCODINGS_NAME); + + ArrayParseResult cert_apr = (ArrayParseResult) getValueOfKey(pdf, egiz_dict, EGIZ_CERT_NAME); + byte[] cert = null; + if (cert_apr != null && !cert_apr.elements.isEmpty()) + { + LiteralStringParseResult lspr = (LiteralStringParseResult) cert_apr.elements.get(0); + int str_length = lspr.content_end_index - lspr.content_start_index; + byte[] encoded = new byte[str_length]; + System.arraycopy(pdf, lspr.content_start_index, encoded, 0, encoded.length); + + cert = Placeholder.unescapePDFString(encoded); + } + + //timestamp + ArrayParseResult timestamp_apr = (ArrayParseResult) getValueOfKey(pdf, egiz_dict, EGIZ_TIMESTAMP_NAME); + byte[] timestamp = null; + if (timestamp_apr != null) { + logger_.debug("found /TimeStamp in egiz dict. Extracting..."); + + if (timestamp_apr != null && !timestamp_apr.elements.isEmpty()) + { + LiteralStringParseResult lspr = (LiteralStringParseResult) timestamp_apr.elements.get(0); + int str_length = lspr.content_end_index - lspr.content_start_index; + byte[] encoded = new byte[str_length]; + System.arraycopy(pdf, lspr.content_start_index, encoded, 0, encoded.length); + + timestamp = Placeholder.unescapePDFString(encoded); + + } + } + + + int num_byte_ranges = byte_ranges_apr.elements.size() / 2; + List byte_ranges = new ArrayList(); + for (int i = 0; i < num_byte_ranges; i++) + { + NumberParseResult start_npr = (NumberParseResult) byte_ranges_apr.elements.get(2 * i); + NumberParseResult length_npr = (NumberParseResult) byte_ranges_apr.elements.get(2 * i + 1); + + StringInfo si = new StringInfo(); + si.string_start = start_npr.number; + si.string_length = length_npr.number; + byte_ranges.add(si); + } + + StringInfo sis[] = new StringInfo[num_byte_ranges - 1]; + for (int i = 0; i < num_byte_ranges - 1; i++) + { + StringInfo prev = (StringInfo) byte_ranges.get(i); + StringInfo next = (StringInfo) byte_ranges.get(i + 1); + + StringInfo hole = new StringInfo(); + hole.string_start = prev.string_start + prev.string_length; + hole.string_length = next.string_start - hole.string_start; + + sis[i] = hole; + } + + int n = replaces_apr.elements.size(); + byte[][] brevs = new byte[n][]; + for (int i = 0; i < n; i++) + { + NameParseResult lspr = (NameParseResult) replaces_apr.elements.get(i); + + byte[] brev = new byte[3]; + System.arraycopy(pdf, lspr.name_start_index, brev, 0, brev.length); + + brevs[i] = brev; // SignatureTypes.convertBrevToType(brev); + } + + n = encodings_apr.elements.size(); + byte[][] encodings = new byte[n][]; + for (int i = 0; i < n; i++) + { + NameParseResult lspr = (NameParseResult) encodings_apr.elements.get(i); + + byte[] enc = new byte[3]; + System.arraycopy(pdf, lspr.name_start_index, enc, 0, enc.length); + encodings[i] = enc; + } + + BinaryBlockInfo bbi = new BinaryBlockInfo(); + bbi.replaces = BinarySignature.reconstructReplaces(pdf, brevs, sis, encodings); + bbi.signed_size = ods_npr.number; + + // BinaryBlockInfo bbi = BinarySignature.retrieveEgizDictInformation(pdf, + // ior.object_number, ior.generation_number, egiz_dict_offset); + + // byte[] original_pdf = BinarySignature.restoreEgizDictInformation(pdf, + // bbi); + + byte[] signed_pdf = BinarySignature.prepareDataToSign(pdf, byte_ranges); + // String signed_text = + // BinarySignature.retrieveSignableTextFromData(signed_pdf, + // signed_pdf.length); // has been moved into the BinarySignatureHolder + + SignatureObject signature_object = new SignatureObject(); + String default_type = SettingsReader.getInstance().getValueFromKey(SignatureTypes.DEFAULT_TYPE); + signature_object.setSigType(default_type); + signature_object.initByType(); + + signature_object.setKZ(kz); + + if (timestamp != null) { + String ts = new String(trimZeroBytes(timestamp)); + signature_object.setTimeStamp(ts); + if (logger_.isDebugEnabled()) { + logger_.debug("extracted timestamp " + ts); + } + } + + if (cert != null) + { + try + { + // ByteArrayInputStream bais = new ByteArrayInputStream(cert); + // CertificateFactory cf = CertificateFactory.getInstance("X.509"); + // X509Certificate certificate = (X509Certificate) + // cf.generateCertificate(bais); + + // trim zero bytes. - the base 64 cert must not have zero bytes. + byte[] b64 = trimZeroBytes(cert); + + signature_object.storeNewCertificateInLocalStore(b64); + } + catch (Exception e) + { + logger_.error(e.getMessage(), e); + } + + } + + Iterator rit = bbi.replaces.iterator(); + while (rit.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) rit.next(); + + String type = SignatureTypes.convertBrevToType(ri.brev); + + if (type == null) { + throw new PresentableException(ErrorCode.UNSUPPORTED_REPLACES_NAME, "Unsupported /replaces name."); + } + + // signature_object.setSigValue(ri.type, ri.value); + if (type.equals(SignatureTypes.SIG_DATE)) + { + signature_object.setSignationDate(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_ISSUER)) + { + signature_object.setSignationIssuer(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_VALUE)) + { + signature_object.setSignationValue(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_NUMBER)) + { + signature_object.setSignationSerialNumber(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_ID)) + { + signature_object.setSignationIDs(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_ALG)) + { + signature_object.setSigAlg(ri.value); + continue; + } + } + + int iu_length = signed_pdf.length - start_of_whole_block; + byte [] iu_block = new byte [iu_length]; + System.arraycopy(signed_pdf, start_of_whole_block, iu_block, 0, iu_length); + + DelimitedPdfDataSource dpds = new DelimitedPdfDataSource(pdfDataSource, start_of_whole_block); + PdfDataSource ds = new CompoundPdfDataSourceImpl(dpds, iu_block); + + //PdfDataSource dsByteArray = new ByteArrayPdfDataSourceImpl(signed_pdf, signed_pdf.length); + + BinarySignatureHolder signature_holder = new BinarySignatureHolder(ds, signature_object); + + List holders = new ArrayList(); + holders.add(signature_holder); + return holders; + } + + private byte[] trimZeroBytes(byte[] arr) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < arr.length; i++) + { + if (arr[i] != 0) + { + baos.write(arr[i]); + } + } + byte[] b64 = baos.toByteArray(); + return b64; + } + + /** + * Retrieves the value of the key from the dictionary. + * + * @param pdf + * The PDF. + * @param egiz_dict + * The dictionary. + * @param name + * The name of the key. + * @return Returns the value of the key. An exception is thrown if the key + * doesn't exist. + * @throws PDFDocumentException + * Thrown, if the key doesn't exist in the dictionary. + */ + protected ParseResult getRequiredValueOfKey(byte[] pdf, DictionaryParseResult egiz_dict, byte[] name) throws PDFDocumentException + { + final int index = PDFUtils.indexOfName(pdf, egiz_dict.names, name); + checkIndex(index); + ParseResult value = (ParseResult) egiz_dict.values.get(index); + return value; + } + + /** + * Throws an excaption, if the index is lower than 0. + * + * @param name_index + * The index. + * @throws PDFDocumentException + * Thrown, if the index is lower than 0. + */ + protected void checkIndex(int name_index) throws PDFDocumentException + { + if (name_index < 0) + { + throw new PDFDocumentException(ErrorCode.COULDNT_VERIFY, "The name wasn't found in the egiz dict."); + } + } + + /** + * Retrieves the value of the key from the dictionary. + * + * @param pdf + * The PDF. + * @param egiz_dict + * The dictionary. + * @param name + * The name of the key. + * @return Returns the key's value, or null if the dictionary didn't contain + * that key. + */ + protected ParseResult getValueOfKey(byte[] pdf, DictionaryParseResult egiz_dict, byte[] name) + { + final int index = PDFUtils.indexOfName(pdf, egiz_dict.names, name); + if (index < 0) + { + return null; + } + ParseResult value = (ParseResult) egiz_dict.values.get(index); + return value; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java new file mode 100644 index 0000000..ae18408 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/verificator/binary/BinaryVerificator_1_1_0.java @@ -0,0 +1,44 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.verificator.binary; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * @author wprinz + * + */ +public class BinaryVerificator_1_1_0 extends BinaryVerificator_1_0_0 +{ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_1_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.verificators.BinaryVerificator_1_0_0#getMyId() + */ + protected PdfASID getMyId() + { + return MY_ID; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java new file mode 100644 index 0000000..f4e91bd --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/Partition.java @@ -0,0 +1,29 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter; + +public interface Partition +{ + public boolean isTextPartition(); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java new file mode 100644 index 0000000..3f0f482 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterImpl.java @@ -0,0 +1,964 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang.time.StopWatch; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException; +import at.gv.egiz.pdfas.framework.SignatureHolderHelper; +import at.gv.egiz.pdfas.framework.VerificatorFactory; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.framework.verificator.Verificator; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilter; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; +import at.gv.egiz.pdfas.impl.input.DelimitedPdfDataSource; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.gv.egiz.pdfas.impl.vfilter.helper.VerificationFilterBinaryHelper; +import at.gv.egiz.pdfas.impl.vfilter.helper.VerificationFilterHelper; +import at.gv.egiz.pdfas.impl.vfilter.partition.BinaryPartition; +import at.gv.egiz.pdfas.impl.vfilter.partition.TextPartition; +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.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.EGIZDate; +import at.knowcenter.wag.egov.egiz.pdf.NoSignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + +/** + * @author wprinz + */ +public class VerificationFilterImpl implements VerificationFilter +{ + + /** + * The log. + */ + private static final Log log = LogFactory.getLog(VerificationFilterImpl.class); + + + public static final String CHECK_DOCUMENT = "check_document"; + public static final String SUPRESS_EXCEPTION_WHEN_LAST_UIBLOCK_IS_NO_SIGNATURE = "supress_exception_when_last_iublock_is_no_signature"; + public static final String BINARY_ONLY = "binary_only"; + public static final String ASSUME_ONLY_SIGNATURE_BLOCKS = "assume_only_signature_blocks"; + + /** + * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilter#extractSignatureHolders(at.gv.egiz.pdfas.framework.input.PdfDataSource, + * java.util.List, + * at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters) + */ + public List extractSignatureHolders(final PdfDataSource pdf, List blocks, final VerificationFilterParameters parameters) throws VerificationFilterException + { + log.trace("extractSignaturHolders:"); + StopWatch sw = new StopWatch(); + sw.start(); + + if (log.isDebugEnabled()) + { + log.debug("Original IU blocks: " + blocks.size()); + debugIUBlocks(blocks); + } + + unrollLinearization(blocks); + + if (log.isDebugEnabled()) + { + log.debug("IU blocks without linearization: " + blocks.size()); + debugIUBlocks(blocks); + } + + + SettingsReader settings; + try { + settings = SettingsReader.getInstance(); + } catch (SettingsException e) { + throw new VerificationFilterException(e); + } + String check_doc = settings.getSetting(CHECK_DOCUMENT, "false"); + + // check document for textual sigs here here if binary_only is set + if ("true".equalsIgnoreCase(check_doc) && + parameters.extractBinarySignaturesOnly()) { + + checkBinaryOnly(pdf, parameters.scanForOldSignatures()); + log.debug("checkDocument: " + sw.getTime() + "ms."); + } else { + log.debug("Skipping checkDocument for textual sigs."); + } + // end add + + List signatureHolderChain = null; + + if (parameters.extractBinarySignaturesOnly()) + { + log.debug("Extracting only binary signatures. Binary-only mode."); + + signatureHolderChain = performBinaryOnly(pdf, blocks); + } + else + { + List partitions = VerificationFilterHelper.partition(pdf, blocks); + if (log.isDebugEnabled()) + { + debugPartitions(partitions); + } + + if (parameters.assumeOnlySignatureUpdateBlocks()) + { + log.debug("Assuming that there are only signature Incremental Update blocks. Semi-conservative mode."); + + signatureHolderChain = performSemiConservative(pdf, parameters.scanForOldSignatures(), blocks, partitions); + } + else + { + log.debug("Scanning complete document. Conservative mode."); + + signatureHolderChain = performFullConservative(pdf, parameters.scanForOldSignatures(), blocks, partitions); + } + + } + + log.trace("extractSignaturHolders finished (" + (signatureHolderChain != null ? signatureHolderChain.size() : 0) + " elements)."); + sw.stop(); + log.debug("extractSignatureHolders: " + sw.getTime() + "ms."); + + return signatureHolderChain; + } + + /** + * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilter#extractSignaturHolders(at.gv.egiz.pdfas.framework.input.TextDataSource, + * at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters) + */ + public List extractSignaturHolders(TextDataSource text, VerificationFilterParameters parameters) throws VerificationFilterException + { + if (parameters.extractBinarySignaturesOnly()) + { + log + .warn("A free text signature extraction was issued although the VerificationFilter was configured to detect only binary signatures (binary-only mode). The result is of course that no signatures can be found."); + + return new ArrayList(); + } + + String freetext = text.getText(); + String normalizedText = normalizeText(freetext); + + List foundSignatures = null; + if (parameters.scanForOldSignatures()) + { + log.debug("Extracting old and new signatures from text."); + + foundSignatures = extractNewAndOldSignaturesFromText(normalizedText); + } + else + { + log.debug("Extracting new signatures from text (not extracting old ones)."); + + foundSignatures = extractNewSignaturesFromText(normalizedText); + } + + List textOnlySignatures = filterOutBinarySignatures(foundSignatures); + + return textOnlySignatures; + } + + protected String normalizeText(String freetext) throws VerificationFilterException + { + try + { + return PdfAS.normalizeText(freetext); + } + catch (NormalizeException e) + { + throw new VerificationFilterException(e); + } + } + + /** + * Removes the linearization footer from the list of update blocks. + * + * @param blocks + * The list of FooterParseResult objects in \prev order. + */ + protected void unrollLinearization(List blocks) + { + int linearization_index = -1; + for (int i = 0; i < blocks.size(); i++) + { + FooterParseResult bpr = (FooterParseResult) blocks.get(i); + + if (bpr.sxpr.xref_index == 0) + { + if (linearization_index >= 0) + { + throw new RuntimeException("There is more than one linearization block! index = " + i); + } + linearization_index = i; + } + } + + if (linearization_index >= 0) + { +// logger_.debug("The document is linearized - unrolling +// linearization block " + linearization_index); + blocks.remove(linearization_index); + } + } + + protected List performBinaryOnly(PdfDataSource pdf, List blocks) throws VerificationFilterException + { + return extractBinarySignaturesOnly(pdf, blocks); + } + + protected List performSemiConservative(PdfDataSource pdf, boolean scanForOldSignatures, List blocks, List partitions) throws VerificationFilterException + { + log.debug("perform semiConservative()..."); + List binarySignatures = extractBinarySignaturesOnly(pdf, blocks); + + log.debug("determining last partition..."); + TextPartition lastTextPartition = VerificationFilterHelper.findLastTextPartition(partitions); + List extractedSignatures = null; + if (scanForOldSignatures) + { + SignaturesAndOld sao = extractSignaturesFromPartitionAndOld(pdf, lastTextPartition); + extractedSignatures = sao.newSignatures; + if (sao.oldSignature != null) + { + extractedSignatures.add(0, sao.oldSignature); + } + } + else + { + log.debug("extracting signatures from last partition..."); + extractedSignatures = extractSignaturesFromPartition(pdf, lastTextPartition); + } + + + List signatureHolderChain = intermingleSignatures(binarySignatures, extractedSignatures); + + return signatureHolderChain; + } + + protected List performFullConservative(PdfDataSource pdf, boolean scanForOldSignatures, List blocks, List partitions) throws VerificationFilterException + { + List binarySignatures = extractBinarySignaturesOnly(pdf, blocks); + + // extract signature values of found binary signature blocks and store these values in a Set + // this set is later used to filter out the binary signatures that are recognized as text + // signatures. + Set binarySigValues = new HashSet(); + Iterator iterator = binarySignatures.iterator(); + while(iterator.hasNext()) { + + SignatureHolder sh = (SignatureHolder)iterator.next(); + + String sigVal = sh.getSignatureObject().getSignationValue(); + binarySigValues.add(sigVal); + } + + SignatureHolder oldSignature = null; + + //List originalPartitions = partitions; + // This gives every IU block an own text partition + // This allows text signatures to be found correctly if there are + // IU blocks with disturbing text after them. + // On the other hand, these requires extra text extractions and + // signature searches and thereby is slow. + List flattedOutPartitions = flattenOutTextPartitions(partitions, blocks); + partitions = flattedOutPartitions; + + SettingsReader settings; + try { + settings = SettingsReader.getInstance(); + } catch (SettingsException e) { + throw new VerificationFilterException(e); + } + String check_doc = settings.getSetting(CHECK_DOCUMENT, "false"); + boolean supressException = "true".equalsIgnoreCase(settings.getSetting(SUPRESS_EXCEPTION_WHEN_LAST_UIBLOCK_IS_NO_SIGNATURE, "false")); + + // flag indicating that the last IU-block of the document is a non-signature IU-block + boolean lastBlockWasModified = false; + + // counter of all signatures (textual and binary) of this document + int signatureCounter = 0; + + // counter of all textual signatures in this document + int txtSigsSoFar = 0; + + // counter of all textual signatures in the current partition + int txtSigsThisPartition = 0; + + List partitionResults = new ArrayList(partitions.size()); + List nshList = new ArrayList(); + + boolean sigFound = false; + + for (int i = 0; i < partitions.size(); i++) + { + Partition p = (Partition) partitions.get(i); + + // updating flag and counter + boolean partitionContainsNewTextSignatures = true; + txtSigsSoFar = txtSigsThisPartition; + + if (p instanceof TextPartition) + { + TextPartition tp = (TextPartition) p; + + List partitionResult = null; + + boolean scanThisPartitionForOldSignature = (i == 0) && scanForOldSignatures; + if (scanThisPartitionForOldSignature) + { + SignaturesAndOld sao = extractSignaturesFromPartitionAndOld(pdf, tp); + partitionResult = sao.newSignatures; + oldSignature = sao.oldSignature; + } + else + { + partitionResult = extractSignaturesFromPartition(pdf, tp); + } + + // binary signature blocks that have been detected as well are identified by comparing their signature values + // with those stored in our Set above and are not considered for our IU-check + List onlyTextSignatures = new ArrayList(); + Iterator iter = partitionResult.iterator(); + while(iter.hasNext()) { + + SignatureHolder sh = (SignatureHolder)iter.next(); + if(!binarySigValues.contains(sh.getSignatureObject().getSignationValue())) { + + onlyTextSignatures.add(sh); + } + } + + // update signature counters + txtSigsThisPartition = onlyTextSignatures.size(); + int newTextSignatures = txtSigsThisPartition - txtSigsSoFar; + signatureCounter = signatureCounter + newTextSignatures; + + // update sigFound flag + if(txtSigsThisPartition > 0) { + + sigFound = true; + } + + // TextPartition is only valid, if at least one more text signature has been found than in the previous text partition + if(!(newTextSignatures > 0)) { + + partitionContainsNewTextSignatures = false; + } + + partitionResults.add(partitionResult); + } else { + // should be binary partition + if(p instanceof BinaryPartition) { + + BinaryPartition binpart = (BinaryPartition)p; + + // updating counter and flag + signatureCounter = signatureCounter + binpart.blocks.size(); + sigFound = true; + + } + } + + // if document checking is enabled, at least one signature has been found so far, we are dealing with a + // non-signature IU-block + if ((check_doc.equalsIgnoreCase("true"))&& (sigFound && !partitionContainsNewTextSignatures)) { + + nshList.add(new NoSignatureHolder(signatureCounter)); + lastBlockWasModified = true; + + } else { + + lastBlockWasModified = false; + } + + } + + // throw an exception if the last update block does not contain a signature and signatures have been found in this document + if (lastBlockWasModified) { + if (!supressException) { + throw new VerificationFilterException(ErrorCode.MODIFIED_AFTER_SIGNATION, "The document has been modified after being signed."); + } else { + log.debug("The document has been modified after being signed. According to the configuration, no exception is thrown."); + } + } + + List extractedSignatures = new ArrayList(); + Iterator it = partitionResults.iterator(); + List prevPartitionResult = null; + while (it.hasNext()) + { + List partitionResult = (List) it.next(); + + if (prevPartitionResult == null) + { + extractedSignatures.addAll(partitionResult); + } + else + { + assert partitionResult.size() >= prevPartitionResult.size(); + +// for (int i = prevPartitionResult.size(); i < partitionResult.size(); i++) +// { +// SignatureHolder sh = (SignatureHolder) partitionResult.get(i); +// extractedSignatures.add(sh); +// } + mergeSignatures(prevPartitionResult, partitionResult, extractedSignatures); + } + + prevPartitionResult = partitionResult; + } + + List signatureHolderChain = intermingleSignatures(binarySignatures, extractedSignatures); + + if (oldSignature != null) + { + signatureHolderChain.add(0, oldSignature); + } + + // add the created NoSignatureHolders + signatureHolderChain.addAll(nshList); + + return signatureHolderChain; + } + + private void mergeSignatures(List oldList, List newList, List result) { + + for(int i=0; i < newList.size(); i++) { + + SignatureHolder currentNewSh = (SignatureHolder)newList.get(i); + + boolean shAlreadyPresentInOldList = false; + int pos = -1; + + for(int j=0; j add + result.add(currentNewSh); + } + + } + + + return; + } + + + protected List flattenOutTextPartitions (List partitions, List blocks) + { + + List blockPartitions = new ArrayList(blocks.size()); + Iterator it = partitions.iterator(); + while (it.hasNext()) + { + Partition p = (Partition)it.next(); + if (p instanceof TextPartition) + { + TextPartition tp = (TextPartition)p; + Iterator blockIt = tp.blocks.iterator(); + while (blockIt.hasNext()) + { + FooterParseResult fpr = (FooterParseResult)blockIt.next(); + TextPartition newPt = new TextPartition(); + newPt.blocks = new ArrayList(1); + newPt.blocks.add(fpr); + blockPartitions.add(newPt); + } + } + else + { + // binary partition + blockPartitions.add(p); + } + } + + // note: successive binary blocks are still combined to one binary partition + assert blockPartitions.size() <= blocks.size(); + + return blockPartitions; + } + + protected String extractText(PdfDataSource pdf, int endOfDocument) throws PresentableException { + return extractText(pdf, endOfDocument, "utf8"); + } + + protected String extractText(PdfDataSource pdf, int endOfDocument, String encoding) throws PresentableException + { + + log.debug("EXTRACTING TEXT (" + encoding + ")... end index = " + endOfDocument); + + DelimitedPdfDataSource dds = new DelimitedPdfDataSource(pdf, endOfDocument); + //DelimitedInputStream dis = new DelimitedInputStream(pdf.createInputStream(), endOfDocument); + return PdfAS.extractNormalizedTextTextual(dds, encoding); + } + + + protected List extractNewSignaturesFromText(String text) throws VerificationFilterException + { + try + { + return AbsoluteTextSignature.extractSignatureHoldersFromText(text); + } + catch (PresentableException e) + { + throw new VerificationFilterException(e); + } + } + + protected List extractNewAndOldSignaturesFromText(String text) throws VerificationFilterException + { + SignaturesAndOld sao = extractSignaturesAndOld(text); + if (sao.oldSignature != null) + { + sao.newSignatures.add(0, sao.oldSignature); + } + + return sao.newSignatures; + } + + protected List extractOldSignaturesFromText(String text) throws PresentableException + { + return PdfAS.extractSignatureHoldersTextual(text, true); + } + + protected List intermingleSignatures(List binarySignatures, List extractedSignatures) + { + List textualSignatures = filterOutBinarySignatures(extractedSignatures); + + List intermingled = new ArrayList(binarySignatures.size() + textualSignatures.size()); + intermingled.addAll(binarySignatures); + intermingled.addAll(textualSignatures); + + sortSignatures(intermingled); + + return intermingled; + } + + protected List filterOutBinarySignatures(List signatures) + { + List textOnly = new ArrayList(signatures.size()); + + Iterator it = signatures.iterator(); + while (it.hasNext()) + { + SignatureHolder sh = (SignatureHolder) it.next(); + if (sh.getSignatureObject().isTextual()) + { + textOnly.add(sh); + } + } + + return textOnly; + } + + protected void sortSignatures(List signatures) + { + SignatureHolderHelper.sortByDate(signatures); + } + + protected void debugIUBlocks(List blocks) + { + Iterator it = blocks.iterator(); + while (it.hasNext()) + { + FooterParseResult fpr = (FooterParseResult) it.next(); + log.debug("footer: " + fpr.start_index + " to " + fpr.next_index + ", has predecessor = " + fpr.tpr.has_predecessor); + } + } + + protected void debugPartitions(List partitions) + { + Iterator it = partitions.iterator(); + while (it.hasNext()) + { + Object o = it.next(); + assert o instanceof Partition; + + List blocks = null; + if (o instanceof TextPartition) + { + TextPartition tp = (TextPartition) o; + + blocks = tp.blocks; + + log.debug("text partition with " + tp.blocks.size() + " blocks:"); + } + else + { + BinaryPartition bp = (BinaryPartition) o; + + blocks = bp.blocks; + + log.debug("binary partition: with " + bp.blocks.size() + " blocks:"); + + } + debugIUBlocks(blocks); + log.debug("partition finished."); + } + } + + /** + * Extracts the binary singatures from the given PDF. + * + *

+ * IU blocks without an egiz dict are not considered. + *

+ * + * @param pdf + * @param blocks + * @return Returns the List of signature holders. + * @throws PresentableException + */ + protected List extractBinarySignaturesOnly(PdfDataSource pdf, List blocks) throws VerificationFilterException + { + SettingsReader settings; + try { + settings = SettingsReader.getInstance(); + } catch (SettingsException e) { + throw new VerificationFilterException(e); + } + String check_doc = settings.getSetting(CHECK_DOCUMENT, "false"); + String binary_only = settings.getSetting(BINARY_ONLY, "false"); + String assume_sigs_only = settings.getSetting(ASSUME_ONLY_SIGNATURE_BLOCKS, "false"); + boolean supressException = "true".equalsIgnoreCase(settings.getSetting(SUPRESS_EXCEPTION_WHEN_LAST_UIBLOCK_IS_NO_SIGNATURE, "false")); + + try + { + // PERF: extract binary signatures needs byte array + byte[] data = DataSourceHelper.convertDataSourceToByteArray(pdf); + + List binarySignatures = new ArrayList(blocks.size()); + + Iterator it = blocks.iterator(); + int prev_end = 0; + boolean sig_detected = false; + while (it.hasNext()) + { + FooterParseResult fpr = (FooterParseResult) it.next(); + assert fpr.next_index > prev_end; + + if (VerificationFilterBinaryHelper.containsEGIZDict(data, fpr)) + { + PdfASID kz = VerificationFilterBinaryHelper.extractKZFromEGIZBlock(data, fpr); + + // TODO dferbas hack baik test + //kz = new PdfASID("urn:pdfsigfilter:bka.gv.at:binaer:v1.1.0"); + + Verificator verificator = VerificatorFactory.createBinaryVerificator(kz); + List binary_holders = verificator.parseBlock(pdf, data, fpr, prev_end); + + binarySignatures.addAll(binary_holders); + if(binary_holders.size() > 0) { + sig_detected = true; + } + } else { + // an Exception is thrown here if: + // 1) check_document is activated + // 2) assume_only_signature_blocks is false - otherwise we permit updates + // 3) binary_only is true - otherwise updates are handled in method performFullConservative(). + // when binary-only is true, we can be sure that a block that contains no egiz-dict is no textual + // signature either but an illegal update, otherwise an Exception (doc contains textual sig) would have been thrown before + // 4) a binary signature has been detected in a previous block + if(check_doc.equalsIgnoreCase("true") && + binary_only.equalsIgnoreCase("true") && + assume_sigs_only.equalsIgnoreCase("false") && + sig_detected) { + + if (!supressException) { + throw new VerificationFilterException(ErrorCode.MODIFIED_AFTER_SIGNATION, "The document has been modified after being signed."); + } else { + log.debug("The document has been modified after being signed. According to the configuration, no exception is thrown."); + } + + } + } + + prev_end = fpr.next_index; + } + + return binarySignatures; + } + catch (PresentableException e) + { + throw new VerificationFilterException(e); + } + } + + protected List extractSignatures(PdfDataSource pdf, int endOfDocument) throws VerificationFilterException + { + try + { + log.debug("Extracting text from 0 to " + endOfDocument + " (total document size = " + pdf.getLength() + "):"); + String extractedText = extractText(pdf, endOfDocument); + log.debug("Extracting text finished."); + log.debug("extracted text: " + extractedText); + + log.debug("Extracting signatures:"); + List extractedSignatures = extractNewSignaturesFromText(extractedText); + log.debug("Extracting signatures finished."); + log.debug("Number of found signatures: " + extractedSignatures.size()); + + if (extractedSignatures.size() > 0) { + List cp1252SignaturesPositions = new ArrayList(); + //boolean iscp1252Sig = false; + for (int i = 0; i < extractedSignatures.size(); i++) { + SignatureHolder sh = (SignatureHolder)extractedSignatures.get(i); + PdfASID kzid = sh.getSignatureObject().getKZ(); + if (kzid != null && kzid.isOldCp1252Version()) { + log.debug("found cp1252 signature"); + cp1252SignaturesPositions.add(new Integer(i)); + //iscp1252Sig = true; + //break; + } + } + if (cp1252SignaturesPositions.size() > 0) { + log.debug("redo text and signature extraction with cp1252 encoding"); + extractedText = extractText(pdf, endOfDocument, "cp1252"); + log.debug("Extracting text finished."); + + log.debug("Extracting signatures:"); + List cp1252ExtractedSignatures = extractNewSignaturesFromText(extractedText); + log.debug("Extracting signatures finished."); + log.debug("Number of found signatures: " + extractedSignatures.size()); + + if (cp1252ExtractedSignatures.size() != extractedSignatures.size()) { + log.error("Invalid cp1252 signatures found. Skipping cp1252 compatibility."); + } + // merge signature holders + for (int i = 0; i < cp1252SignaturesPositions.size(); i++) { + int replaceIndex = ((Integer)cp1252SignaturesPositions.get(i)).intValue(); + extractedSignatures.remove(replaceIndex); + extractedSignatures.add(replaceIndex, cp1252ExtractedSignatures.get(replaceIndex)); + } + } + + } + + if (log.isDebugEnabled()) + { + log.debug("extracted signatures:"); + for (int i = 0; i < extractedSignatures.size(); i++) + { + SignatureHolder sh = (SignatureHolder)extractedSignatures.get(i); + String dateStr = sh.getSignatureObject().getSignationDate(); + EGIZDate ed = EGIZDate.parseFromString(dateStr); + log.debug("#" + i + ": dateStr = " + dateStr + ", egizDate = " + ed.toString()); + } + } + + return extractedSignatures; + } + catch (PresentableException e) + { + throw new VerificationFilterException(e); + } + } + + protected String determineRestText(List newSignatures, String extractedText) + { + if (newSignatures.isEmpty()) + { + return extractedText; + } + + // note that even if the oldest signature is a binary signature, + // the rest text is the text of this binary signature, which was extracted + // like a text signature. + TextualSignatureHolder oldestSignature = (TextualSignatureHolder) newSignatures.get(0); + return oldestSignature.getSignedText(); + } + + protected List extractSignaturesFromPartition(PdfDataSource pdf, Partition partition) throws VerificationFilterException + { + assert partition.isTextPartition(); + + int endOfDocument = VerificationFilterHelper.getEndOfPartition(partition); + List extractedSigs = extractSignatures(pdf, endOfDocument); + TextualSignatureHolder.mulitSetUiBlockEndPos(extractedSigs, endOfDocument); + return extractedSigs; + } + + protected SignaturesAndOld extractSignaturesFromPartitionAndOld(PdfDataSource pdf, Partition partition) throws VerificationFilterException + { + assert partition.isTextPartition(); + + try + { + int endOfDocument = VerificationFilterHelper.getEndOfPartition(partition); + +// log.debug("Extracting text from 0 to " + endOfDocument + " (total document size = " + pdf.getLength() + "):"); + String extractedText = extractText(pdf, endOfDocument); +// log.debug("Extracting text finished."); +// log.debug("extracted text: " + extractedText); + + SignaturesAndOld sao = extractSignaturesAndOld(extractedText); + TextualSignatureHolder.trySetUiBlockEndPos(sao.oldSignature, endOfDocument); + TextualSignatureHolder.mulitSetUiBlockEndPos(sao.newSignatures, endOfDocument); + + return sao; + } + catch (PresentableException e) + { + throw new VerificationFilterException(e); + } + } + + protected void checkBinaryOnly(PdfDataSource pdf, boolean considerOldSigs) throws VerificationFilterException { + + DelimitedPdfDataSource dds = new DelimitedPdfDataSource(pdf, pdf.getLength()); + String text = null; + try { + text = PdfAS.extractNormalizedTextTextual(dds, "utf-8"); + } catch (PresentableException e) { + throw new VerificationFilterException(e); + } + + List sigs = new ArrayList(); + + if(considerOldSigs) { + SignaturesAndOld sao = extractSignaturesAndOld(text); + if(sao != null) { + if(sao.newSignatures != null) { + sigs.addAll(sao.newSignatures); + } + if(sao.oldSignature != null) { + sigs.add(sao.oldSignature); + } + } + } else { + List signatures = extractSignatures(pdf, pdf.getLength()); + if(signatures != null) { + sigs.addAll(signatures); + } + } + + Iterator it = sigs.iterator(); + while(it.hasNext()) { + SignatureHolder current = (SignatureHolder)it.next(); + if((current != null)&&(!current.getSignatureObject().isBinary())) { + throw new VerificationFilterException(ErrorCode.NON_BINARY_SIGNATURES_PRESENT, "The document contains non-binary signatures."); + } + } + } + + + protected static class SignaturesAndOld + { + public List newSignatures = null; + + public SignatureHolder oldSignature = null; + } + + protected SignaturesAndOld extractSignaturesAndOld(String text) throws VerificationFilterException + { + try + { + log.debug("Extracting signatures:"); + List extractedSignatures = extractNewSignaturesFromText(text); + log.debug("Extracting signatures finished."); + + log.debug("Extracting old signatures:"); + SignatureHolder oldSignature = extractOldSignature(text, extractedSignatures); + log.debug("Extracting old signatures finished."); + log.debug("oldSignature = null: " + (oldSignature==null)); + + SignaturesAndOld sao = new SignaturesAndOld(); + sao.newSignatures = extractedSignatures; + sao.oldSignature = oldSignature; + + return sao; + } + catch (PresentableException e) + { + throw new VerificationFilterException(e); + } + } + + /** + * Extracts the old signature from the text, but only if it is older than the + * oldest signature of the new signatueres. + * + * @param extractedText + * @param newSignatures + * @return + * @throws PDFDocumentException + * @throws SignatureException + * @throws NormalizeException + * @throws SignatureTypesException + */ + protected SignatureHolder extractOldSignature(String extractedText, List newSignatures) throws PDFDocumentException, SignatureException, NormalizeException, SignatureTypesException + { + SignatureHolder oldSignature = null; + + String restText = determineRestText(newSignatures, extractedText); + + List oldSignatures = PdfAS.extractSignatureHoldersTextual(restText, true); + if (!oldSignatures.isEmpty()) + { + oldSignature = (SignatureHolder) oldSignatures.get(0); + if (!newSignatures.isEmpty()) + { + SignatureHolder oldestNewSignature = (SignatureHolder) newSignatures.get(0); + EGIZDate oldDate = EGIZDate.parseFromString(oldSignature.getSignatureObject().getSignationDate()); + EGIZDate newDate = EGIZDate.parseFromString(oldestNewSignature.getSignatureObject().getSignationDate()); + if (newDate.compareTo(oldDate) <= 0) + { + oldSignature = null; + } + } + } + return oldSignature; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java new file mode 100644 index 0000000..635dc99 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/VerificationFilterParametersImpl.java @@ -0,0 +1,98 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; + +/** + * @author wprinz + * + */ +public class VerificationFilterParametersImpl implements VerificationFilterParameters, Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -7118403150485416046L; + + protected boolean extractBinarySignaturesOnly = false; + + protected boolean assumeOnlySignatureUpdateBlocks = false; + + protected boolean scanForOldSignatures = true; + + protected boolean hasBeenCorrected = false; + + public VerificationFilterParametersImpl(boolean extractBinarySignaturesOnly, boolean assumeOnlySignatureUpdateBlocks, boolean scanForOldSignatures) + { + this.extractBinarySignaturesOnly = extractBinarySignaturesOnly; + this.assumeOnlySignatureUpdateBlocks = assumeOnlySignatureUpdateBlocks; + this.scanForOldSignatures = scanForOldSignatures; + } + + /** + * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters#extractBinarySignaturesOnly() + */ + public boolean extractBinarySignaturesOnly() + { + return this.extractBinarySignaturesOnly; + } + + /** + * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters#assumeOnlySignatureUpdateBlocks() + */ + public boolean assumeOnlySignatureUpdateBlocks() + { + return this.assumeOnlySignatureUpdateBlocks; + } + + + /** + * @see at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters#scanForOldSignatures() + */ + public boolean scanForOldSignatures() + { + return this.scanForOldSignatures; + } + + /** + * @see java.lang.Object#toString() + */ + // @override + public String toString() + { + return "{VerificationFilterParametersImpl: extractBinarySignaturesOnly = " + extractBinarySignaturesOnly() + ", assumeOnlySignatureUpdateBlocks = " + assumeOnlySignatureUpdateBlocks() + "}"; + } + + public boolean hasBeenCorrected() { + return this.hasBeenCorrected; + } + + public void setBeenCorrected(boolean corrected) { + this.hasBeenCorrected = corrected; + + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java new file mode 100644 index 0000000..735b874 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterBinaryHelper.java @@ -0,0 +1,190 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter.helper; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.Placeholder; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference; +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; + +/** + * Contains helpful methods used by the VerificationFilter to analyze the PDF for binary signatures. + * + * @author wprinz + */ +public final class VerificationFilterBinaryHelper +{ + /** + * The name of the egiz dict key. + */ + public static final byte[] EGIZ_DICT_NAME = { 'E', 'G', 'I', 'Z', 'S', 'i', 'g', 'D', 'i', 'c', 't' }; + + /** + * The name of the ID (SIG_KZ) property in the egiz dict. + */ + public static final byte[] EGIZ_KZ_NAME = { 'I', 'D' }; + + /** + * The log. + */ + private static final Log log = LogFactory.getLog(VerificationFilterBinaryHelper.class); + + /** + * Tells, if the given incremental update block contains a binary signature. + * + *

+ * According to definition, if a block is a binary block, it must/cannot + * contain other signatures than this one. + *

+ * + * @param block + * The incremental update block. + * @return Returns true, if this block is a binary signature block, false + * otherwise. + */ + public static boolean containsEGIZDict(final byte[] pdf, final FooterParseResult block) + { + int dict_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, EGIZ_DICT_NAME); + if (dict_index <= 0) + { + return false; + } + + return true; + } + + /** + * Extracts the PDF AS ID of the egiz block. + * + * @param pdf + * The pdf. + * @param block + * The IU block. + * @return Returns the extracted PDF AS ID. + * @throws PDFDocumentException + * Forwarded exception. + * @throws InvalidIDException + * Forwarded exception. + */ + public static PdfASID extractKZFromEGIZBlock(final byte[] pdf, final FooterParseResult block) throws PDFDocumentException, InvalidIDException + { + int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, EGIZ_DICT_NAME); + if (egiz_index < 0) + { + throw new PDFDocumentException(301, "egiz_index = " + egiz_index); + } + + IndirectObjectReferenceParseResult egiz_dict_iorpr = (IndirectObjectReferenceParseResult) block.tpr.dpr.values.get(egiz_index); + // logger_.debug("egiz_dict_ir = " + egiz_dict_iorpr.ior.object_number + // + " " + egiz_dict_iorpr.ior.generation_number); + + IndirectObjectReference ior = egiz_dict_iorpr.ior; + + final int egiz_dict_offset = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(block.xpr, ior); + // logger_.debug("egiz_dict_offset = " + egiz_dict_offset); + + ObjectParseResult obj = PDFUtils.parseObject(pdf, egiz_dict_offset); + DictionaryParseResult egiz_dict = (DictionaryParseResult) obj.object; + + int kz_index = PDFUtils.indexOfName(pdf, egiz_dict.names, EGIZ_KZ_NAME); + if (kz_index < 0) + { + throw new PDFDocumentException(301, "kz_index = " + kz_index); + } + ArrayParseResult kz_apr = (ArrayParseResult) egiz_dict.values.get(kz_index); + + String kz_string = restoreKZ(pdf, kz_apr); + PdfASID kz = new PdfASID(kz_string); + + return kz; + } + + /** + * Restores the Kennzeichnung String from an Array. + * + * @param pdf + * The PDF. + * @param kz_apr + * The Array, as parsed from the EGIZ Dict. + * @return Returns the restored KZ. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static String restoreKZ(byte[] pdf, ArrayParseResult kz_apr) throws PDFDocumentException + { + try + { + List partition = new ArrayList(); + + int linesToProcess = (kz_apr.elements.size() / 2); + log.trace("Lines to process for KZ: " + linesToProcess); + /* + if (linesToProcess > 1) { + log.debug("Multiple KZHOTFIX: forcing single line to process"); + linesToProcess = 1; + } + */ + for (int i = 0; i < linesToProcess; i++) + { + NumberParseResult start_npr = (NumberParseResult) kz_apr.elements.get(i * 2); + NumberParseResult length_npr = (NumberParseResult) kz_apr.elements.get(i * 2 + 1); + + StringInfo si = new StringInfo(); + si.string_start = start_npr.number; + si.string_length = length_npr.number; + si.pdf = pdf; + + log.trace("Adding KZ: " + si.toString()); + + partition.add(si); + } + + String KZ = Placeholder.reconstructStringFromPartition(pdf, partition, BinarySignature.ENCODING_WIN); + return KZ; + } + catch (IOException e1) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e1); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java new file mode 100644 index 0000000..69803e7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterHelper.java @@ -0,0 +1,162 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter.helper; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.gv.egiz.pdfas.exceptions.framework.VerificationFilterException; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.gv.egiz.pdfas.impl.vfilter.Partition; +import at.gv.egiz.pdfas.impl.vfilter.partition.BinaryPartition; +import at.gv.egiz.pdfas.impl.vfilter.partition.TextPartition; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + +/** + * Contains helpful methods used by the VerificationFilter. + * + * @author wprinz + */ +public final class VerificationFilterHelper +{ + /** + * Partitions the list of Incremental Update blocks into text and binary + * partitions. + * + *

+ * A partition is a sequence of Incremental Update blocks of the same type. + *

+ *

+ * An Incremental Update block is considered to have the type "binary" if it + * contains an egiz dictionary. A block not containing an egiz dictionary is + * considert to have the type "text". + *

+ * + * @param pdf + * The PDF. + * @param blocks + * The Incremental Update blocks. + * @return Returns the partitioning of the blocks. + * @throws VerificationFilterException + * Thrown if something goes wrong. + */ + public static List partition(PdfDataSource pdf, List blocks) throws VerificationFilterException + { + List partitions = new ArrayList(blocks.size()); + + Iterator it = blocks.iterator(); + while (it.hasNext()) + { + FooterParseResult fpr = (FooterParseResult) it.next(); + + byte[] data = DataSourceHelper.convertDataSourceToByteArray(pdf); + if (VerificationFilterBinaryHelper.containsEGIZDict(data, fpr)) + { + BinaryPartition bp = null; + if (partitions.isEmpty() || ((Partition) partitions.get(partitions.size() - 1)).isTextPartition()) + { + bp = new BinaryPartition(); + bp.blocks = new ArrayList(blocks.size()); + partitions.add(bp); + } + else + { + bp = (BinaryPartition) partitions.get(partitions.size() - 1); + } + assert bp != null; + + bp.blocks.add(fpr); + } + else + { + TextPartition tp = null; + if (partitions.isEmpty() || !((Partition) partitions.get(partitions.size() - 1)).isTextPartition()) + { + tp = new TextPartition(); + tp.blocks = new ArrayList(blocks.size()); + partitions.add(tp); + } + else + { + tp = (TextPartition) partitions.get(partitions.size() - 1); + } + assert tp != null; + + tp.blocks.add(fpr); + } + } + + assert partitions.size() >= 1 : "There must be at least one partition"; + + return partitions; + } + + /** + * Determines the end of the given partiton. + * + * @param partition + * The partition. + * @return Returns the end index of the given partition. + */ + public static int getEndOfPartition(Partition partition) + { + List blocks = null; + if (partition instanceof TextPartition) + { + blocks = ((TextPartition) partition).blocks; + } + else + { + blocks = ((BinaryPartition) partition).blocks; + } + + return ((FooterParseResult) blocks.get(blocks.size() - 1)).next_index; + } + + /** + * Finds the last text partition in the given list of partitions. + * + * @param partitions + * The partitions. + * @return Returns the last TextPartition. + */ + public static TextPartition findLastTextPartition(List partitions) + { + Partition lastTextPartition = (Partition) partitions.get(partitions.size() - 1); + + if (!lastTextPartition.isTextPartition()) + { + assert partitions.size() > 1 : "The only one partition cannot be a binary partition - where is the original document?"; + Partition previousToLastPartition = (Partition) partitions.get(partitions.size() - 2); + assert previousToLastPartition.isTextPartition() : "The previous to last partition must be a text partition or something is wrong with the partitioning algorithm."; + + lastTextPartition = previousToLastPartition; + } + + return (TextPartition) lastTextPartition; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java new file mode 100644 index 0000000..87aa159 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/helper/VerificationFilterTextHelper.java @@ -0,0 +1,35 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter.helper; + +/** + * Contains helpful methods used by the VerificationFilter to analyze text and + * find text signatures. + * + * @author wprinz + */ +public final class VerificationFilterTextHelper +{ + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java new file mode 100644 index 0000000..5b3c7e2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/BinaryPartition.java @@ -0,0 +1,39 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter.partition; + +import java.util.List; + +import at.gv.egiz.pdfas.impl.vfilter.Partition; + + +public class BinaryPartition implements Partition +{ + public List blocks = null; + + public boolean isTextPartition() + { + return false; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java new file mode 100644 index 0000000..665a5ef --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/vfilter/partition/TextPartition.java @@ -0,0 +1,40 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.vfilter.partition; + +import java.util.List; + +import at.gv.egiz.pdfas.impl.vfilter.Partition; + + +public class TextPartition implements Partition +{ + public List blocks = null; + + public boolean isTextPartition() + { + return true; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/xmldsig/XMLDsigReconstructor.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/xmldsig/XMLDsigReconstructor.java new file mode 100644 index 0000000..f7d5f37 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/impl/xmldsig/XMLDsigReconstructor.java @@ -0,0 +1,76 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.impl.xmldsig; + +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.commandline.CommandlineConnectorChooser; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper; + +/** + * Utility class for reconstructing xmldsig + * + * @author exthex + * + */ +public class XMLDsigReconstructor { + + /** + * Reconstructs the xmldsig from the given parameters. + * + * @param si the signature information from which to reconstruct the xmldsig + * @param connectorType the type of connector (usually BKU or MOA) to use to create the xmldsig + * @return + * @throws ConnectorException + * @throws ConnectorFactoryException + * @throws SignatureException + */ + public static XMLDsigData reconstruct(SignatureInformation si, String connectorType) throws ConnectorException, ConnectorFactoryException, SignatureException { + SignatureHolder holder = (SignatureHolder)si.getInternalSignatureInformation(); + SignatureObject sigObject = holder.getSignatureObject(); + + SignSignatureObject so = SignatureObjectHelper.convertSignatureObjectToSignSignatureObject(sigObject); + SignatureData sd = PdfAS.convertSignatureHolderToSignatureData(holder); + + String profile = sigObject.getSignatureTypeDefinition().getType(); + String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForVerify(connectorType, sigObject.getKZ(), so.id, profile); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + Connector c = at.gv.egiz.pdfas.framework.ConnectorFactory.createConnector(connectorId, cp); + + return c.reconstructXMLDsig(sd, so); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java new file mode 100644 index 0000000..03e7999 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSink.java @@ -0,0 +1,107 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java new file mode 100644 index 0000000..e00211a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/ByteArrayDataSource.java @@ -0,0 +1,115 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java new file mode 100644 index 0000000..c93ad2a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSink.java @@ -0,0 +1,116 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java new file mode 100644 index 0000000..7cb585d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedDataSource.java @@ -0,0 +1,141 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java new file mode 100644 index 0000000..aaf99ea --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/FileBasedTextBasedDataSource.java @@ -0,0 +1,123 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java new file mode 100644 index 0000000..8fe0dd6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/io/StringTextBasedDataSource.java @@ -0,0 +1,116 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +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; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java new file mode 100644 index 0000000..d03187c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounter.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.performance; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author wprinz + */ +public class PerformanceCounter +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(PerformanceCounter.class); + + protected String name = null; + + protected long counter = 0; + + public PerformanceCounter(String name) + { + this.name = name; + reset(); + } + + public PerformanceCounter(Class clazz) + { + this(clazz.getName()); + } + + public void increment() + { + this.counter++; + log.trace(this.name + ": incremented to " + this.counter); + } + + public void reset() + { + this.counter = 0; + log.trace(this.name + ": reset to 0"); + } + + /** + * @return the name + */ + public String getName() + { + return this.name; + } + + /** + * @return the counter + */ + public long getCounter() + { + return this.counter; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java new file mode 100644 index 0000000..831c7c2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceCounters.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.performance; + +/** + * Contains various global PerformanceCounters that provide information about the system. + * + * @author wprinz + */ +public final class PerformanceCounters +{ + /** + * Keeps track of the number of text extractions done so far. + */ + public static PerformanceCounter textExtractions = new PerformanceCounter("TextExtractions"); + + /** + * Keeps track of the number of large byte array allocations. + */ + public static PerformanceCounter byteArrays = new PerformanceCounter("ByteArrays"); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java new file mode 100644 index 0000000..c405383 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/performance/PerformanceTimer.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.performance; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author wprinz + * + */ +public class PerformanceTimer +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(PerformanceTimer.class); + + protected String name = null; + + protected long startTime = -1; + + protected long stopTime = -1; + + public PerformanceTimer(String name) + { + this.name = name; + } + + public void start() + { + this.startTime = System.currentTimeMillis(); + log.trace(this.name + ": started at " + this.startTime); + } + + public void stop() + { + this.stopTime = System.currentTimeMillis(); + log.trace(this.name + ": stopped at " + this.stopTime); + log.trace(this.name + ": time elapsed = " + getTimeElapsed()); + } + + public long getTimeElapsed() + { + return this.stopTime - this.startTime; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderContext.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderContext.java new file mode 100644 index 0000000..0636304 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderContext.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.placeholder; + +/** + * Store and retrieve {@link SignaturePlaceholderData} in/from a thread local context. + * + * @author exthex + * + */ +public class SignaturePlaceholderContext { + + private ThreadLocal sigHolder = new ThreadLocal(); + + private static SignaturePlaceholderContext instance = new SignaturePlaceholderContext(); + + /** + * Constructor. Private because this is a singleton. + */ + private SignaturePlaceholderContext() { + + } + + /** + * Get the {@link SignaturePlaceholderData} which is currently bound to this thread. + * Might be null. + * + * @return + */ + public static SignaturePlaceholderData getSignaturePlaceholderData(){ + return (SignaturePlaceholderData)instance.sigHolder.get(); + } + + /** + * + * @return true if there is currently a {@link SignaturePlaceholderData} bound to this thread, false otherwise. + */ + public static boolean isSignaturePlaceholderDataSet() { + return instance.sigHolder.get() != null; + } + + /** + * Bind a {@link SignaturePlaceholderData} to this thread. + * If the given data is null, the context will be cleared. + * + * @param data if null, clears the ThreadLocal, else binds the data to the current thread. + */ + public static void setSignaturePlaceholderData(SignaturePlaceholderData data) { + instance.sigHolder.set(data); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderData.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderData.java new file mode 100644 index 0000000..ec42d75 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderData.java @@ -0,0 +1,152 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.placeholder; + +import at.knowcenter.wag.egov.egiz.pdf.TablePos; + +/** + * This class represents all the data which can be extracted from a placeholder image. + * + * @author exthex + * + */ +public class SignaturePlaceholderData { + + public static final String ID_KEY = "id"; + + public static final String PROFILE_KEY = "profile"; + + public static final String TYPE_KEY = "type"; + + public static final String SIG_KEY_KEY = "key"; + + private String profile; + + private String type; + + private String key; + + private String id; + + private TablePos tablePos; + + private String placeholderName; + + /** + * + * @param profile + * @param type + * @param sigKey + * @param id + */ + public SignaturePlaceholderData(String profile, String type, String sigKey, String id) { + this.profile = profile; + this.type = type; + this.key = sigKey; + this.id = id; + } + + /** + * Get the table position for the signature block.
+ * The table position is created from the page number, the upper left corner and the width of the placeholder image. + * + * @return + */ + public TablePos getTablePos() { + return tablePos; + } + + void setTablePos(TablePos tablePos) { + this.tablePos = tablePos; + } + + /** + * The profile name. Might be null if not included in the qr-code. + * + * @return + */ + public String getProfile() { + return profile; + } + + void setProfile(String profile) { + this.profile = profile; + } + + /** + * The signature type: "textual" or "binary". Might be null if not included in the qr-code. + * @return + */ + public String getType() { + return type; + } + + void setType(String type) { + this.type = type; + } + + /** + * The key identifier for MOA signature. Might be null if not included in the qr-code. + * + * @return + */ + public String getKey() { + return key; + } + + void setKey(String key) { + this.key = key; + } + + public String toString() { + return getClass().toString() + ": profile=" + profile + "; type=" + type + "; sigKey=" + key + "; table pos=" + tablePos; + } + + void setPlaceholderName(String name) { + this.placeholderName = name; + } + + /** + * The name of the placeholder image. + * + * @return + */ + public String getPlaceholderName() { + return placeholderName; + } + + /** + * The id associated with this placeholder. + * + * @return + */ + public String getId() { + return id; + } + + void setId(String id) { + this.id = id; + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderExtractor.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderExtractor.java new file mode 100644 index 0000000..8abe516 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/placeholder/SignaturePlaceholderExtractor.java @@ -0,0 +1,350 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.placeholder; + +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.exceptions.WrappedIOException; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage; +import org.apache.pdfbox.util.Matrix; +import org.apache.pdfbox.util.PDFOperator; +import org.apache.pdfbox.util.PDFStreamEngine; +import org.apache.pdfbox.util.ResourceLoader; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.PlaceholderExtractionException; +import at.gv.egiz.pdfas.utils.PDFASUtils; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.LuminanceSource; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.NotFoundException; +import com.google.zxing.ReaderException; +import com.google.zxing.Result; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.HybridBinarizer; + +////// + + + +/** + * Extract all relevant information from a placeholder image. + * + * @author exthex + * + */ +public class SignaturePlaceholderExtractor extends PDFStreamEngine { + /** + * The log. + */ + private static Log log = LogFactory.getLog(SignaturePlaceholderExtractor.class); + + private List placeholders = new Vector(); + private int currentPage = 0; + + private SignaturePlaceholderExtractor(String placeholderId, int placeholderMatchMode) throws IOException { + super(ResourceLoader.loadProperties("at/gv/egiz/pdfas/placeholder/pdfbox-reader.properties", + true)); + } + + /** + * Search the document for placeholder images and possibly included + * additional info.
+ * Searches only for the first placeholder page after page from top. + * + * @param inputStream + * @return all available info from the first found placeholder. + * @throws PDFDocumentException if the document could not be read. + * @throws PlaceholderExtractionException if STRICT matching mode was requested and no suitable placeholder could be found. + */ + public static SignaturePlaceholderData extract(InputStream inputStream, String placeholderId, int matchMode) + throws PDFDocumentException, PlaceholderExtractionException { + SignaturePlaceholderContext.setSignaturePlaceholderData(null); + PDDocument doc = null; + try + { + try { + doc = PDDocument.load(inputStream); + } catch (IOException e) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + PDFASUtils.checkDocumentPermissions(doc); + SignaturePlaceholderExtractor extractor; + try + { + extractor = new SignaturePlaceholderExtractor(placeholderId, matchMode); + } catch (IOException e2) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e2); + } + List pages = doc.getDocumentCatalog().getAllPages(); + Iterator iter = pages.iterator(); + int pageNr = 0; + while (iter.hasNext()) { + pageNr++; + PDPage page = (PDPage) iter.next(); + try { + extractor.setCurrentPage(pageNr); + extractor.processStream( page, page.findResources(), page.getContents().getStream() ); + SignaturePlaceholderData ret = matchPlaceholderPage(extractor.placeholders, placeholderId, matchMode); + if (ret != null){ + SignaturePlaceholderContext.setSignaturePlaceholderData(ret); + return ret; + } + } catch (IOException e1) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e1); + } + + } + if (extractor.placeholders.size() > 0){ + SignaturePlaceholderData ret = matchPlaceholderDocument(extractor.placeholders, placeholderId, matchMode); + SignaturePlaceholderContext.setSignaturePlaceholderData(ret); + return ret; + } + // no placeholders found, apply strict mode if set + if (matchMode == Constants.PLACEHOLDER_MATCH_MODE_STRICT) { + throw new PlaceholderExtractionException(ErrorCode.SIGNATURE_PLACEHOLDER_EXTRACTION_FAILED, "no suitable placeholder found and STRICT matching mode requested."); + } + + return null; + } finally { + if (doc != null) + try { + doc.close(); + } catch (IOException e) { + log.debug("Could not close document.", e); + } + } + + } + + private static SignaturePlaceholderData matchPlaceholderDocument( + List placeholders, String placeholderId, int matchMode) throws PlaceholderExtractionException { + + if (matchMode == Constants.PLACEHOLDER_MATCH_MODE_STRICT) + throw new PlaceholderExtractionException(ErrorCode.SIGNATURE_PLACEHOLDER_EXTRACTION_FAILED, "no suitable placeholder found and STRICT matching mode requested."); + + if (placeholders.size() == 0) + return null; + + for (int i = 0; i < placeholders.size(); i++) + { + SignaturePlaceholderData spd = (SignaturePlaceholderData)placeholders.get(i); + if (spd.getId() == null) + return spd; + } + + if (matchMode == Constants.PLACEHOLDER_MATCH_MODE_LENIENT) + return (SignaturePlaceholderData)placeholders.get(0); + + return null; + } + + private static SignaturePlaceholderData matchPlaceholderPage(List placeholders, + String placeholderId, int matchMode) { + if (placeholders.size() == 0) + return null; + for (int i = 0; i < placeholders.size(); i++) + { + SignaturePlaceholderData data = (SignaturePlaceholderData)placeholders.get(i); + if (placeholderId != null && placeholderId.equals(data.getId())) + return data; + if (placeholderId == null && data.getId() == null) + return data; + } + return null; + } + + private void setCurrentPage(int pageNr) { + this.currentPage = pageNr; + } + + protected void processOperator( PDFOperator operator, List arguments ) throws IOException + { + String operation = operator.getOperation(); + if( operation.equals( "Do" ) ) + { + COSName objectName = (COSName)arguments.get( 0 ); + Map xobjects = getResources().getXObjects(); + PDXObject xobject = (PDXObject)xobjects.get( objectName.getName() ); + if( xobject instanceof PDXObjectImage ) + { + try + { + PDXObjectImage image = (PDXObjectImage)xobject; + SignaturePlaceholderData data = checkImage(image); + if (data != null) + { + PDPage page = getCurrentPage(); + Matrix ctm = getGraphicsState().getCurrentTransformationMatrix(); + double rotationInRadians = (page.findRotation() * Math.PI)/180; + + AffineTransform rotation = new AffineTransform(); + rotation.setToRotation( rotationInRadians ); + AffineTransform rotationInverse = rotation.createInverse(); + Matrix rotationInverseMatrix = new Matrix(); + rotationInverseMatrix.setFromAffineTransform( rotationInverse ); + Matrix rotationMatrix = new Matrix(); + rotationMatrix.setFromAffineTransform( rotation ); + + Matrix unrotatedCTM = ctm.multiply( rotationInverseMatrix ); + + float x = unrotatedCTM.getXPosition(); + float y = unrotatedCTM.getYPosition() + unrotatedCTM.getYScale(); + float w = unrotatedCTM.getXScale(); + + String posString = "p:" + currentPage + ";x:" + x + ";y:" + y + ";w:" + w; + try + { + data.setTablePos(new TablePos(posString)); + data.setPlaceholderName(objectName.getName()); + placeholders.add(data); + } catch (PDFDocumentException e) { + throw new WrappedIOException(e); + } + } + } + catch( NoninvertibleTransformException e ) + { + throw new WrappedIOException( e ); + } + } + } + else + { + super.processOperator( operator, arguments ); + } + } + + /** + * Checks an image if it is a placeholder for a signature. + * + * @param image + * @return + * @throws IOException + */ + private SignaturePlaceholderData checkImage(PDXObjectImage image) throws IOException { + BufferedImage bimg = image.getRGBImage(); + if (bimg == null) { + String type = image.getSuffix(); + if (type != null) { + type = type.toUpperCase() + " images"; + } else { + type = "Image type"; + } + log.info("Unable to extract image for QRCode analysis. " + type + " not supported. Add additional JAI Image filters to your classpath. Refer to https://jai.dev.java.net. Skipping image."); + return null; + } + if(bimg.getHeight() < 10 || bimg.getWidth() < 10) { + log.debug("Image too small for QRCode. Skipping image."); + return null; + } + + LuminanceSource source = new BufferedImageLuminanceSource(bimg); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + Result result; + long before = System.currentTimeMillis(); + try { + Hashtable hints = new Hashtable(); + Vector formats = new Vector(); + formats.add(BarcodeFormat.QR_CODE); + hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); + result = new MultiFormatReader().decode(bitmap, hints); + + String text = result.getText(); + String profile = null; + String type = null; + String sigKey = null; + String id = null; + if (text != null) { + if (text.startsWith(Constants.QR_PLACEHOLDER_IDENTIFIER)) { + String[] data = text.split(";"); + if (data.length > 1) { + for (int i = 1; i < data.length; i++) { + String kvPair = data[i]; + String[] kv = kvPair.split("="); + if (kv.length != 2) { + log.debug("Invalid parameter in placeholder data: " + kvPair); + } else { + if (kv[0].equalsIgnoreCase(SignaturePlaceholderData.ID_KEY)) { + id = kv[1]; + } else if (kv[0].equalsIgnoreCase(SignaturePlaceholderData.PROFILE_KEY)) { + profile = kv[1]; + } else if (kv[0] + .equalsIgnoreCase(SignaturePlaceholderData.SIG_KEY_KEY)) { + sigKey = kv[1]; + } else if (kv[0] + .equalsIgnoreCase(SignaturePlaceholderData.TYPE_KEY)) { + type = kv[1]; + } + } + } + } + return new SignaturePlaceholderData(profile, type, sigKey, id); + } else { + log.warn("QR-Code found but does not start with \"" + Constants.QR_PLACEHOLDER_IDENTIFIER + "\". Ignoring QR placeholder."); + } + } + } catch (ReaderException re) { + re.printStackTrace(); + if (log.isDebugEnabled()) { + log.debug("Could not decode - not a placeholder. needed: " + + (System.currentTimeMillis() - before)); + } + if (!(re instanceof NotFoundException)){ + if (log.isInfoEnabled()) { + log.info("Failed to decode image", re); + } + } + } catch(ArrayIndexOutOfBoundsException e){ + if (log.isInfoEnabled()) { + log.info("Failed to decode image. Probably a zxing bug", e); + } + } + return null; + } + +} + + diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/test/JarExtractTest.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/test/JarExtractTest.java new file mode 100644 index 0000000..d804b64 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/test/JarExtractTest.java @@ -0,0 +1,51 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.test; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.utils.ConfigUtils; + +public final class JarExtractTest { + + private JarExtractTest() { + } + + public static void main(String[] args) { + try { + + String sysProp = System.getProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY); + System.out.println("System property \"" + Constants.CONFIG_DIR_SYSTEM_PROPERTY + "\" = " + (sysProp != null ? ("\"" + sysProp + "\"") : null)); + + String deployedTo = ConfigUtils.deployDefaultConfiguration(); + if (deployedTo != null) { + System.out.println("Configuration successfully deployed to \"" + deployedTo + "\"."); + } else { + System.out.println("Configuration was NOT deployed. Maybe a configuration already exists."); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/ConfigUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/ConfigUtils.java new file mode 100644 index 0000000..bbc64b1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/ConfigUtils.java @@ -0,0 +1,318 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.SystemUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.log4j.PropertyConfigurator; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.exceptions.ConfigUtilsException; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.pdf.Utils; + +/** + * @author Thomas Knall + */ +public final class ConfigUtils { + + private ConfigUtils() { + } + + /** + * The log. + */ + private static final Log logger_ = LogFactory.getLog(ConfigUtils.class); + + /** + * Deploys the default configuration with apache commons vfs. + * + * @param destination The destination folder. + * @param overwriteExisting If set true an already existing configuration is overwritten. If false nothing is being copied if the destination folder already exists. + * @return true if the configuration has been deployed, false if not. + * @throws ConfigUtilsException Thrown if there was an error during the deployment of the configuration. + */ + /* + private static boolean deployWithCommonsVFS(String destination, boolean overwriteExisting) throws ConfigUtilsException { + try { + FileSystemManager fsManager = VFS.getManager(); + FileObject defaultConfigurationFile = fsManager.resolveFile("res:DefaultConfiguration"); + FileObject destinationFile = fsManager.resolveFile(destination); + + if (destinationFile.exists() && !overwriteExisting) { + return false; + } + + destinationFile.copyFrom(defaultConfigurationFile, new AllFileSelector()); + return true; + } catch (FileSystemException e) { + throw new ConfigUtilsException(e); + } + } + */ + + + /** + * Deploys the default configuration from an included zip file. + * + * @param destination The destination folder. + * @param overwriteExisting If set true an already existing configuration is overwritten. If false nothing is being copied if the destination folder already exists. + * @return true if the configuration has been deployed, false if not. + * @throws ConfigUtilsException Thrown if there was an error during the deployment of the configuration. + */ + private static boolean deployFromZIP(String destination, boolean overwriteExisting) throws ConfigUtilsException { + try { + if (!overwriteExisting) { + if (configurationAlreadyExists(destination)) { + logger_.debug("There is at least one file or folder that would be overwritten at destination path \"" + destination + "\". Skipping extraction."); + return false; + } + } + InputStream in = ConfigUtils.class.getClassLoader().getResourceAsStream(Constants.DEFAULT_CONFIGURATION_ZIP_RESOURCE); + if (in == null) { + throw new ConfigUtilsException("Unable to find default configuration resource \"" + Constants.DEFAULT_CONFIGURATION_ZIP_RESOURCE + "\"."); + } + return deployFromZIP(in, destination, overwriteExisting); + } catch (IOException e) { + throw new ConfigUtilsException(e); + } + } + + /** + * Deploys the contents of a ZIP file to a certain location. + * + * @param inputStream The inputStream of a ZIP container. + * @param destination The destination folder. + * @param overwriteExisting If set true an already existing configuration is overwritten. If false nothing is being copied if the destination folder already exists. + * @return true if the configuration has been deployed, false if not. + * @throws ConfigUtilsException Thrown if there was an error during the deployment of the configuration. + */ + public static boolean deployFromZIP(InputStream inputStream, String destination, boolean overwriteExisting) throws ConfigUtilsException { + try { + if (!overwriteExisting) { + if (configurationAlreadyExists(destination)) { + logger_.debug("There is at least one file or folder that would be overwritten at destination path \"" + destination + "\". Skipping extraction."); + return false; + } + } + if (inputStream == null) { + throw new ConfigUtilsException("Unable to deploy ZIP file. InputStream is null."); + } + ZipInputStream zis = new ZipInputStream(inputStream); + ZipEntry ze; + File destinationFolder = new File(destination); + destinationFolder.mkdirs(); + logger_.debug("Extracting ZIP contents to folder \"" + destinationFolder.getCanonicalPath() + "\"."); + while ((ze = zis.getNextEntry()) != null) { + if (ze.isDirectory()) { + File newFolder = new File(destinationFolder, ze.getName()); + logger_.debug("Extracting folder \"" + newFolder.getPath() + "\"."); + newFolder.mkdirs(); + } else { + File destFile = new File(destinationFolder, ze.getName()); + logger_.trace("Extracting file \"" + destFile.getName() + "\"."); + PDFASUtils.toFile(zis, destFile); + } + zis.closeEntry(); + } + zis.close(); + return true; + } catch (IOException e) { + throw new ConfigUtilsException(e); + } + } + + private static boolean configurationAlreadyExists(String destination) throws ConfigUtilsException, IOException { + logger_.debug("Checking configuration \"" + destination + "\" already exists (resp. if there are any directories or files that would be overwritten)."); + File destinationFolder = new File(destination); + if (destinationFolder == null || !destinationFolder.exists()) { + return false; + } + InputStream in = ConfigUtils.class.getClassLoader().getResourceAsStream(Constants.DEFAULT_CONFIGURATION_ZIP_RESOURCE); + if (in == null) { + throw new ConfigUtilsException("Unable to find default configuration resource \"" + Constants.DEFAULT_CONFIGURATION_ZIP_RESOURCE + "\"."); + } + ZipInputStream zis = new ZipInputStream(in); + ZipEntry ze; + while ((ze = zis.getNextEntry()) != null) { + if (ze.isDirectory()) { + File newFolder = new File(destinationFolder, ze.getName()); + logger_.debug("Checking if folder \"" + newFolder.getPath() + "\" already exists."); + if (newFolder.exists()) { + logger_.debug("YES !"); + return true; + } else { + logger_.debug("no"); + } + } else { + File destFile = new File(destinationFolder, ze.getName()); + logger_.trace("Checking if file \"" + destFile.getName() + "\" already exists."); + if (destFile.exists()) { + logger_.trace("YES !"); + return true; + } else { + logger_.trace("no"); + } + } + zis.closeEntry(); + } + zis.close(); + return false; + } + + /** + * Deploys the default configuration to the given destination folder. + * + * @param destination The destination folder. + * @param overwriteExisting If set true an already existing configuration is overwritten. If false nothing is being copied if the destination folder already exists. + * @return The folder the configuration has been extracted to or null if the configuration has NOT been deployed. + * @throws ConfigUtilsException Thrown if there was an error during the deployment of the configuration. + */ + public static String deployDefaultConfiguration(String destination, boolean overwriteExisting) throws ConfigUtilsException { + if (destination == null) { + throw new NullPointerException("Destination must not be null."); + } + if (destination.length() == 0) { + throw new IllegalArgumentException("Destination must not be empty."); + } + return deployFromZIP(destination, overwriteExisting) ? destination : null; + } + + /** + * Deploys the default configuration to the user's home directory to the subdirectory specified by + * Constants.Constants.USERHOME_CONFIG_FOLDER. + * + * @param overwriteExisting If set true an already existing configuration is overwritten. If false nothing is being copied if the destination folder already exists. + * @return The folder the configuration has been extracted to or null if the configuration has NOT been deployed. + * @throws ConfigUtilsException Thrown if there was an error during the deployment of the configuration. + * @see Constants#USERHOME_CONFIG_FOLDER + */ + public static String deployDefaultConfiguration(boolean overwriteExisting) throws ConfigUtilsException { + String configdir = System.getProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY); + if (configdir == null) { + configdir = System.getProperty("user.home"); + if (configdir != null) { + configdir = configdir + File.separator + Constants.USERHOME_CONFIG_FOLDER; + } + } + if (configdir == null || configdir.length() == 0) { + return null; + } + return deployDefaultConfiguration(configdir, overwriteExisting); + } + + /** + * Deploys the default configuration to the user's home directory to the subdirectory specified by + * Constants.Constants.USERHOME_CONFIG_FOLDER. + * + * @return The folder the configuration has been extracted to or null if the configuration has NOT been deployed. + * @throws ConfigUtilsException Thrown if there was an error during the deployment of the configuration. + * @see Constants#USERHOME_CONFIG_FOLDER + */ + public static String deployDefaultConfiguration() throws ConfigUtilsException { + return deployDefaultConfiguration(false); + } + + public static void writeInputStreamToOutputStream(InputStream inputStream, OutputStream outputStream) throws IOException { + final int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + int len = -1; + while ((len = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, len); + } + outputStream.flush(); + } + + public static String assertFileSeparator(String path) { + if (path == null) { + throw new NullPointerException("Path must not be null."); + } + if (path.endsWith(File.separator) || path.endsWith("/") || path.endsWith("\\")) { + return path; + } else { + return (path + File.separator); + } + } + + public static void initializeLogger() { + String loggerConfiguration = System.getProperty("log4j.configuration"); + if (loggerConfiguration != null) { + logger_.info("No PDF-AS logger configured because a configuration has already been set via system property \"log4j.configuration\" (=\"" + loggerConfiguration + "\")."); + return; + } + loggerConfiguration = assertFileSeparator(SettingsReader.CONFIG_PATH) + "log4j.properties"; + File loggerConfigFile = new File(loggerConfiguration); + if (!loggerConfigFile.exists()) { + logger_.info("No PDF-AS logger configured because there is no log4j.properties within the pdf-as work dir. Maybe the logger configuration is handled by an outside application (e.g. a web application)."); + return; + } + logger_.info("Initializing PDF-AS logger (configuration = \"" + loggerConfiguration + "\")."); + PropertyConfigurator.configure(loggerConfiguration); + } + + public static void printConfigInfo(Log logger) { + int length = Utils.max(new int[] { SettingsReader.RESOURCES_PATH.length(), SettingsReader.TMP_PATH.length(), SettingsReader.CONFIG_PATH.length(), SettingsReader.CERT_PATH.length() }); + + String separator = StringUtils.repeat("*", length + 25); + String infoResources = " resources path = \"" + SettingsReader.RESOURCES_PATH + "\""; + String infoConfiguration = " configuration path = \"" + SettingsReader.CONFIG_PATH + "\""; + String infoCertStore = " certstore path = \"" + SettingsReader.CERT_PATH + "\""; + String infoTempPath = " temporary path = \"" + SettingsReader.TMP_PATH + "\""; + String encoding = " file.encoding = \"" + System.getProperty("file.encoding") + "\""; + + if (logger != null) { + logger.info(separator); + logger.info(infoResources); + logger.info(infoConfiguration); + logger.info(infoCertStore); + logger.info(infoTempPath); + logger.info(encoding); + logger.info(separator); + } else { + StringBuffer buffer = new StringBuffer(); + buffer.append(separator).append(SystemUtils.LINE_SEPARATOR); + buffer.append(infoResources).append(SystemUtils.LINE_SEPARATOR); + buffer.append(infoConfiguration).append(SystemUtils.LINE_SEPARATOR); + buffer.append(infoCertStore).append(SystemUtils.LINE_SEPARATOR); + buffer.append(infoTempPath).append(SystemUtils.LINE_SEPARATOR); + buffer.append(encoding).append(SystemUtils.LINE_SEPARATOR); + buffer.append(separator); + System.out.println(buffer.toString()); + } + } + + public static void printConfigInfo() { + printConfigInfo(null); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java new file mode 100644 index 0000000..4b26ada --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/DataHashUtils.java @@ -0,0 +1,156 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.codec.binary.Base64; + +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; + +/** + * Contains helpful methods for building data hashed. + * + *

+ * Data hashes are useful for summarizing the signed data of signatures for + * debugging and testing purposes. Do not use these hashes for signatures. + *

+ *

+ * A data hash is always a Base64 encoded String. + *

+ * + * @author wprinz + * + */ +public final class DataHashUtils +{ + + /** + * + * @param text + * @return + */ + public static String buildDataHash(String text) + { + try + { + MessageDigest md = getMessageDigest(); + // probable performance leak for very large texts + md.update(text.getBytes("UTF-8")); + byte[] rawDigest = md.digest(); + + return encodeDigest(rawDigest); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException(e); + } + } + + public static String buildDataHash(byte[] data) + { + MessageDigest md = getMessageDigest(); + md.update(data); + byte[] rawDigest = md.digest(); + + return encodeDigest(rawDigest); + } + + public static String buildDataHash(InputStream is) + { + try + { + MessageDigest md = getMessageDigest(); + + DigestInputStream dis = new DigestInputStream(is, md); + + byte[] temp = new byte[1024]; + int i = 0; + while (dis.read(temp) >= 0) + { + // this just keeps the compiler from optimizing this loop away + i++; + } + dis.close(); + + byte[] rawDigest = md.digest(); + + return encodeDigest(rawDigest); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public static String buildDataHash(SignatureHolder sh) + { + if (sh instanceof TextualSignatureHolder) + { + TextualSignatureHolder tsh = (TextualSignatureHolder) sh; + String signedText = tsh.getSignedText(); + return buildDataHash(signedText); + } + + { + BinarySignatureHolder bsh = (BinarySignatureHolder) sh; + InputStream is = bsh.getSignedPdf().createInputStream(); + return buildDataHash(is); + } + } + + protected static MessageDigest getMessageDigest() + { + try + { + MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); + return sha1; + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + } + + protected static String encodeDigest(byte[] rawDigest) + { + try + { + byte[] encoded = Base64.encodeBase64(rawDigest); + String str = new String(encoded, "US-ASCII"); + return str; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/OgnlUtil.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/OgnlUtil.java new file mode 100644 index 0000000..69b30f8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/OgnlUtil.java @@ -0,0 +1,209 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import ognl.Ognl; +import ognl.OgnlException; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +/** + * Utility class for ognl evaluation. + * ognl website + * @author dferbas + * @author mhiess + * + */ +public class OgnlUtil { + + private static final String EXP_END = "}"; + + private static final String EXP_START = "${"; + + private static final Logger log = Logger.getLogger(OgnlUtil.class); + + private Map context = new HashMap(); + private Object root = null; + + public OgnlUtil() { + this.init(null); + } + + public OgnlUtil(Map context) { + this.init(context); + } + + public OgnlUtil(Object root) { + this.root = root; + this.init(null); + } + + /** + * Adds the default utils to the context + * + * @param context1 + */ + private void init(Map context1) { + if (context1 != null) { + this.context = context1; + } + } + + private List extractExpressions(String text) { + + List expressions = new ArrayList(); + + int indexStart = 0; + int indexEnd = 0; + String exp; + + while (indexStart != -1) { + indexStart = text.indexOf(EXP_START, indexStart); + indexEnd = text.indexOf(EXP_END, indexStart); + + if (indexStart != -1 && indexEnd != -1) { + + exp = text.substring(indexStart + 2, indexEnd); + log.debug("Found expression in template: " + exp); + if (!exp.equals("") && exp != null) { + if (!expressions.contains(exp)) { + expressions.add(exp); + } else { + log.debug("Duplicated expression '" + exp + "' found"); + } + } + + indexStart = indexEnd; + } + } + + return expressions; + } + + public boolean containsExpression(String template) { + return template != null && StringUtils.contains(template,"${") && StringUtils.contains(template, "}"); + } + + /** + * Compile/evaluate a message with ognl expressions marked with ${expression} + * + * @param template + * @return + */ + public String compileMessage(String template) { + + if (this.context != null) { + String compiledMsg = template; + List expressions = this.extractExpressions(template); + + String value; + for (Iterator it = expressions.iterator(); it.hasNext();) { + String expr = (String) it.next(); + + try { + if (this.root != null) { + value = String.valueOf(Ognl.getValue(expr, this.root)); + } else { + value = String.valueOf(Ognl.getValue(expr, this.context)); + } + log.debug("Found value: '" + value + "' for expression: '" + expr + "'"); + + if (value == null) { + value = ""; + log.debug("Set value for expression to: empty string"); + } + + compiledMsg = StringUtils.replace(compiledMsg, EXP_START + expr + EXP_END, value); + } catch (OgnlException e) { + log.error(e.getMessage(), e); + } + } + log.debug("Returning compiled message: " + compiledMsg); + return compiledMsg; + } + return null; + } + + /** + * Evaluate an expression as ognl, returning result as object. No placeholders ${ } allowed. + * @param ognlExp + * @return + */ + public Object evaluate(String ognlExp) { + + if (this.context != null) { + + Object value = null; + try { + value = Ognl.getValue(ognlExp, this.context); + log.debug("Found value: '" + value + "' for expression: '" + ognlExp + "'"); + + } catch (OgnlException e) { + log.error(e.getMessage(), e); + } + return value; + } else return null; + } + + /** + * This method compiles a map of ognl expression to a map with entries + * + * @param toCompile + * @return + */ + public Map compileExpressions(Map toCompile) { + if (this.context != null) { + Map result = new HashMap(); + + for (Iterator it = result.entrySet().iterator(); it.hasNext();) { + Entry entry = (Entry) it.next(); + try { + result.put(entry.getKey(), Ognl.getValue(entry.getValue(), this.context)); + } catch (OgnlException e) { + result.put(entry.getKey(), null); + log.warn(e.getMessage(), e); + } + } + return result; + + } + return null; + } + + public Map getContext() { + return this.context; + } + + public void mergeOgnlContext(OgnlUtil ognlUtil) { + this.context.putAll(ognlUtil.getContext()); + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PDFASUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PDFASUtils.java new file mode 100644 index 0000000..4cd3bd5 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PDFASUtils.java @@ -0,0 +1,92 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.pdfbox.pdmodel.PDDocument; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +import com.lowagie.text.pdf.PdfReader; + +/** + * @author tknall + */ +public class PDFASUtils { +//23.11.2010 changed by exthex - added checkDocumentPermissions(PDDocument doc) + + private PDFASUtils() { + } + + /** + * Verifies that a document could be opened with full permissions. + * @param pdfReader The PdfReader + * @throws PDFDocumentException Thrown if document has not been opened with full permissions. + */ + public static void checkReaderPermissions(PdfReader pdfReader) throws PDFDocumentException { + if (pdfReader.isEncrypted()) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_IS_PROTECTED, "Document is encrypted."); + } + if (!pdfReader.isOpenedWithFullPermissions()) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_IS_PROTECTED, "Document is protected."); + } + } + + public static boolean toFile(byte[] data, File file) throws IOException { + return PDFASUtils.toFile(new ByteArrayInputStream(data), file); + } + + public static boolean toFile(InputStream inputStream, File file) throws IOException { + boolean result = false; + BufferedOutputStream bufferedOutputStream = null; + try { + bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file)); + ConfigUtils.writeInputStreamToOutputStream(inputStream, bufferedOutputStream); + } finally { + if (bufferedOutputStream != null) { + try { + bufferedOutputStream.close(); + result = true; + } catch (IOException e) { + result = false; + } + } + } + return result; + } + + public static void checkDocumentPermissions(PDDocument doc) throws PDFDocumentException { + if (doc.isEncrypted()) { + throw new PDFDocumentException(ErrorCode.DOCUMENT_IS_PROTECTED, "Document is encrypted."); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PdfAUtil.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PdfAUtil.java new file mode 100644 index 0000000..e741bca --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/PdfAUtil.java @@ -0,0 +1,66 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +/** + * PDF/A utility class + * @author dferbas + * + */ +public class PdfAUtil { + /** + * dferbas: Text representation of pdfa version string + */ + private static final String PDFA_PREFIX = "ISO 19005-1:2005 PDF/A-"; + /** + * Extract pdfa version from pdf metadata + * @param pdfMetadata + * @return + */ + public static String findPdfAVersion(String pdfMetadata) { + + String inf = pdfMetadata; + String pdfaNsMark = "http://www.aiim.org/pdfa/ns/id/"; + String partMark = ""; + String confMark = ""; + int pdfaI = inf.indexOf(pdfaNsMark); + + if (pdfaI > -1) { + int part = inf.indexOf(partMark); + StringBuffer version = new StringBuffer(PDFA_PREFIX); + part = part + partMark.length(); + version.append(inf.substring(part, part + 1)); + int conf = inf.indexOf(confMark); + + conf = conf + confMark.length(); + version.append(inf.substring(conf, conf + 1).toLowerCase()); + + return version.toString(); + } else { + return null; + + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java new file mode 100644 index 0000000..3dce5b1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/StreamUtils.java @@ -0,0 +1,66 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class StreamUtils +{ + + public static void writeInputStreamToOutputStream (InputStream is, OutputStream os) throws IOException + { + byte [] buffer = new byte [2048]; + + int read = -1; + while ((read = is.read(buffer)) > 0) + { + os.write(buffer, 0, read); + } + os.flush(); + is.close(); + os.close(); + } + + // The InputStream should be self- delimited. +// public static void writeInputStreamToOutputStream(InputStream is, OutputStream os, int length) throws IOException +// { +// byte [] buffer = new byte [2048]; +// +// int bytes_to_write = length; +// +// int read = -1; +// while ((read = is.read(buffer, 0, (bytes_to_write >= buffer.length) ? buffer.length : bytes_to_write)) > 0) +// { +// os.write(buffer, 0, read); +// bytes_to_write -= read; +// } +// is.close(); +// os.close(); +// +// assert bytes_to_write == 0; +// } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/TempDirHelper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/TempDirHelper.java new file mode 100644 index 0000000..bccc67b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/utils/TempDirHelper.java @@ -0,0 +1,377 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egiz.pdfas.utils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.FileBased; +import at.gv.egiz.pdfas.impl.input.FileBasedTextDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.gv.egiz.pdfas.impl.output.ByteArrayDataSink; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; + +/** + * @author wprinz + * + */ +public class TempDirHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(TempDirHelper.class); + + protected static long runningIndex = 0; + + /** + * Assembles the File of the temporary directory without checking if it really + * exists. + */ + public static File assembleTemporaryDirectoryFile() + { + File temp_dir = new File(SettingsReader.TMP_PATH); + return temp_dir; + } + + /** + * Returns the directory where temporary files should be stored. + * + *

+ * If the directory doesn't exist, it is created. + *

+ * + * @return Returns the directory where temporary files should be stored. + */ + public static File getTemporaryDirectory() + { + File temp_dir = assembleTemporaryDirectoryFile(); + if (!temp_dir.exists()) + { + temp_dir.mkdirs(); + } + return temp_dir; + } + + /** + * Deletes all files in the temporary directory, if it exists. + * + *

+ * This should be used to clear temporary files when the application shuts + * down. + *

+ */ + public static void clearTemporaryDirectory() + { + File temp_dir = assembleTemporaryDirectoryFile(); + log.debug("Clearing temporary directory: " + temp_dir); + + if (!temp_dir.exists()) + { + return; + } + + File[] files = temp_dir.listFiles(); + for (int i = 0; i < files.length; i++) + { + // added by tknall: do not try to remove svn-metadata + if (files[i].getName().endsWith(".svn")) { + continue; + } + log.debug(" Clearing temporary file: " + files[i]); + boolean delete_success = files[i].delete(); + if (!delete_success) + { + log.error("Couldn't delete the temporary file: " + files[i]); + } + } + } + + public static void storeTextSignatureHoldersIfApplicable(List shs, String fileNameSuffix) throws IOException + { + Iterator it = shs.iterator(); + while (it.hasNext()) + { + SignatureHolder sh = (SignatureHolder) it.next(); + if (sh instanceof TextualSignatureHolder) + { + TextualSignatureHolder tsh = (TextualSignatureHolder) sh; + if (!(tsh.getDataSource() instanceof FileBased)) + { + TextDataSource tds = (TextDataSource) tsh.getDataSource(); + if (isReasonableToStore(tds.getText().length())) + { + TextDataSource fbtds = placeTextIntoTempDir(tds.getText(), fileNameSuffix); + tsh.exchangeDataSource(fbtds); + } + } + } + } + } + + /** + * Places the text into the temp dir if reasonable. + * + *

+ * Reasonable means that the text is longer than a certain threshold. + * Otherwise a short text is simply held in memory. + *

+ * + * @param text + * The text to be stored. + * @param fileNameSuffix + * A file name suffix so that the temp file gets a more "readable" + * name. + * @return Returns the TextDataSource. + * @throws IOException + * F.e. + */ + public static TextDataSource placeTextIntoTempDir(String text, String fileNameSuffix) throws IOException + { + if (isReasonableToStore(text.length())) + { + String fileName = formatFileName(fileNameSuffix); + + File tmpFile = createTempFileInDir(fileName); + + FileOutputStream fos = new FileOutputStream(tmpFile); + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); + osw.write(text); + osw.close(); + + FileBasedTextDataSourceImpl textDataSource = new FileBasedTextDataSourceImpl(tmpFile, "UTF-8"); + return textDataSource; + } + else + { + return new TextDataSourceImpl(text); + } + } + + /** + * Tells, if it is reasonable to store the text of the given length onto the + * disk. + * + * @param textLength + * The length of the text under question. + * @return Returns true if the text should be stored on the disk. + */ + public static boolean isReasonableToStore(int textLength) + { + return false; +// return textLength >= 10000; + } + + public static PdfDataSource placePdfIntoTempDir(InputStream pdfInput, String fileNameSuffix) throws IOException + { + log.debug("PERF: placing pdf into memory cache"); + + byte [] pdfData = DataSourceHelper.convertInputStreamToByteArray(pdfInput); + PdfDataSource pdfDataSource = new ByteArrayPdfDataSourceImpl(pdfData); + +// File pdfFile = placeInputIntoTempDirFile(pdfInput, fileNameSuffix); +// +// FileBasedPdfDataSourceImpl pdfDataSource = new FileBasedPdfDataSourceImpl(pdfFile, (int) pdfFile.length()); + return pdfDataSource; + } + + public static File placeInputIntoTempDirFile(InputStream input, String fileNameSuffix) throws IOException + { + String fileName = formatFileName(fileNameSuffix); + + File tmpFile = createTempFileInDir(fileName); + + FileOutputStream fos = new FileOutputStream(tmpFile); + + byte[] buffer = new byte[2048]; + int read = -1; + while ((read = input.read(buffer)) > 0) + { + fos.write(buffer, 0, read); + } + fos.close(); + input.close(); + + return tmpFile; + } + + public static File formTempFile(String fileNameSuffix) + { + String fileName = formatFileName(fileNameSuffix); + File tmpFile = getFileInTempDir(fileName); + + return tmpFile; + } + + protected static File getFileInTempDir (String fileName) + { +// File tempDir = new File(new File(SettingsReader.RESOURCES_PATH), "pdfastmp"); + File tempDir = assembleTemporaryDirectoryFile(); + + File tmpFile = new File(tempDir, fileName); + + return tmpFile; + } + + protected static String formatFileName(String fileNameSuffix) + { + // double check so that file name is always correct. + fileNameSuffix = extractFileNameSuffix(fileNameSuffix); + String fileName = "tmp" + formatIndex(runningIndex) + "_" + fileNameSuffix; + runningIndex++; + + return fileName; + } + + protected static String formatIndex(long index) + { + NumberFormat nf = new DecimalFormat("00000000"); + + return nf.format(index); + } + + protected static File createTempFileInDir(String fileName) throws IOException + { + File tmpFile = getFileInTempDir(fileName); + + tmpFile.createNewFile(); + + tmpFile.deleteOnExit(); + + return tmpFile; + } + + public static DataSink createTempDataSink(String fileNameSuffix) throws IOException + { + log.debug("PERF: placing pdf into memory cache"); + + DataSink ds = new ByteArrayDataSink(); + +// String fileName = formatFileName(fileNameSuffix); +// +// File tmpFile = createTempFileInDir(fileName); +// +// FileBasedDataSink ds = new FileBasedDataSink(tmpFile); + + return ds; + } + +// public static void writeDataSinkToHttpResponse(DataSink ds, HttpServletResponse response) throws IOException +// { +// +// response.setContentType(ds.getMimeType()); +// response.setCharacterEncoding(ds.getCharacterEncoding()); +// +// OutputStream os = response.getOutputStream(); +// +// if (ds instanceof FileBasedDataSink) +// { +// FileBasedDataSink fbds = (FileBasedDataSink)ds; +// byte[] buffer = new byte[2048]; +// FileInputStream fis = new FileInputStream(fbds.getFile()); +// int n = -1; +// while ((n = fis.read(buffer)) > 0) +// { +// os.write(buffer, 0, n); +// } +// fis.close(); +// } +// else +// { +// ByteArrayDataSink bads = (ByteArrayDataSink)ds; +// os.write(bads.getByteArray()); +// os.flush(); +// +// } +// +// os.close(); +//} + + /** + * Deletes the underlying file of the FileBased DataSource. + * + *

+ * If the DataSource is not FileBased, nothing is done. + *

+ *

+ * This is usually used by the application to delete temporary files. + *

+ * + * @param dataSource + */ + public static void deleteDataSourceIfFileBased(DataSource dataSource) + { + if (dataSource instanceof FileBased) + { + FileBased fb = (FileBased) dataSource; + log.debug("Deleting temp file " + fb.getFile()); + boolean deleted = fb.getFile().delete(); + log.debug("deleted = " + deleted); + } + } + + public static void deleteDataSinkIfFileBased(DataSink dataSink) + { + if (dataSink instanceof FileBased) + { + FileBased fb = (FileBased) dataSink; + log.debug("Deleting temp file " + fb.getFile()); + boolean deleted = fb.getFile().delete(); + log.debug("deleted = " + deleted); + } + } + + /** + * Given a file (maybe with path), extracts the file name suffix. + * @param file The file and maybe path. + * @return Returns the file name. + */ + public static String extractFileNameSuffix (String file) + { + if (file == null || file.trim().length() == 0) + { + return "nofilename"; + } + File f = new File(file); + return f.getName(); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java new file mode 100644 index 0000000..c222259 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java @@ -0,0 +1,1575 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PdfAS.java,v 1.5 2006/10/31 08:04:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +import at.gv.egiz.pdfas.api.commons.DynamicSignatureProfileImpl; +import at.gv.egiz.pdfas.api.commons.SignatureInformation; +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.api.verify.VerifyParameters; +import at.gv.egiz.pdfas.api.xmldsig.ExtendedSignatureInformation; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.commandline.CommandlineConnectorChooser; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.framework.CorrectorException; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.input.correction.Corrector; +import at.gv.egiz.pdfas.framework.input.correction.CorrectorFactory; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.impl.api.commons.PdfDataSourceAdapter; +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.gv.egiz.pdfas.utils.PDFASUtils; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.FoundBlock; +import at.knowcenter.wag.egov.egiz.framework.FoundKey; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.ObjectExtractor; +import at.knowcenter.wag.egov.egiz.pdf.PDFSignatureCreation; +import at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject; +import at.knowcenter.wag.egov.egiz.pdf.PDFUtilities; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignature; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorChooser; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; +import at.knowcenter.wag.exactparser.ParseDocument; +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.HeaderParseResult; + +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfReader; + +/** + * This class contains the major methods used by both, the commandline and the + * webapp, to perform signation and verification. + * + * @author wprinz + * @author mruhmer + */ +public abstract class PdfAS +{ +//23.11.2010 changed by exthex - added method: verifyExtendedSignatureHolders(List extended_signature_info, String connectorType, boolean returnHashInputData, Date verificationTime) + + /** + * The current version of the pdf-as library. This version string is logged on every invocation + * of the api or the web application. + */ + public static final String PDFAS_VERSION = "3.2"; + + /** + * The key of the strict mode setting. + */ + public static final String STRICT_MODE_KEY = "strict_mode"; + + /** + * The left/right border. + */ + public static final float SIGNATURE_BORDER = 100f; + + /** + * The top/bottom border. + */ + public static final float SIGNATURE_MARGIN = 20f; + + /** + * The Mime Type of a PDF document. + */ + public static final String PDF_MIME_TYPE = "application/pdf"; + + public static final String CORRECT_DOCUMENT_IF_NECESSARY_KEY = "correct_document_if_necessary"; + + /** + * The logger definition. + */ + private static final Log log = LogFactory.getLog(PdfAS.class); + + /** + * Tells, if strict PDF checking the PDF version is enabled. + * + * @return Returns true, if incoming PDFs should be checked strictly. + */ + public static boolean isStrictPdfChecking() + { + try + { + SettingsReader settings = SettingsReader.getInstance(); + String strict_mode = settings.getSetting(STRICT_MODE_KEY, "false"); + if (strict_mode.equals("true")) + { + return true; + } + } + catch (SettingsException e) + { + log.error(e.getMessage(), e); + } + return false; + } + + /** + * Checks the version of the given PDF to be 1.4 or lower. + * + *

+ * This scans the first 1000 bytes of the PDF for the pdf Header. + *

+ * + * @param pdfDataSource + * The PDF. + * @return Returns true, if the given PDF is strict 1.4, false otherwise. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static boolean isPdf14(PdfDataSource pdfDataSource) throws PDFDocumentException + { + try + { + byte[] firstBytes = new byte[1000]; + InputStream is = pdfDataSource.createInputStream(); + is.read(firstBytes); + is.close(); + + HeaderParseResult hpr = PDFUtils.parseHeader(firstBytes, 0); + + if (hpr.major <= 1 && hpr.minor <= 4) + { + return true; + } + return false; + } + catch (Exception e) + { + throw new PDFDocumentException(201, e); + } + } + + /** + * Applies strict version mode on the PDF and throws an exception, if the pdf + * is not 1.4. + * + *

+ * Furthermore (independently of strict mode) the PDF is checked for + * parsability. + *

+ * + * @param pdfDataSource + * The pdf to be checked against strict mode. + * @throws PDFDocumentException + * @throws SettingsException + * @throws CorrectorException + */ + public static PdfDataSource applyStrictMode(PdfDataSource pdfDataSource) throws PDFDocumentException, SettingsException, CorrectorException + { + if (isStrictPdfChecking()) + { + if (!isPdf14(pdfDataSource)) + { + throw new PDFDocumentException(201, "StrictMode: The pdf version is not 1.4 or lower."); + } + } + try + { + byte[] pdf = DataSourceHelper.convertDataSourceToByteArray(pdfDataSource); + ParseDocument.parseDocument(pdf); + } + catch (Exception e) + { + log.debug("Error while parsing Document.", e); + + boolean tryToCorrect = SettingsReader.getInstance().getSetting(CORRECT_DOCUMENT_IF_NECESSARY_KEY, "false").equals("true"); + if (!tryToCorrect) + { + throw new PDFDocumentException(201, e); + } + log.info("Correcting document..."); + Corrector cor = CorrectorFactory.createCorrector(); + PdfDataSource correctedDS = cor.correctDocument(pdfDataSource); + log.info("Correction finished."); + + return correctedDS; + } + + return pdfDataSource; + } + + public static at.gv.egiz.pdfas.api.io.DataSource applyStrictMode (at.gv.egiz.pdfas.api.io.DataSource dataSource) throws PDFDocumentException, SettingsException, CorrectorException + { + if (dataSource.getMimeType().equals("application/pdf")) + { + PdfDataSource pdfDS = new PdfDataSourceAdapter(dataSource); + PdfDataSource correctedDS = applyStrictMode(pdfDS); + if (correctedDS != pdfDS) + { + return new at.gv.egiz.pdfas.impl.api.commons.DataSourceApiAdapter(correctedDS); + } + } + return dataSource; + } + + // TODO: unused method - remove + // /** + // * Verifies the given PDF document. + // * + // * @param pdf + // * The PDF document. + // * @param connector + // * The connector. + // * @return Returns the List of results. + // * @throws PresentableException + // * Forwarded exception. + // */ + // public static List verifyPdf(final byte[] pdf, final String connector) + // throws PresentableException + // { + // VerificationFilter vf = new VerificationFilter(); + // List signature_holders = vf.extractSignaturesFromPdf(pdf); + // if (signature_holders.isEmpty()) + // { + // throw new PDFDocumentException(206); + // } + // + // List results = verifySignatureHolders(signature_holders, connector); + // + // return results; + // } + + // TODO: unused method - remove + // /** + // * Verifies the given text that is supposed to be extracted from a PDF + // * document using text extraction mechanisms. + // * + // * @param text + // * The text to be verified. + // * @param connector + // * The connecor. + // * @return Returns the List of results. + // * @throws PresentableException + // * Forwarded exception. + // */ + // public static List verifyText(final String text, final String connector) + // throws PresentableException + // { + // VerificationFilter vf = new VerificationFilter(); + // List signature_holders = vf.extractSignaturesFromPlainText(text); + // if (signature_holders.isEmpty()) + // { + // throw new PDFDocumentException(206); + // } + // + // List results = verifySignatureHolders(signature_holders, connector); + // + // return results; + // } + + /** + * Extracts all signature blocks from the given raw text using textual mode. + * + * @param raw_text + * The raw text. + * @return Returns a List of all SignatureHolders extracted from the text. + * @throws PDFDocumentException + * F.e. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * @throws NormalizeException + */ + public static List extractSignatureHoldersTextual(String raw_text, boolean old_style) throws PDFDocumentException, SignatureException, SignatureTypesException, NormalizeException + { + List signature_holders = new ArrayList(); + + String text = raw_text; + for (;;) + { + TextualSignatureHolder holder = extractSignatureHolderTextual(text, old_style); + if (holder == null) + { + break; + } + { + log.debug("Found holder: " + holder.getSignatureObject().getSignationType()); + } + signature_holders.add(0, holder); + + text = holder.getSignedText(); + } + + return signature_holders; + } + + /** + * Extracts the last signature holder from the given text. + * + * @param raw_text + * @param old_style + * @return Returns the found singature holder, or null, if none could be + * found. + * @throws SignatureException + * @throws SignatureTypesException + * @throws NormalizeException + */ + public static TextualSignatureHolder extractSignatureHolderTextual(String raw_text, boolean old_style) throws SignatureException, SignatureTypesException, NormalizeException + { + List signatureTypes_ = AbsoluteTextSignature.getSignatureTypesForTextAnalysis(); + + List found_blocks = new ArrayList(); + for (int cur_type = 0; cur_type < signatureTypes_.size(); cur_type++) + { + SignatureTypeDefinition cur_std = (SignatureTypeDefinition) signatureTypes_.get(cur_type); + + List found_keys = findBlockInText(raw_text, cur_std, old_style); + if (found_keys != null) + { + FoundBlock found_block = new FoundBlock(); + found_block.found_keys = found_keys; + found_block.end_index = raw_text.length(); + found_block.std = cur_std; + found_blocks.add(found_block); + } + } + + List last_most_blocks = sortOutEarlyBlocks(found_blocks); + + List minimum_blocks = sortOutLargeBlocks(last_most_blocks); + + if (minimum_blocks.size() > 1) + { + log.debug("There are still " + minimum_blocks.size() + " candidates:"); + + for (int i = 0; i < minimum_blocks.size(); i++) + { + FoundBlock fb = (FoundBlock) minimum_blocks.get(i); + log.debug(" fb: " + fb.std.getType()); + } + + log.debug("... checking for Semantic Equality."); + } + + boolean semantic_equality = checkForSemanticEquality(minimum_blocks); + + if (minimum_blocks.size() > 1) + { + log.debug("... Semantic Equality = " + semantic_equality); + } + + if (!semantic_equality) + { + throw new SignatureException(ErrorCode.NOT_SEMANTICALLY_EQUAL, "The found blocks are not semantically equal."); + } + + if (!minimum_blocks.isEmpty()) + { + FoundBlock actual_block = (FoundBlock) minimum_blocks.get(0); + + String signed_text = raw_text.substring(0, actual_block.getFirstKey().start_index); + + SignatureObject signatureObject_ = new SignatureObject(); + signatureObject_.setSigType(actual_block.std.getType()); + signatureObject_.initByType(); + + int end_index = actual_block.end_index; + for (int i = 0; i < actual_block.found_keys.size(); i++) + { + FoundKey cur_key = (FoundKey) actual_block.found_keys.get(i); + int start_index = cur_key.getStartIndex() + cur_key.caption.length(); + + String value = raw_text.substring(start_index, end_index); + + signatureObject_.setSigValueCaption(cur_key.getKey(), value, cur_key.caption); + + end_index = cur_key.getStartIndex(); + } + + // this normalization is required to get rid of possible trailing + // newlines. + String normalized_text = normalizeText(signed_text); + TextualSignatureHolder holder = new TextualSignatureHolder(normalized_text, signatureObject_); + return holder; + } + + return null; + } + + /** + * Tries to find a block of the given type in the text. + * + * @param text + * The text. + * @param sig_type_def + * The type of the block. + * @param old_style + * Tells, if the block is old style (SIG_KZ will be ignored), or if + * it is a new block. + * @return Returns a List of the found keys of the block, or null, if the + * block could not be found. + */ + public static List findBlockInText(String text, SignatureTypeDefinition sig_type_def, boolean old_style) + { + Vector keys = sig_type_def.getRevertSortedKeys(); + Vector captions = sig_type_def.getRevertSortedCaptions(); + + int last_index = text.length(); + List found_keys = new ArrayList(); + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String key = (String) keys.get(key_idx); + // logger_.debug("Key="+key); + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + // If separating the old style way - skip The "Kennzeichnung" + // key, because it wasn't present in old profiles. + continue; + } + + String caption = (String) captions.get(key_idx); + + // int found_index = text.lastIndexOf(caption); + // we're searching for captions that start at the beginning of the line. + int found_index = text.lastIndexOf("\n" + caption) + 1;// text.lastIndexOf("\n" + // + caption) + 1; + // // the +1 + // text.lastIndexOf(caption) + // + 1; // + // compensates the + // \n + if (found_index == 0) + { + // try without /n + found_index = text.lastIndexOf(caption); + + // fix #331 here ?? + } + log.debug("found key:" + caption + " at index:" + found_index); + if (key.equals(SignatureTypes.SIG_ID)) + { + if (found_index < 0 || found_index >= last_index) + { + // not found, SIG_ID is not required + continue; + } + FoundKey fk = new FoundKey(key, caption, found_index); + found_keys.add(fk); + } + else + { + if (found_index < 0 || found_index >= last_index) + { + // one key is not found - the profile doesn't match. + return null; + } + + FoundKey fk = new FoundKey(key, caption, found_index); + found_keys.add(fk); + last_index = found_index; + } + } + + sortFoundKeysDescendingly(found_keys); + + boolean matched = checkThatOrderIsCorrectAndCorrectFoundKeys(found_keys, keys, old_style); + // boolean found_required = checkFoundRequiredKeys(found_keys, old_style); + // logger_.debug("KKKKKKKKKKmatched="+matched); + if (matched) + { + return found_keys; + } + return null; + } + + /** + * Sorts the FoundKeys List descendingly according to the start indices of the + * found keys (the first found key in the list will have the highest start + * index, the second one the second highest and so forth). + * + * @param found_keys + * The List of FoundKey objects to be sorted. + */ + public static void sortFoundKeysDescendingly(List found_keys) + { + // sort the found_keys according to their start pos reversely. + + Collections.sort(found_keys, new Comparator() { + public int compare(Object arg0, Object arg1) + { + FoundKey fk0 = (FoundKey) arg0; + FoundKey fk1 = (FoundKey) arg1; + // sort reversely! + return fk1.start_index - fk0.start_index; + } + }); + } + + /** + * Sorts the FoundKeys List ascendingly according to the start indices of the + * found keys (the first found key in the list will have the lowest start + * index, the second one the second lowest and so forth). + * + * @param found_keys + * The List of FoundKey objects to be sorted. + */ + public static void sortFoundKeysAscendingly(List found_keys) + { + // sort the found_keys according to their start pos. + + Collections.sort(found_keys, new Comparator() { + public int compare(Object arg0, Object arg1) + { + FoundKey fk0 = (FoundKey) arg0; + FoundKey fk1 = (FoundKey) arg1; + return fk0.start_index - fk1.start_index; + } + }); + } + + /** + * Checks that the found keys are in correct order regarding SIG_ID as + * optional key. + * + *

+ * If the SIG_ID key is misplaced, it will be removed from the found keys + * list. + *

+ * + * @param found_keys + * The found keys ordered descendingly to their start position + * @param profile_keys + * The profile keys. + * @param old_style + * Tells, if SIG_KZ should be ignored, or not. + * @return Returns true, if the keys are correct. + */ + public static boolean checkThatOrderIsCorrectAndCorrectFoundKeys(List found_keys, List profile_keys, boolean old_style) + { + + int found_index = 0; + for (int profile_index = 0; profile_index < profile_keys.size(); profile_index++) + { + String key = (String) profile_keys.get(profile_index); + + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + continue; + } + + FoundKey found_key = (FoundKey) found_keys.get(found_index); + + boolean match = key.equals(found_key.getKey()); + if (match) + { + found_index++; + continue; + } + + if (key.equals(SignatureTypes.SIG_ID)) + { + continue; + } + + // doesn't match + return false; + } + + // remove all fields above the found_index - they are not correctly matched + // indices (should be only the ID + int size = found_keys.size(); + for (int i = found_index; i < size; i++) + { + // this removes all (size - found_index) objects above found_index + found_keys.remove(found_index); + } + + return true; + } + + /** + * Sorts out early blocks and leaves only those at the bottom of the text. + * + * @param found_blocks + * The found blocks. + * @return Returns a list of the last blocks. + */ + public static List sortOutEarlyBlocks(List found_blocks) + { + int last_most_index = Integer.MIN_VALUE; + + List last_most_blocks = new ArrayList(); + for (int block_index = 0; block_index < found_blocks.size(); block_index++) + { + FoundBlock block = (FoundBlock) found_blocks.get(block_index); + + int this_last_index = block.getLastKey().start_index; + if (this_last_index < last_most_index) + { + // this block cannot be the last most block. + continue; + } + if (this_last_index == last_most_index) + { + last_most_blocks.add(block); + continue; + } + if (this_last_index > last_most_index) + { + last_most_blocks = new ArrayList(); + last_most_blocks.add(block); + last_most_index = this_last_index; + } + } + + return last_most_blocks; + } + + /** + * Sorts out large blocks. + * + * @param found_blocks + * The found blocks. + * @return Returns a list of the smallest blocks. + */ + public static List sortOutLargeBlocks(List found_blocks) + { + int last_min_size = Integer.MAX_VALUE; + + List min_size_blocks = new ArrayList(); + for (int block_index = 0; block_index < found_blocks.size(); block_index++) + { + FoundBlock block = (FoundBlock) found_blocks.get(block_index); + + int size = block.getSize(); + + if (size > last_min_size) + { + // this block is larger + continue; + } + if (size == last_min_size) + { + min_size_blocks.add(block); + continue; + } + if (size < last_min_size) + { + min_size_blocks = new ArrayList(); + min_size_blocks.add(block); + last_min_size = size; + } + } + + return min_size_blocks; + } + + /** + * Checks the list of blocks for semantic equality. + * + * @param found_blocks + * The list of found blocks. + * @return Returns true if all blocks are semantically equal. + */ + public static boolean checkForSemanticEquality(List found_blocks) + { + if (found_blocks.size() <= 1) + { + return true; + } + + for (int block_index = 0; block_index < found_blocks.size() - 1; block_index++) + { + FoundBlock first_block = (FoundBlock) found_blocks.get(block_index); + FoundBlock second_block = (FoundBlock) found_blocks.get(block_index + 1); + + if (!first_block.isSemanticallyEqual(second_block)) + { + return false; + } + } + + return true; + } + + public static int getIndexOfFoundKey(List found_keys, String key) + { + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey fk = (FoundKey) found_keys.get(i); + if (fk.getKey().equals(key)) + { + return i; + } + } + return -1; + } + + public static boolean containsFoundKey(List found_keys, String key) + { + return getIndexOfFoundKey(found_keys, key) >= 0; + } + + /** + * Checks the found keys for the required keys regarding the old style. + * + * @param found_keys + * The found keys. + * @param old_style + * Flag that tells, if KZ is not required. + * @return Returns true, if all required keys were found. + */ + public static boolean checkFoundRequiredKeys(List found_keys, boolean old_style) + { + if (!containsFoundKey(found_keys, SignatureTypes.SIG_DATE)) + { + return false; + } + if (!containsFoundKey(found_keys, SignatureTypes.SIG_ISSUER)) + { + return false; + } + if (!containsFoundKey(found_keys, SignatureTypes.SIG_NUMBER)) + { + return false; + } + if (!containsFoundKey(found_keys, SignatureTypes.SIG_VALUE)) + { + return false; + } + if (!old_style && !containsFoundKey(found_keys, SignatureTypes.SIG_KZ)) + { + return false; + } + return true; + } + + public static List verifySignatureHolders(List signature_holders, String connectorType, boolean returnHashInputData, Date verificationTime) throws PDFDocumentException, NormalizeException, SignatureException, ConnectorException, ConnectorFactoryException + { + List results = new ArrayList(); + for (int i = 0; i < signature_holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) signature_holders.get(i); + + // logger_.debug(); + // logger_.debug(); + // logger_.debug("Verifying Holder " + i + "..."); + // logger_.debug("holder[" + i + "].signed_text = " + + // holder.signed_text); + // logger_.debug("holder[" + i + "].sig_obj = "); + // logger_.debug("holder[" + i + "].type = " + + // (holder.signature_object.isTextual() ? "textual" : "binary")); + // logger_.debug(holder.signature_object.toString()); + + SignatureResponse result = verify(holder, connectorType, returnHashInputData, verificationTime, null); + results.add(result); + + // logger_.debug(); + // logger_.debug("check[" + i + "].cert = " + + // result.getCertificateCheckInfo()); + // logger_.debug("check[" + i + "].sig = " + + // result.getSignatureCheckInfo().trim()); + // logger_.debug("check[" + i + "].manifest = " + + // result.getSignatureManifestCheckInfo()); + // logger_.debug(); + } + return results; + } + + /** + * Verify a list of signatures + * + * @param extended_signature_info a list of {@link ExtendedSignatureInformation} to be verified + * @param connectorType the connector to use for verification + * @param returnHashInputData + * @param verificationTime + * @param verifySignatureAtIndex only verify the signature at the given index in the extended_signature_info list. A value < 0 means to verify all signatures in the list. + * @return a list of {@link SignatureResponse}s + * @throws PDFDocumentException + * @throws NormalizeException + * @throws SignatureException + * @throws ConnectorException + * @throws ConnectorFactoryException + */ + public static List verifyExtendedSignatureHolders(List extended_signature_info, String connectorType, boolean returnHashInputData, Date verificationTime, int verifySignatureAtIndex) throws PDFDocumentException, NormalizeException, SignatureException, ConnectorException, ConnectorFactoryException + { + List results = new ArrayList(); + for (int i = 0; i < extended_signature_info.size(); i++) + { + if (verifySignatureAtIndex < 0 || verifySignatureAtIndex == i) + { + ExtendedSignatureInformation sigInfo = (ExtendedSignatureInformation) extended_signature_info.get(i); + SignatureInformation si = sigInfo.getSignatureInformation(); + SignatureHolder holder = (SignatureHolder) si.getInternalSignatureInformation(); + + SignatureResponse result = verify(holder, connectorType, returnHashInputData, verificationTime, sigInfo.getXmlDsigData()); + results.add(result); + } + } + return results; + } + + /** + * Verifies a SignatureHolder using the given connector. + * + * @param signature_holder + * The SignatureHolder to be verified. + * @param connector + * The connector. + * @return Returns the SignatureResponse object. + * @throws NormalizeException + * F.e. + * @throws PDFDocumentException + * F.e. + * @throws SignatureException + * F.e. + * @throws ConnectorException + * @throws ConnectorFactoryException + */ + public static SignatureResponse verify(SignatureHolder signature_holder, String connectorType, boolean returnHashInputData, Date verificationTime, XMLDsigData dsig) throws NormalizeException, PDFDocumentException, SignatureException, ConnectorException, ConnectorFactoryException + { + // String text_to_be_verified = signature_holder.getSignedText(); + // logger_.debug("verify text_to_be_verified"+text_to_be_verified); + SignatureObject so_to_be_verified = signature_holder.getSignatureObject(); + + // if (text_to_be_verified == null) + // { + // throw new SignatureException(311, "Document can not be verified because + // the text to be verified is either null."); + // } + // if (text_to_be_verified.length() <= 0) + // { + // throw new SignatureException(311, "Document can not be verified because + // the length of the text to be verified is 0. (length = " + + // text_to_be_verified.length() + ")"); + // } + + if (so_to_be_verified == null) + { + throw new SignatureException(312, "Document can not be verified because no signature object are set."); + } + + // fixed by tknall + if (so_to_be_verified.getX509Cert() == null) + { + throw new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "Document certificate is not defined."); + } + + SignSignatureObject so = SignatureObjectHelper.convertSignatureObjectToSignSignatureObject(so_to_be_verified); + SignatureData sd = convertSignatureHolderToSignatureData(signature_holder); + + String profile = so_to_be_verified.getSignatureTypeDefinition().getType(); +// Connector c = ConnectorChooser.chooseCommandlineConnectorForVerify(connector, so_to_be_verified.getKZ(), so.id, profile); + String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForVerify(connectorType, so_to_be_verified.getKZ(), so.id, profile); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + cp.setReturnHashInputData(returnHashInputData); + cp.setVerificationTime(verificationTime); + Connector c = at.gv.egiz.pdfas.framework.ConnectorFactory.createConnector(connectorId, cp); + + return executeVerify(dsig, so, sd, c); + } + + private static SignatureResponse executeVerify(XMLDsigData dsig, SignSignatureObject so, + SignatureData sd, Connector c) throws ConnectorException { + SignatureResponse res = null; + try { + return c.doVerify(sd, so, dsig); + } catch (ConnectorException e) { + if (VerifyParameters.isSuppressVerifyExceptions()) { + res = new SignatureResponse(); + res.setVerificationImpossibleEx(e); + } else { + throw e; + } + } + return res; + } + + public static SignatureResponse verifyWeb(SignatureHolder signature_holder, String connector, String loc_ref) throws NormalizeException, PDFDocumentException, SignatureException, ConnectorException + { + // String text_to_be_verified = signature_holder.getSignedText(); + // logger_.debug("verify text_to_be_verified"+text_to_be_verified); + SignatureObject so_to_be_verified = signature_holder.getSignatureObject(); + + // if (text_to_be_verified == null) + // { + // throw new SignatureException(311, "Document can not be verified because + // the text to be verified is either null."); + // } + // if (text_to_be_verified.length() <= 0) + // { + // throw new SignatureException(311, "Document can not be verified because + // the length of the text to be verified is 0. (length = " + + // text_to_be_verified.length() + ")"); + // } + + if (so_to_be_verified == null) + { + throw new SignatureException(312, "Document can not be verified because no signature object are set."); + } + + // added by tknall + if (so_to_be_verified.getX509Cert() == null) + { + throw new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "Document certificate is not defined."); + } + + + SignSignatureObject so = SignatureObjectHelper.convertSignatureObjectToSignSignatureObject(so_to_be_verified); + SignatureData sd = convertSignatureHolderToSignatureData(signature_holder); + + String profile = so_to_be_verified.getSignatureTypeDefinition().getType(); + Connector c = ConnectorChooser.chooseWebConnectorForVerify(connector, so_to_be_verified.getKZ(), so.id, profile, loc_ref); + + return executeVerify(null, so, sd, c); + + } + + public static SignatureData convertSignatureHolderToSignatureData(SignatureHolder signature_holder) + { + SignatureData sd = null; + if (signature_holder instanceof BinarySignatureHolder) + { + BinarySignatureHolder bsh = (BinarySignatureHolder) signature_holder; + sd = new SignatureDataImpl(bsh.getDataSource(), "application/pdf"); + } + else + { + TextualSignatureHolder tsh = (TextualSignatureHolder)signature_holder; + sd = new SignatureDataImpl(tsh.getDataSource(), "text/plain", "UTF-8"); + } + return sd; + } + + /** + * Signs the given text with the provided connector using the given signature + * type. + * + * @param data_to_sign + * The data to be signed. + * @param signature_type + * The type of the signature. + * @param connector + * The connector. + * @return Returns the corresponding SignatureObject. + * @throws SignatureException + * F.e. + * @throws PDFDocumentException + * F.e. + * @throws ConnectorException + */ + public static SignSignatureObject sign(final SignatureData data_to_sign, final Connector connector, final TimeStamper timeStamper) throws SignatureException, PDFDocumentException, ConnectorException + { +// if (data_to_sign == null || data_to_sign.getData() == null) +// { +// throw new SignatureException(301, "Signature can not be produced. Data is null."); //$NON-NLS-1$ +// } + // if (data_to_sign.getData().length <= 0) + // { + // throw new SignatureException(301, "Signature can not be produced. Data is + // empty. (length = " + data_to_sign.getData().length + ")"); //$NON-NLS-1$ + // //$NON-NLS-2$ + // } + + SignSignatureObject signed_signature_object = connector.doSign(data_to_sign); + + // call timestamper if available + if (timeStamper != null) { + log.debug("execute timestamping with stamper: " + timeStamper.getClass()); + signed_signature_object.sigTimeStamp = timeStamper.applyTimeStamp(signed_signature_object.getSignatureValue()); + } + + return signed_signature_object; + } + + /** + * Helper method that creates a SignatureObject and initializes it with the + * given type. + * + * @param signature_type + * The type. + * @return Returns the created SignatureObject. + * @throws SignatureException + * f.e. + * @throws SignatureTypesException + * f.e. + */ + public static SignatureObject createSignatureObjectFromType(final String signature_type) throws SignatureException, SignatureTypesException + { + SignatureObject sig_obj = new SignatureObject(); + sig_obj.setSigType(signature_type); + sig_obj.initByType(); + + return sig_obj; + } + +// /** +// * @deprecated moved to Main.processSign use signCommandline instead +// * @param pdfDataSource +// * @param dataSink +// * @param signatorId +// * @param connectorType +// * @param profile +// * @param pos +// * @throws PresentableException +// */ +// public static void sign(PdfDataSource pdfDataSource, DataSink dataSink, PdfASID signatorId, final String connectorType, final String profile, TablePos pos) throws PresentableException +// { +//// //Signator signator = SignatorFactory.createSignator(algorithm); +//// at.gv.egiz.pdfas.framework.signator.Signator signator = at.gv.egiz.pdfas.framework.SignatorFactory.createSignator(algorithm); +//// +//// //IncrementalUpdateInformation iui = signator.prepareSign(pdfDataSource, signature_type, pos, ConnectorFactory.needsSIG_ID(connector)); +//// SignatorInformation si = signator.prepareSign(pdfDataSource, signature_type, pos, ConnectorFactory.needsSIG_ID(connector)); +// +// // Connector c = ConnectorChooser.chooseCommandlineConnectorForSign(connector, signature_type); +// +//// SignSignatureObject sso = sign(si.getSignatureData(), c); +//// +//// si.setSignSignatureObject(sso); +//// +//// signator.finishSign(si, dataSink); +// +// String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForSign(connectorType); +// +// signCommandline(pdfDataSource, dataSink, signatorId, connectorId, profile, pos); +// } + + public static SignatorInformation signCommandline(PdfDataSource pdfDataSource, DataSink dataSink, PdfASID signatorId, String connectorId, final String profile, final String signatureKeyIdentifier, TablePos pos, TimeStamper timeStamper, Properties overrideProps) throws PresentableException + { + try { + at.gv.egiz.pdfas.framework.signator.Signator signator = at.gv.egiz.pdfas.framework.SignatorFactory.createSignator(signatorId); + if (overrideProps != null) { + OverridePropertyHolder.setOverrideProps(overrideProps); + } + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + cp.setSignatureKeyIdentifier(signatureKeyIdentifier); + Connector c = at.gv.egiz.pdfas.framework.ConnectorFactory.createConnector(connectorId, cp); + + // SignatorInformation si = signator.prepareSign(pdfDataSource, profile, pos, ConnectorFactory.needsSIG_ID(connector)); + SignatorInformation si = signator.prepareSign(pdfDataSource, profile, pos, timeStamper); + + SignSignatureObject sso = sign(si.getSignatureData(), c, timeStamper); + + si.setSignSignatureObject(sso); + + signator.finishSign(si, dataSink); + + return si; + } finally { + OverridePropertyHolder.removeProperties(); + DynamicSignatureProfileImpl.disposeLocalProfile(); + } + } + + public static SignatorInformation signCommandline(PdfDataSource pdfDataSource, DataSink dataSink, PdfASID signatorId, String connectorId, final String profile, TablePos pos) throws PresentableException { + return signCommandline(pdfDataSource, dataSink, signatorId, connectorId, profile, null, pos, null, null); + } + + /** + * Extracts and normalizes the text from the pdf. + * + * @param pdf + * The PDF document. + * @return Returns the text String. + * @throws PresentableException + * F.e. + */ +// public static String extractNormalizedTextTextual(final byte[] pdf) throws PresentableException +// { +// // ByteArrayInputStream bais = new ByteArrayInputStream(pdf); +// // String raw_document_text = TextualSignature.extractTextTextual(bais); +// // +// // String document_text = normalizeText(raw_document_text); +// +// return extractNormalizedTextTextual(pdf, pdf.length); +// } + + + /** + * + * @param pdfDs + * @return List of {@link NonTextObjectInfo} + */ + public static List extractNonTextualObjects(PdfDataSource pdfDs) { + return ObjectExtractor.extractNonTextInfo(pdfDs); + } + + + /** + * @deprecated + * Use version with explicit encoding {@link PdfAS#extractNormalizedTextTextual(PdfDataSource, String)}. + * This one uses cp1252. + * + * @param pdfDataSource + * @return + * @throws PresentableException + */ + public static String extractNormalizedTextTextual(PdfDataSource pdfDataSource) throws PresentableException { + return extractNormalizedTextTextual(pdfDataSource, "cp1252"); + + } + + public static String extractNormalizedTextTextual(PdfDataSource pdfDataSource, String encoding) throws PresentableException + { + String raw_document_text = TextualSignature.extractTextTextual(pdfDataSource, encoding); + String document_text = normalizeText(raw_document_text); + return document_text; + } + /** + @deprecated + */ + public static String extractNormalizedTextTextual(byte [] pdf, int length) throws PresentableException + { + ByteArrayPdfDataSourceImpl pdfDataSource = new ByteArrayPdfDataSourceImpl(pdf, length); + String raw_document_text = TextualSignature.extractTextTextual(pdfDataSource, "cp1252"); + String document_text = normalizeText(raw_document_text); + return document_text; + } + +// public static String extractNormalizedTextTextual(InputStream pdfInputStream, int length) throws PresentableException +// { +// DelimitedInputStream dis = new DelimitedInputStream(pdfInputStream, length); +// String raw_document_text = TextualSignature.extractTextTextual(dis); +// String document_text = normalizeText(raw_document_text); +// return document_text; +// } +// /** +// * Extracts and normalizes the text from the pdf. +// * +// * @param pdf +// * The PDF document. +// * @param length +// * The length of the PDF document. The decument is considered to be +// * that long even if the byte array is longer. +// * @return Returns the text String. +// * @throws PresentableException +// * F.e. +// */ +// public static String extractNormalizedTextTextual(final byte[] pdf, final int length) throws PresentableException +// { +// ByteArrayInputStream bais = new ByteArrayInputStream(pdf, 0, length); +// String raw_document_text = TextualSignature.extractTextTextual(bais); +// // logger_.info("extractNormalizedTextTextual +// // raw_document_text="+raw_document_text); +// String document_text = normalizeText(raw_document_text); +// // logger_.info("extractNormalizedTextTextual document_text +// // ="+document_text); +// return document_text; +// } + + /** + * Normalizes the given text. + * + * @param text + * The text to be normalized. + * @return Returns the normalized text. + * @throws NormalizeException + * F.e. + */ + public static String normalizeText(final String text) throws NormalizeException + { + Normalizer normalizer = new Normalizer(); + String normalized_text = normalizer.normalize(text, false); + // fix #331 ?? + //normalized_text = normalized_text.replaceAll("\n", ""); + return normalized_text; + } + + /** + * Creates the iText PDFPTable from a given SignatureObject. + * + * @param signature_object + * The SignatureObject. + * @return Returns the created PDFPTable. + * @throws PDFDocumentException + * F.e. + * @throws SignatureException + * F.e. + */ + public static PdfPTable createPdfPTableFromSignatureObject(final SignatureObject signature_object) throws PDFDocumentException, SignatureException + { + PDFSignatureCreation creation = new PDFSignatureCreation(signature_object); + PDFSignatureObject pdf_sig_obj = creation.getPDFSignatureObject(); + PdfPTable pdf_table = (PdfPTable) pdf_sig_obj.getSignatureObject(); + + return pdf_table; + } + + /** + * Evalutates absolute positioning and prepares the PositioningInstruction for + * placing the table. + * + * @param pos + * The absolute positioning parameter. If null it is sought in the + * profile definition. + * @param signature_type + * The profile definition of the table to be written. + * @param pdf + * The pdf. + * @param pdf_table + * The pdf table to be written. + * @return Returns the PositioningInformation. + * @throws PDFDocumentException + * F.e. + * @throws SettingsException + * F.e. + */ + public static PositioningInstruction determineTablePositioning(TablePos pos, String signature_type, PdfDataSource pdfDataSource, PdfPTable pdf_table) throws PDFDocumentException, SettingsException + { + if (pos == null) + { + String pos_string = SettingsReader.getInstance().getSetting(SignatureTypes.SIG_OBJ + signature_type + ".pos", null); + if (pos_string != null) + { + pos = PdfAS.parsePositionFromPosString(pos_string); + } + } + if (pos == null) + { + // The default algorithm. x,y,w =auto ,p=lastpage, f:ignored because + // y:auto + pos = new TablePos(); + } + // System.out.println("Tablepos="+pos); + return PdfAS.adjustSignatureTableandCalculatePosition(pdfDataSource, pdf_table, pos); + } + + /** + * Sets the width of the table according to the layout of the document and + * calculates the y position where the PDFPTable should be placed. + * + * @param pdf + * The PDF document. + * @param pdf_table + * The PDFPTable to be placed. + * @return Returns the position where the PDFPTable should be placed. + * @throws PDFDocumentException + * F.e. + */ + public static PositioningInstruction adjustSignatureTableandCalculatePosition(final PdfDataSource pdfDataSource, PdfPTable pdf_table, TablePos pos) throws PDFDocumentException + { + // first check pageinstruction in TablePos-object + // new,auto,absolut + PdfReader reader = readInPdfDocument(pdfDataSource); + PDFASUtils.checkReaderPermissions(reader); + // get pages of currentdocument + int doc_pages = reader.getNumberOfPages(); + int page = doc_pages; + boolean make_new_page = pos.isNewPage(); + if (!(pos.isNewPage() || pos.isPauto())) + { + // we should posit signaturtable on this page + + page = pos.getPage(); + // System.out.println("XXXXPAGE="+page+" doc_pages="+doc_pages); + if (page > doc_pages) + { + make_new_page = true; + page = doc_pages; + // throw new PDFDocumentException(227, "Page number is to big(=" + page+ + // ") cannot be parsed."); + } + } + + // getPagedimensions + Rectangle psize = reader.getPageSizeWithRotation(page); + int page_rotation = reader.getPageRotation(page); + +// [tknall] for iText 1.x.x: +// float page_width = psize.width(); +// float page_height = psize.height(); + +// [tknall] for iText 2.x.x: +// float page_width = psize.getWidth(); +// float page_height = psize.getHeight(); + + float page_width = psize.getWidth(); + float page_height = psize.getHeight(); + + // now we can calculate x-position + float pre_pos_x = SIGNATURE_BORDER / 2; + if (!pos.isXauto()) + { + // we do have absolute x + pre_pos_x = pos.getPosX(); + } + // calculate width + // center + float pre_width = page_width - pre_pos_x - pre_pos_x; + if (!pos.isWauto()) + { + // we do have absolute width + pre_width = pos.getWidth(); + if (pos.isXauto()) + { // center x + pre_pos_x = (page_width - pre_width) / 2; + } + } + final float pos_x = pre_pos_x; + final float width = pre_width; + // Signatur table dimensions are complete + pdf_table.setTotalWidth(width); + pdf_table.setLockedWidth(true); + final float table_height = pdf_table.getTotalHeight(); + // now check pos_y + float pos_y = pos.getPosY(); + if (!pos.isYauto()) + { + // we do have y-position too --> all parameters but page ok + if (make_new_page) + { + page++; + } + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + // pos_y is auto + if (make_new_page) + { + // ignore footer in new page + page++; + pos_y = page_height - SIGNATURE_BORDER / 2; + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + // up to here no checks have to be made if Tablesize and Pagesize are fit + // Now we have to getfreespace in page and reguard footerline + float footer_line = pos.getFooterLine(); + float pre_page_length = PDFUtilities.calculatePageLength(pdfDataSource, page - 1, page_height - footer_line, page_rotation); + if (pre_page_length == Float.NEGATIVE_INFINITY) + { + // we do have an empty page or nothing in area above footerline + pre_page_length = page_height; + // no text --> SIGNATURE_BORDER + pos_y = page_height - SIGNATURE_BORDER / 2; + if (pos_y - footer_line <= table_height) + { + make_new_page = true; + if (!pos.isPauto()) + { + // we have to correct pagenumber + page = reader.getNumberOfPages(); + } + page++; + // no text --> SIGNATURE_BORDER + pos_y = page_height - SIGNATURE_BORDER / 2; + } + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + final float page_length = pre_page_length; + // we do have text take SIGNATURE_MARGIN + pos_y = page_height - page_length - SIGNATURE_MARGIN; + if (pos_y - footer_line <= table_height) + { + make_new_page = true; + if (!pos.isPauto()) + { + // we have to correct pagenumber in case of absolute page and not enough + // space + page = reader.getNumberOfPages(); + } + page++; + // no text --> SIGNATURE_BORDER + pos_y = page_height - SIGNATURE_BORDER / 2; + } + return new PositioningInstruction(make_new_page, page, pos_x, pos_y); + } + +// /** +// * Sets the width of the table according to the layout of the document and +// * calculates the y position where the PDFPTable should be placed. +// * +// * @deprecated +// * @param pdf +// * The PDF document. +// * @param pdf_table +// * The PDFPTable to be placed. +// * @return Returns the position where the PDFPTable should be placed. +// * @throws PDFDocumentException +// * F.e. +// */ +// public static PositioningInstruction adjustTableAndCalculatePosition(final byte[] pdf, PdfPTable pdf_table) throws PDFDocumentException +// { +// boolean make_new_page = false; +// +// PdfReader reader = readInPdfDocument(pdf); +// +// int page = reader.getNumberOfPages(); +// Rectangle psize = reader.getPageSizeWithRotation(page); +// float page_width = psize.width(); +// float page_height = psize.height(); +// +// final float width = page_width - SIGNATURE_BORDER; +// pdf_table.setTotalWidth(width); +// pdf_table.setLockedWidth(true); +// +// final float pos_x = SIGNATURE_BORDER / 2; +// +// final float table_height = pdf_table.getTotalHeight(); +// final float page_length = PDFUtilities.calculateLastPageLength(pdf, page_height); +// float pos_y = page_height - page_length - SIGNATURE_MARGIN; +// +// if (pos_y <= table_height) +// { +// make_new_page = true; +// page++; +// +// pos_y = page_height - SIGNATURE_BORDER / 2; +// } +// +// return new PositioningInstruction(make_new_page, page, pos_x, pos_y); +// } + +// /** +// * Sets the width of the table according to the layout of the document and +// * calculates the y position where the PDFPTable should be placed. +// * +// *

+// * This algorithm tries to position the table between the end of the text and +// * the footer line. +// *

+// * +// * @deprecated +// * @param pdf +// * The PDF document. +// * @param pdf_table +// * The PDFPTable to be placed. +// * @return Returns the position where the PDFPTable should be placed. +// * @throws PDFDocumentException +// * F.e. +// */ +// public static PositioningInstruction adjustTableAndCalculatePositionRegardingFooter(final byte[] pdf, PdfPTable pdf_table, float footer_line) throws PDFDocumentException +// { +// boolean make_new_page = false; +// +// PdfReader reader = readInPdfDocument(pdf); +// +// int page = reader.getNumberOfPages(); +// Rectangle psize = reader.getPageSizeWithRotation(page); +// float page_width = psize.width(); +// float page_height = psize.height(); +// +// final float width = page_width - SIGNATURE_BORDER; +// pdf_table.setTotalWidth(width); +// pdf_table.setLockedWidth(true); +// +// final float pos_x = SIGNATURE_BORDER / 2; +// +// final float table_height = pdf_table.getTotalHeight(); +// +// final float page_length = PDFUtilities.calculateLastPageLength(pdf, page_height - footer_line); +// float pos_y = page_height - page_length - SIGNATURE_MARGIN; +// +// if (pos_y - footer_line <= table_height) +// { +// make_new_page = true; +// page++; +// +// pos_y = page_height - SIGNATURE_BORDER / 2; +// } +// +// return new PositioningInstruction(make_new_page, page, pos_x, pos_y); +// } + + /** + * Creates an iText Reader that parses the document. + *

+ * This is a convenience function for wrapping the Reader's exceptions into + * PDFDocumentException. + *

+ * + * @param pdf + * The PDF document. + * @return Returns the created PdfReader. + * @throws PDFDocumentException + * F.e. + */ + public static PdfReader readInPdfDocument(final PdfDataSource pdfDataSource) throws PDFDocumentException + { + try + { + //InputStream is = pdfDataSource.createInputStream(); + // PERF: byte array instead of stream + byte [] pdf_data = pdfDataSource.getAsByteArray(); + PdfReader reader = new PdfReader(pdf_data); + //is.close(); + return reader; + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + } + + /** + * Parses the TablePos object from a given String with the appropriate format. + * + * @param pos_string + * The pos string. e.g. x:40.0;y:auto;w:auto;p:1;f:300.0 + * @return Returns the parsed TablePos object. + * @throws PDFDocumentException + * Thrown, if the String doesn't have the proper format. + */ + public static TablePos parsePositionFromPosString(String pos_string) throws PDFDocumentException + { + TablePos pos = new TablePos(pos_string); + return pos; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java new file mode 100644 index 0000000..ef9cb87 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfASID.java @@ -0,0 +1,222 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PdfASID.java,v 1.1 2006/08/25 17:04:16 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * This class encapsulates the Pdf-AS ID ("Kennzeichnung") urn. + * + * @author wprinz + */ +public class PdfASID implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 4776635173830445739L; + + /** + * The urn word that leads in the identifier. + */ + protected static final String URN = "urn"; + + /** + * The namespace of the urn. + */ + protected static final String NAMESPACE = "pdfsigfilter"; + + /** + * The separator between urn blocks. + */ + protected static final String SPLIT_STRING = ":"; + + /** + * The vendor. + */ + protected String vendor = null; + + /** + * The algorithm type. + */ + protected String type = null; + + /** + * The version of the algorithm. + */ + protected String version = null; + + /** + * Constructor that fills in the parameters directly. + * + * @param vendor + * @param type + * @param version + */ + public PdfASID(String vendor, String type, String version) + { + set(vendor, type, version); + } + + /** + * Parses the given id String and throws an Exception if it is not valid. + * + * @param id + * The id String to be parsed. + */ + public PdfASID(String id) throws InvalidIDException + { + String[] tokens = id.split(SPLIT_STRING); + + if (tokens.length != 5) + { + throw new InvalidIDException(ErrorCode.UNABLE_TO_PARSE_ID, "The method doesn't have enough tokens (" + id + ")"); + } + + if (!tokens[0].equals(URN)) + { + throw new InvalidIDException(ErrorCode.UNABLE_TO_PARSE_ID, "The method must start with " + URN + " (" + id + ")"); + } + + if (!tokens[1].equals(NAMESPACE)) + { + throw new InvalidIDException(ErrorCode.UNABLE_TO_PARSE_ID, "The namespace of the method must be " + NAMESPACE + " (" + id + ")"); + } + + set(tokens[2], tokens[3], tokens[4]); + } + + /** + * Copy Constructor. + * + * @param other + * The other PdfASID to copy the data from. + */ + public PdfASID(final PdfASID other) + { + set(other.vendor, other.type, other.version); + } + + /** + * Auxiliary constructor. + * + * @param vendor + * The vendor. + * @param type + * The type. + * @param version + * The version. + */ + private void set(String vendor, String type, String version) + { + this.vendor = vendor; + this.type = type; + this.version = version; + } + + /** + * Returns the type. + * + * @return Returns the type. + */ + public String getType() + { + return this.type; + } + + /** + * Returns the vendor. + * + * @return Returns the vendor. + */ + public String getVendor() + { + return this.vendor; + } + + /** + * Returns the version. + * + * @return Returns the version. + */ + public String getVersion() + { + return this.version; + } + + + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + //@override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof PdfASID)) + { + return false; + } + + PdfASID other = (PdfASID) obj; + + return this.toString().equals(other.toString()); + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return toString().hashCode(); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return URN + SPLIT_STRING + NAMESPACE + SPLIT_STRING + this.vendor + SPLIT_STRING + this.type + SPLIT_STRING + this.version; + } + + /** + * Returns if it is an old textual signature (pre 1.2.0) that used cp1252 encoding for text extraction (mostly) + * @return + */ + public boolean isOldCp1252Version() { + return this.getVersion().equals(SignatorFactory.VERSION_1_0_0) + || this.getVersion().equals(SignatorFactory.VERSION_1_1_0); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java new file mode 100644 index 0000000..ed3dd3c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/ConfigLogger.java @@ -0,0 +1,79 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ConfigLogger.java,v 1.3 2006/08/30 13:55:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.cfg; + +import java.util.ArrayList; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +/** + * This logger class is the main logger class for the pdf-as project. It holds static logger + * instances with could be configured the level with one method. + * + * @deprecated use commons.logging instead + */ +public class ConfigLogger { + + /** + * The static logger cache. It holds all used logger instances that could be configured by this + * main class. + */ + private static ArrayList logger_ = new ArrayList(); + /** + * This is the Level to use. Default is INFO. + */ + private static Level level_ = Level.INFO; + + /** + * This method activates a new log4j logger instance and store the instance in the local logger + * store. + * + * @param classRef the caller class to be set + * @return a log4j logger instance + * @see Logger + */ + public static Logger getLogger(Class classRef) { + Logger logger = Logger.getLogger(classRef); + //logger.setLevel(level_); + logger_.add(logger); + return logger; + } + + /** + * This method is to set a new logger level for all stored config logger. + * + * @param level the level to set + */ + public static void setLevel(Level level) { + level_ = level; + for (int log_idx = 0; log_idx < logger_.size(); log_idx++) { + Logger logger = (Logger) logger_.get(log_idx); + logger.setLevel(level_); + logger_.set(log_idx, logger); + } + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/OverridePropertyHolder.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/OverridePropertyHolder.java new file mode 100644 index 0000000..ddc3290 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/OverridePropertyHolder.java @@ -0,0 +1,86 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.cfg; + +import java.util.Properties; + +import at.gv.egiz.pdfas.api.sign.SignParameters; +import at.gv.egiz.pdfas.utils.OgnlUtil; + +/** + * Thread local holder for profile override values. + * Don't use this class directly, use {@link SignParameters#setProfileOverrideValue(String, String)} + * + * @author exthex + * + */ +public class OverridePropertyHolder { + + private static ThreadLocal propHolder = new ThreadLocal() { + protected Object initialValue() { return new Properties();}; + }; + private static ThreadLocal ognlHolder = new ThreadLocal(); + + public static Properties getOverrideProps() { + return (Properties) propHolder.get(); + } + + public static void setOverrideProps(Properties props) { + propHolder.set(props); + } + + public static void setProperty(String key, String val) { + getOverrideProps().setProperty(key, val); + } + + public static String getProperty(String key) { + + String res = getOverrideProps().getProperty(key); + if (res != null) { + OgnlUtil ognl = getOgnl(); + if (ognl != null && ognl.containsExpression(res)) { + // evaluate expression + res = ognl.compileMessage(res); + } + } + return res; + } + + public static void removeProperties() { + propHolder.set(new Properties()); + } + + public static void setOgnlUtil(OgnlUtil ognl) { + ognlHolder.set(ognl); + } + + private static OgnlUtil getOgnl() { + return (OgnlUtil) ognlHolder.get(); + } + + public static void removeOgnlUtil() { + ognlHolder.set(null); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java new file mode 100644 index 0000000..49ba003 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/PropertyTree.java @@ -0,0 +1,358 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PropertyTree.java,v 1.4 2006/10/31 08:06:28 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.cfg; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +/** + * This class can be used to store a property config tree. The property key are separated by the + * {@link at.knowcenter.wag.egov.egiz.cfg.PropertyTree#SPLIT_STRING}. Therefore the keys an also + * the values of a configuration is stored in nested hashes. The keys in an area are stored in a + * HashMap. The values of a key are stored in a Vector to overload some keys. The property tree can + * be used to extract sub nodes and sub keys of different tree levels. + * + * @author wlackner + * @see java.util.HashMap + * @see java.util.Vector + */ +public class PropertyTree implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = -1686170519955886222L; + + /** + * The key split string. A key can be a complex key. Sub keys are separated from each other with + * the split string. This string is used to devide the complex key. + */ + public static final String SPLIT_STRING = "\\."; + /** + * Stores the key references to the sub nodes + */ + private Map keys_ = new HashMap(3); + /** + * Stores all values of a node + */ + private Vector values_ = new Vector(3); + + /** + * The default constructor od the class. + */ + public PropertyTree() { + } + + /** + * This method takes a key value tupel and store them in the property tree. The key splitted into + * different levels (splitted by the string + * {@link at.knowcenter.wag.egov.egiz.cfg.PropertyTree#SPLIT_STRING}). All subnodes not stored in + * the tree will be created. The last part of the key (last splitted element) adds the value to + * there own value data structure (Vector).
+ * Example: setKeyValue("key.1_level.2_level","the value for k_1_2")null
if the key is not a subtree referece + */ + private PropertyTree getLastSubTree(String splitKey) { + String[] keys = splitKey.split(SPLIT_STRING); + PropertyTree curr_tree = this; + for (int key_idx = 0; key_idx < keys.length; key_idx++) { + String key = keys[key_idx]; + if (!curr_tree.containsNode(key)) { + return null; + } + curr_tree = (PropertyTree) curr_tree.getSubNode(key); + } + return curr_tree; + } + + /** + * This method return the subtree that corresponds to a particular key. The key does not split. + * Therefore the key must be a children of the current node. Search only in the key map of the + * current node. + * + * @param key the key that has to be a sub node + * @return a sub tree (PropertyTree) or null if the key is not a children of the + * current node + */ + private PropertyTree getSubNode(String key) { + return (PropertyTree) keys_.get(key); + } + + /** + * Returns the last value (keys can be overloaded) of a key. The key are splitted into subnodes + * and the last node of the key is the current value holder. If a key or subnode is not in the sub + * tree the return value is null. + * + * @param key the key that holds the value (can be a nested key like "key.1.2.3") + * @return the value of the key (last node of the key) or null otherwise + */ + public String getLastValue(String key) { + PropertyTree curr_tree = getLastSubTree(key); + String result = null; + if (curr_tree != null && !curr_tree.values_.isEmpty()) { + result = (String) curr_tree.values_.lastElement(); + } +// if (logger_.isDebugEnabled()) { +// logger_.debug("getLastValue:" + key + "=" + result); +// } + return result; + } + + /** + * Returns the first value (keys can be overloaded) of a key. The key are splitted into subnodes + * and the last node of the key is the current value holder. If a key or subnode is not in the sub + * tree the return value is null. + * + * @param key the key that holds the value (can be a nested key like "key.1.2.3") + * @return the value of the key (last node of the key) or null otherwise + */ + public String getFirstValue(String key) { + PropertyTree curr_tree = getLastSubTree(key); + String result = null; + if (curr_tree != null && !curr_tree.values_.isEmpty()) { + result = (String) curr_tree.values_.firstElement(); + } +// if (logger_.isDebugEnabled()) { +// logger_.debug("getFirstValue:" + key + "=" + result); +// } + return result; + } + + /** + * This method return all values of the current node. The values are stored as String values. + * + * @return the values (type String) of the current node + * @see Vector + */ + public Vector getValues() { + return values_; + } + + /** + * This method return all keys (sub tree references) of the current node as a Map. The keys are + * stored as String values. + * + * @return the keys (type String) of the current node + * @see Map + */ + public Map getKeyEntries() { + return keys_; + } + + /** + * This method return all keys (sub tree references) of the current node as an ArrayList. The keys + * are stored as String values. + * + * @return the keys (type String) of the current node + * @see ArrayList + */ + public ArrayList getKeys() { + if (!keys_.isEmpty()) { + Object[] objs = keys_.keySet().toArray(); + ArrayList keys = new ArrayList(objs.length); + for (int idx = 0; idx < objs.length; idx++) { + keys.add((String) objs[idx]); + } + return keys; + } + return null; + } + + /** + * + * This method return all sub tree references of a key as an ArrayList. The keys are stored as + * String values. + * + * @param key (can be a nested key like "key.1.2.3") + * @return the keys (type String) of the current node + * @see ArrayList + */ + public ArrayList getKeys(String key) { + PropertyTree curr_tree = getLastSubTree(key); + if (curr_tree != null) { + return curr_tree.getKeys(); + } + return null; + } + + /** + * This method return all values of a key. The values are stored as String values. + * + * @param key (can be a nested key like "key.1.2.3") + * @return the values (type Vector) of the key or null if the key is not in the sub + * tree of the current node + * @see Vector + */ + public Vector getValues(String key) { + PropertyTree curr_tree = getLastSubTree(key); + if (curr_tree != null) { + return curr_tree.values_; + } + return null; + } + + /** + * Store a sub tree (type PropertyTree) in the current node. The key and it's sub tree are stored + * in a HashMap. + * + * @param key the reference of the sub tree + * @param tree the sub tree of the key + * @see HashMap + */ + private void setSubTree(String key, PropertyTree tree) { + if (tree == null) { + tree = new PropertyTree(); + } + keys_.put(key, tree); + } + + /** + * Extracts a sub tree of a nested key. The Method returns the last sub tree of the nested key. + * Example: if the key is like: key.1.2.3 the sub tree of the last + * node 3 is returned. + * + * @param key the reference of the sub tree + * @return a sub tree of the key or null if the key can not be found + */ + public PropertyTree getSubTree(String key) { + return getLastSubTree(key); + } + + /** + * This method checks if a key is a reference to a sub tree in the current node. + * + * @param key a simple key that is a parent reference of a sub tree + * @return true if the key is found, false otherwise + */ + public boolean containsNode(String key) { + return keys_.containsKey(key); + } + + /** + * The default toString method. It starts with the current node recursively downwards and return + * the String representation of the node. + * + * @return the string representation of the node + */ + public String toString() { + return toString("", this); + } + + /** + * This is a helper function to define the prefix for different levels in the toString method, not + * realy nice ;-). + * It replaces all "." chars with " ". + * + * @param key + * @return a replaces prefix string + */ + private static String getEmptyString(String key) { + return key.replaceAll(".", " "); + } + + /** + * This method concatenates all values of the current node and return them as a combinded string. + * + * @param prefix + * @param tree + * @return the string representation of the node values + */ + private static String printValues(String prefix, PropertyTree tree) { + String os = ""; + Iterator values = tree.getValues().iterator(); + while (values.hasNext()) { + String value = (String) values.next(); + os += prefix + "=" + value; + } + return os; + } + + /** + * The toString method. It starts with a special level prefix, sub tree and recursively adds all + * sub trees. + * + * @param prefix the prefix for this node + * @param tree the current node + * @return the string representation of the node + */ + public static String toString(String prefix, PropertyTree tree) { + String os = ""; + Iterator entries = tree.getKeyEntries().entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry) entries.next(); + String key = (String) entry.getKey(); + PropertyTree sub = (PropertyTree) entry.getValue(); + String os_key = "\n" + prefix + "." + key; + os += printValues(os_key, sub); + String subs = toString(prefix + getEmptyString(key) + " |", sub); + if (subs.length() > 0) { + os += os_key + "|" + subs; + } + } + return os; + } + + public void removeEntry(String key) { + this.keys_.remove(key); + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java new file mode 100644 index 0000000..0c238ac --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/Settings.java @@ -0,0 +1,63 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Settings.java,v 1.2 2006/08/03 07:43:03 wprinz Exp $ + */ + +package at.knowcenter.wag.egov.egiz.cfg; + +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; + +/** + * Defines an interface reading a configuration file. + * + * @author wlackner + */ +public interface Settings { + /** + * Search for a key in the configuration file. + * + * @param key to search for + * @return the corresponding value + * @throws SettingNotFoundException if the key is not found + */ + public String getSetting(String key) throws SettingNotFoundException; + + /** + * Search for a key in the configuration file. + * + * @param key to search for + * @param defaultValue return this value if the key is not found + * @return the corresponding value + */ + public String getSetting(String key, String defaultValue); + + /** + * + * @param primaryKey to search for + * @param defaultKey to search for if the primaryKey is not found + * @param defaultValue return this value if the defaultKey is not found + * @return the corresponding value + */ + public String getSetting(String primaryKey, String defaultKey, String defaultValue); +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java new file mode 100644 index 0000000..6bc1c99 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/cfg/SettingsReader.java @@ -0,0 +1,905 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SettingsReader.java,v 1.6 2006/10/31 08:06:36 wprinz Exp $ + */ + +package at.knowcenter.wag.egov.egiz.cfg; + +import iaik.asn1.ObjectID; +import iaik.security.ecc.provider.ECCProvider; +import iaik.security.provider.IAIK; +import iaik.utils.RFC2253NameParser; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.security.Security; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Properties; +import java.util.Vector; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.text.StrSubstitutor; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.exceptions.ConfigUtilsException; +import at.gv.egiz.pdfas.utils.ConfigUtils; +import at.gv.egiz.pdfas.utils.TempDirHelper; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.pdf.Utils; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * The SettingsReader reads the settings.txt file. The + * settings.txt is a simple java property file that collects all + * parameters used in different modules. + * + * The SettingsReader provides methods to get the property keys and the + * corresponding values. The keys could be defined as combinations of single + * keys. Therefore it is possible to combine differen classes of keys. An + * example could be: + * + *
+ *     
+ *                        #SettingNotFoundException
+ *                        error.code.100=Interner Fehler
+ *                        error.code.101=Die Konfigurationsdatei konnte nicht geladen werden
+ *                        
+ *                        #PDFDocumentException
+ *                        error.code.200=Das Dokument konnte nicht geladen werden
+ *                        
+ *                        #SignatureException
+ *                        error.code.300=Die Signatur ist ungültig
+ *                        
+ *                        #NormalizeException
+ *                        error.code.400=Die angegebene Version ist nicht bekannt
+ *                       
+ *                        normalizer.version=V01
+
+ *      
+ * 
+ * + * The internal representation of the example above is: + * + *
+ *     
+
+ *                        .error|
+ *                              |.code|
+ *                              |     |.200=Das Dokument konnte nicht geladen werden
+ *                              |     |.100=Interner Fehler
+ *                              |     |.400=Die angegebene Version ist nicht bekannt
+ *                              |     |.101=Die Konfigurationsdatei konnte nicht geladen werden
+ *                              |     |.300=Die Signatur ist ungueltig
+ *                       .normalizer|
+ *                                  |.version=V01      
+ *      
+ * 
+ * + * @author wlackner + */ +public class SettingsReader implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -8754114172766023454L; + + /** + * The system File separator char + */ + private static final String FILE_SEP = System.getProperty("file.separator"); + + // /** + // * The system temp file path + // */ + // private static final String TEMP_FILE_PATH = + // System.getProperty("java.io.tmpdir"); + +// /** +// * The home path of the tomcat webaplication +// */ +// private static final String CATALINA_HOME = System.getProperty("catalina.home"); + +// /** +// * The default application name used in templates, settings, jsp's etc. +// */ +// private static final String APPL_NAME = "pdf-as"; + + // private static final String APPL_NAME = "egiz"; + /** + * The config file path postfix + */ + private static final String CFG = "cfg"; + + /** + * The file path postfix where certificates are stored + */ + private static final String CERT = "certificates"; + + /** + * pdf-as internal properties resource path + */ + private static final String PDF_AS_PROP_RESOURCE = "/config/pdf-as.properties"; + + /** + * internal help file + */ + private static final String HELP_TEXT_PROP_RESOURCE = "/config/help_text.properties"; + + public static final boolean REGISTER_IAIK_PROVIDERS_ON_DEFAULT = true; + +// /** +// * The web application path +// */ +// private static final String WEB_APPL_DIR = "webapps" + FILE_SEP + APPL_NAME + FILE_SEP; + + /** + * The path of the resources repository. + * + *

+ * This usually contains sub directories for the templates, the configuration + * files, etc. + *

+ */ + public static String RESOURCES_PATH = null; + + /** + * The path for temporary files. + */ + public static String TMP_PATH = null; + + /** + * The path of the configuration directory. + */ + public static String CONFIG_PATH = null; + + /** + * The path of the certificated directory. + */ + public static String CERT_PATH = null; + + // /** + // * The application config path for the command line tool + // */ + // public static final String APPL_CONFIG_PATH = USER_DIR + FILE_SEP + CFG + + // FILE_SEP; + // + // /** + // * The application config path for the web application + // */ + // public static final String WEB_CONFIG_PATH = CATALINA_HOME + FILE_SEP + + // WEB_APPL_DIR + CFG + FILE_SEP; + // + // /** + // * The certificates path for the command line tool + // */ + // public static final String APPL_CERT_PATH = USER_DIR + FILE_SEP + CERT + + // FILE_SEP; + // + // /** + // * The certificates path for the cweb application + // */ + // public static final String WEB_CERT_PATH = CATALINA_HOME + FILE_SEP + + // WEB_APPL_DIR + CERT + FILE_SEP; + + /** + * The name of the default configuration file. The definition syntax is the + * java property config syntax. + */ + public static final String CONFIG_FILE_DEFAULT_NAME = "config.properties"; + + /** + * The name of the help text configuration file. The definition syntax is the + * java property config syntax. + */ +// public static final String HELP_TEXT_FILE_DEFAULT_NAME = "help_text.properties"; + + /** + * The java properties from the settings file. + */ + private Properties properties_ = null; + + /** + * The settings reader instance. Used to make the class singleton. + */ + private static SettingsReader instance_ = null; + + /** + * The reference to the settings file. + */ + private static String settingsFile_ = null; + + /** + * The reference to the property representation of the settings file. + */ + private PropertyTree pTree_ = new PropertyTree(); + + /** + * The log. + */ + private static final Log logger_ = LogFactory.getLog(SettingsReader.class); + + private static final String INTERNAL_RESOURCE_PATH = "/config/"; + + + /** + * Make this constructor private. Use the method + * {@link SettingsReader#getInstance()}to get an instance from this class. + * The only cause to do this is that the definition file should only be read + * once while getting often this instance. The method throws an IOException if + * the settings file could not be read. + * + * @param settingsFile + * load this file, if the settingsFile == null the + * default settings ({@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}) + * file is used + * @throws SettingsException + * if the settings file could not be read + */ + private SettingsReader(String settingsFile) throws SettingsException + { + try + { + String cfg_path = CONFIG_PATH; + properties_ = new Properties(); + if (settingsFile == null) + { + settingsFile = cfg_path + CONFIG_FILE_DEFAULT_NAME; + } + settingsFile_ = settingsFile; + if (logger_.isInfoEnabled()) + { + File file = new File(settingsFile_); + logger_.debug("load Settings:" + file.getAbsolutePath()); + // Properties sys_prop = System.getProperties(); + // Enumeration prop_keys = sys_prop.propertyNames(); + // while (prop_keys.hasMoreElements()) { + // String key = (String) prop_keys.nextElement(); + // String value = sys_prop.getProperty(key); + // logger_.info(key + "=" + value); + // } + } + FileInputStream sfs = new FileInputStream(settingsFile_); + properties_.load(sfs); + + // dferbas override with system props + properties_.load(SettingsReader.class.getResourceAsStream(PDF_AS_PROP_RESOURCE)); + + Properties help_prop = new Properties(); +// FileInputStream hfs = new FileInputStream(cfg_path + HELP_TEXT_FILE_DEFAULT_NAME); +// help_prop.load(hfs); + help_prop.load(SettingsReader.class.getResourceAsStream(HELP_TEXT_PROP_RESOURCE)); + + // load properties from current package! + // properties_.load(getClass().getResourceAsStream(settingsFile_)); + Enumeration prop_keys = properties_.propertyNames(); + + while (prop_keys.hasMoreElements()) + { + String key = (String) prop_keys.nextElement(); + String value = properties_.getProperty(key); + pTree_.setKeyValue(key, value); + } + prop_keys = help_prop.propertyNames(); + while (prop_keys.hasMoreElements()) + { + String key = (String) prop_keys.nextElement(); + String value = help_prop.getProperty(key); + properties_.setProperty(key, value); + pTree_.setKeyValue(key, value); + } + } + catch (IOException e) + { + throw new SettingsException("Couldn't load settings from file " + settingsFile, e); + } + } + + /** + * This method returns an synchronized instance of this class. The settings + * file is read only once using this class. This method returns the instance + * holding the definitions of the default settings file. Default file: + * {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: "settings.txt". + * Note: IAIK JCE and IAIK ECC security providers are automatically registered. + * + * @return an instance of the SettingsReader + * @throws SettingsException + * if the default settings file could not be read + */ + public synchronized static SettingsReader getInstance() throws SettingsException + { + return getInstance(null); + } + + /** + * Reloads the Settings file. + * + *

+ * Subsequent calls to getInstance will return the new settings. + * Note: IAIK JCE and IAIK ECC security providers are automatically registered. + *

+ * + * @throws SettingsException f.e. + */ + public synchronized static void createInstance() throws SettingsException + { + instance_ = null; + getInstance(); + } + + /** + * Reloads the Settings file. + * + *

+ * Subsequent calls to getInstance will return the new settings. + *

+ * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; + * false: providers will NOT be automatically registered, providers + * needed have to be registered by the API user + * @throws SettingsException f.e. + */ + public synchronized static void createInstance(boolean registerProvider) throws SettingsException + { + instance_ = null; + getInstance(null, registerProvider); + } + + /** + * This method returns an synchronized instance of this class. The settings + * file is read only once using this class. This method returns the instance + * holding the definitions of the settingsFile. If the input param + * settingsFile == null the default settings file will be load. + * Default file: {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: + * "settings.txt" + * + * If an instance of this class exist, the input param is ignored! The + * SettingsReader is singleton and therefore the first + * {@link SettingsReader#getInstance()}defines the settings file that has to + * be loaded. This means changes between a application lifecyle can not be + * done! + * + * @param settingsFile + * the settings file that should be load. + * @param registerProvider true: automatically registers IAIK JCE and ECC Provider; + * false: providers will NOT be automatically registered, providers + * needed have to be registered by the API user + * @return an instance of the SettingsReader + * @throws SettingsException + * if the settings file could not be read + */ + private synchronized static SettingsReader getInstance(String settingsFile, boolean registerProvider) throws SettingsException + { + if (instance_ == null) + { + int length = Utils.max(new int[] { RESOURCES_PATH.length(), TMP_PATH.length(), CONFIG_PATH.length(), CERT_PATH.length() }); + + logger_.info(StringUtils.repeat("*", length + 25)); + logger_.info(" resources path = \"" + RESOURCES_PATH + "\""); + logger_.info(" configuration path = \"" + CONFIG_PATH + "\""); + logger_.info(" certstore path = \"" + CERT_PATH + "\""); + logger_.info(" temporary path = \"" + TMP_PATH + "\""); + logger_.debug(" file.encoding = \"" + System.getProperty("file.encoding") + "\""); + logger_.info(StringUtils.repeat("*", length + 25)); + + if (registerProvider) { + IAIK.addAsProvider(); + ECCProvider.addAsProvider(); + } else { + if (Security.getProvider("IAIK") == null) { + logger_.debug("Default IAIK JCE provider not registered."); + } else { + logger_.debug("IAIK JCE provider already registered."); + } + if (Security.getProvider("IAIK_ECC") == null) { + logger_.debug("Default IAIK ECC provider not registered."); + } else { + logger_.debug("IAIK ECC provider already registered."); + } + } + // Does not conform with PKIX, but is used by belgium citizen card +// log.info("Registering RDN \"SERIALNUMBER\" as " + ObjectID.serialNumber + "."); + RFC2253NameParser.register("SERIALNUMBER", ObjectID.serialNumber); + + instance_ = new SettingsReader(settingsFile); + } + return instance_; + } + + /** + * This method returns an synchronized instance of this class. The settings + * file is read only once using this class. This method returns the instance + * holding the definitions of the settingsFile. If the input param + * settingsFile == null the default settings file will be load. + * Default file: {@link SettingsReader#CONFIG_FILE_DEFAULT_NAME}: + * "settings.txt". + * Note: IAIK JCE and IAIK ECC security providers are automatically registered. + * + * If an instance of this class exist, the input param is ignored! The + * SettingsReader is singleton and therefore the first + * {@link SettingsReader#getInstance()}defines the settings file that has to + * be loaded. This means changes between a application lifecyle can not be + * done! + * + * @param settingsFile + * the settings file that should be load. + * @return an instance of the SettingsReader + * @throws SettingsException + * if the settings file could not be read + */ + private static SettingsReader getInstance(String settingsFile) throws SettingsException + { + return getInstance(settingsFile, REGISTER_IAIK_PROVIDERS_ON_DEFAULT); + } + + /** + * This method returns a property value to the corresponding key. If the key + * is not found in the property file a SettingNotFoundException is thrown. + * + * @param key + * get the value for that key in the property file + * @return the value of the property key. + * @throws SettingNotFoundException + * ErrorCode: 100 + */ + public String getSetting(String key) throws SettingNotFoundException + { + String result = OverridePropertyHolder.getProperty(key); + if (result == null) { + result = properties_.getProperty(key); + } + if (result == null) + { + String log_message = "Configuration key not found: '" + key + "'! Check '" + settingsFile_ + "' file."; + if (logger_.isWarnEnabled()) + { + logger_.warn(log_message); + } + SettingNotFoundException snf = new SettingNotFoundException(log_message); + throw snf; + } + + return result; + } + + // TODO in the next change request, the Setting system will be refactored + // this is just for testing purposes. + public void setSetting(String key, String value) + { + properties_.setProperty(key, value); + } + + /** + * Relocates the relative file. + * + * @param file + * The relative file. + * @return Returns the usable file. + */ + public static String relocateFile(String file) + { + // if (isWeb()) + // { + // return CATALINA_HOME + FILE_SEP + WEB_APPL_DIR + file; + // } + // + // return file; + return RESOURCES_PATH + file; + } + + /** + * This method returns a property value to the corresponding key. If the key + * is not found in the property file the input param defaultValue is returned. + * + * @param key + * get the value for that key in the property file + * @param defaultValue + * the default value if the key is not found + * @return the value of the property key + */ + public String getSetting(String key, String defaultValue) + { + + String result = properties_.getProperty(key); + if (result == null) + { + result = defaultValue; + } +// if (logger_.isDebugEnabled()) +// { +// logger_.debug("Get Property:" + key + "=" + result); +// } + return result; + } + + /** + * This method returns a property value to the corresponding key. If the key + * is not found in the property file the input param defaultKey is searched. + * If the default key is not found the input param defaultValue is returned. + * + * @param primaryKey + * get the value for that key in the property file + * @param defaultKey + * the default key that should be searched if the primaryKey is not + * found + * @param defaultValue + * the default value if the defaultKey is not found + * @return the value of the property key + */ + public String getSetting(String primaryKey, String defaultKey, String defaultValue) + { + String key = primaryKey; + String result = properties_.getProperty(key); + if (result == null) + { + key = defaultKey; + result = properties_.getProperty(key); + if (result == null) + { + result = defaultValue; + } + } +// if (logger_.isDebugEnabled()) +// { +// logger_.debug("Get Property:" + key + "=" + result); +// } + return result; + } + + /** + * This method returns an array of keys in the same hierarchy of the + * keyPrefix. The method search all keys in the property file that has the + * keyPrefix as leading substring. The Object[] collects all + * sub keys without the keyPrefix. + * + * @param keyPrefix + * to search for sub keys + * @return alls keys starting with the keyPrefix + */ + public Vector getSettingKeys(String keyPrefix) + { + Vector keys = new Vector(); + Enumeration names = properties_.propertyNames(); + while (names.hasMoreElements()) + { + String full_name = (String) names.nextElement(); + if (full_name.indexOf(keyPrefix) == 0) + { + keys.add(full_name.substring(keyPrefix.length() + 1)); + } + } + return keys; + } + + /** + * If a property value is number (interger) this method extracts the value and + * convert it to an int. If the key ist not found or the conversion fails, the + * defaultValue is returned. + * + * @param key + * get the value for that key in the property file + * @param defaultValue + * the default value if the key is not found + * @return the int value of the property key + */ + public int getIntSetting(String key, int defaultValue) + { + int int_property = defaultValue; + String value = null; + try + { + value = getSetting(key); + int_property = Integer.parseInt(value); + } + catch (NumberFormatException e) + { + if (logger_.isWarnEnabled()) + { + logger_.warn("Can not convert " + value + " to int.", e); + } + } + catch (SettingNotFoundException e) + { + if (logger_.isWarnEnabled()) + { + logger_.warn("Setting " + key + " not found, return default value:" + defaultValue, e); + } + } + return int_property; + } + + /** + * This method returns an array of sub keys (children references) of the key. + * The method is a wrapper calling the method + * {@link PropertyTree#getKeys(String key)}. + * + * @param key + * get all sub keys for that key in the property file + * @return an list of sub keys (type String) + * @see PropertyTree + */ + public ArrayList getKeys(String key) + { + return pTree_.getKeys(key); + } + + /** + * This method returns a the first value from a key. This means the method + * search in the PropertyTree representation of the config file. The + * PropertyTree class can overload key value paires. But the config file can + * not overload keys. If a key is defined more than one times the last + * definition is stored it the property list. The method is a wrapper calling + * the method {@link PropertyTree#getFirstValue(String key)}. + * + * @param key + * get the value for that key in the property file + * @return the value of the property key + * @see PropertyTree + */ + public String getValueFromKey(String key) + { + String value = OverridePropertyHolder.getProperty(key); + if (value == null) { + value = pTree_.getFirstValue(key); + } + + return value; + } + + /** + * This method returns the PropertyTree representation of the configuration + * file. + * + * @return Returns the pTree. + * @see PropertyTree + */ + public PropertyTree getPTree() + { + return pTree_; + } + + /** + * Reads internal resource as string. + * @param relativePath + * @return null in case of error + */ + public String readInternalResourceAsString(String relativePath) { +// return readAsString(getInternalResource(relativePath)); + return FileHelper.readFromInputStream(getInternalResource(relativePath)); + } + + /** + * Get resource as stream, relative to internal resource path {@value #INTERNAL_RESOURCE_PATH} + * + * @param relativePath + * @return + */ + public InputStream getInternalResource(String relativePath) { + // kill starting "." and "./" in resource path + relativePath = StringUtils.removeStart(relativePath, "."); + relativePath = StringUtils.removeStart(relativePath, "/"); + String streamURI = INTERNAL_RESOURCE_PATH + relativePath; + logger_.trace("Trying to get stream from \"" + streamURI + "\"."); + InputStream stream = this.getClass().getResourceAsStream(streamURI); + if (stream == null) { + logger_.trace("Could not get stream."); + } else { + logger_.trace("Got stream."); + } + return stream; + } + + /** + * Read resource as utf8 string. + * @param is + * @return null in case of error + */ + /* + public String readAsString(InputStream is) { + if (is == null) return null; + try { + return IOUtils.toString(is, "utf-8"); + } catch (IOException e) { + logger_.info("error reading stream to string ", e); + } + return null; + } + */ + + // /** + // * This method checks the application context. + // * + // * @return true if the application is running in a webinterface, false + // * otherwise + // */ + // public static boolean isWeb() + // { + // return CATALINA_HOME != null; + // } + + /** + * Assembles the File of the temporary directory without checking if it really + * exists. + * @see TempDirHelper#assembleTemporaryDirectoryFile() + */ + protected static File assembleTemporaryDirectoryFile() + { + return TempDirHelper.assembleTemporaryDirectoryFile(); + } + + /** + * Returns the directory where temporary files should be stored. + * + *

+ * If the directory doesn't exist, it is created. + *

+ * + * @return Returns the directory where temporary files should be stored. + * @see TempDirHelper#getTemporaryDirectory() + */ + public static File getTemporaryDirectory() + { + return TempDirHelper.getTemporaryDirectory(); + } + + /** + * Deletes all files in the temporary directory, if it exists. + * + *

+ * This should be used to clear temporary files when the application shuts + * down. + *

+ * @see TempDirHelper#clearTemporaryDirectory() + */ + public static void clearTemporaryDirectory() + { + TempDirHelper.clearTemporaryDirectory(); + } + + public static synchronized void initialize(String configdir, String tmpdir) { + + String defaultConfigDeployedTo = null; + // resolve work directory + // configuration explicitely given ? + if (configdir == null) { + + // configuration via system property ? + logger_.debug("No configuration directory given. Looking for system property \"" + Constants.CONFIG_DIR_SYSTEM_PROPERTY + "\"."); + configdir = System.getProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY); + if (configdir == null) { + + // configuration via user's home directory ? + logger_.debug("System property not set. Trying to locate configuration within the user's home directory."); + String userHome = System.getProperty("user.home"); + if (userHome == null || userHome.length() == 0) { + throw new RuntimeException("Unable to resolve user's home directory."); + } + configdir = ConfigUtils.assertFileSeparator(userHome) + Constants.USERHOME_CONFIG_FOLDER; + try { + defaultConfigDeployedTo = ConfigUtils.deployDefaultConfiguration(configdir, false); + } catch (ConfigUtilsException e) { + throw new RuntimeException(e); + } + if (defaultConfigDeployedTo != null) { + logger_.info("** Default configuration successfully deployed to \"" + defaultConfigDeployedTo + "\" **"); + } else { + logger_.debug("Default configuration has NOT been deployed. Maybe the configuration already exists."); + } + } else { + logger_.debug("Configuration set by system property."); + if (tmpdir == null) { + tmpdir = configdir; + } + } + } else { + logger_.debug("Configuration path explicitely set."); + } + File configdirFile = new File(StrSubstitutor.replaceSystemProperties(configdir)); + try { + configdir = ConfigUtils.assertFileSeparator(configdirFile.getCanonicalPath()); + } catch (IOException e) { + configdir = ConfigUtils.assertFileSeparator(configdirFile.getPath()); + } + if (!configdirFile.isDirectory()) + { + throw new IllegalArgumentException("The config directory \"" + configdir + "\" does not exist or is not a directory."); + } + + // resolve temporary dir + if (tmpdir == null) { + logger_.debug("Temporary directory not explicitely set. Looking for user's temp directory."); + tmpdir = System.getProperty("java.io.tmpdir"); + if (tmpdir == null) { + logger_.debug("Unable to resolve user's temporary directory. Assuming temporary directory located within config dir."); + tmpdir = configdir; + } + } else { + logger_.debug("Temporary directory explicitely set."); + } + File tmpdirFile = new File(StrSubstitutor.replaceSystemProperties(ConfigUtils.assertFileSeparator(tmpdir) + Constants.TEMP_DIR_NAME)); + try { + tmpdir = ConfigUtils.assertFileSeparator(tmpdirFile.getCanonicalPath()); + } catch (IOException e) { + tmpdir = ConfigUtils.assertFileSeparator(tmpdirFile.getPath()); + } + + RESOURCES_PATH = configdir; + TMP_PATH = tmpdir; + CONFIG_PATH = RESOURCES_PATH + CFG + FILE_SEP; + CERT_PATH = RESOURCES_PATH + CERT + FILE_SEP; + +// ConfigUtils.printConfigInfo(logger_); + + if (defaultConfigDeployedTo != null) { + logger_.debug("** Default configuration successfully deployed to \"" + defaultConfigDeployedTo + "\" **"); + } + logger_.debug("Setting system property \"" + Constants.CONFIG_DIR_SYSTEM_PROPERTY + "\" to \"" + configdirFile.getPath() + "\"."); + System.setProperty(Constants.CONFIG_DIR_SYSTEM_PROPERTY, configdirFile.getPath()); + } + + public static void initialize(String base_dir) + { + initialize(base_dir, null); + } + + /** + * Initializes the paths of the SettingsReader for web application usage. + * + * @param base_dir + * The base directory of this web application. E.g. + * TOMCAT_HOME/webapps/pdf-as + */ + public static void initializeForWeb(String base_dir) + { + initialize(base_dir, base_dir); + } + + /** + * Initializes the paths of the SettingsReader for commanline usage. + */ + public static void initializeForCommandLine() + { + initialize(null); + } + + static { + + String versionString = "* PDF-AS library version " + PdfAS.PDFAS_VERSION + " *"; + String paddingString = StringUtils.repeat("*", versionString.length()); + logger_.info("PDF-AS info\n" + paddingString + "\n" + versionString + "\n" + paddingString); + } + + public Properties getProperties() { + return this.properties_; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java new file mode 100644 index 0000000..1b66f53 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/commandline/Main.java @@ -0,0 +1,1149 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Main.java,v 1.5 2006/10/31 08:06:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.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.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.commandline.CommandlineConnectorChooser; +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.DataSourceHolder; +import at.gv.egiz.pdfas.framework.config.SettingsHelper; +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.ExtractionStage; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.vfilter.VerificationFilterParameters; +import at.gv.egiz.pdfas.impl.input.FileBasedPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.gv.egiz.pdfas.impl.output.FileBasedDataSink; +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.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +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.ConnectorFactory; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * The main program entry point of the commandline tool. + * + * @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 + * + * @deprecated use {@link at.gv.egiz.pdfas.commandline.Main} instead + */ + public static void main(String[] args) throws IOException { + System.out.println("\nWarning: The entry point at.knowcenter.wag.egov.egiz.commandline.Main is deprecated. Use at.gv.egiz.pdfas.commandline.Main instead.\n"); + at.gv.egiz.pdfas.commandline.Main.main(args); + } + + /* + 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 (PresentableException 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 PresentableException + { + // 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 PresentableException + { + messageOutput.println("Signing..."); + + // for performance measurement + long startTime = 0; + long fileSize = 0; + if (logger_.isInfoEnabled()) { + startTime = System.currentTimeMillis(); + } + + PdfDataSource pdfDataSource; + try + { + File file = new File(input); + pdfDataSource = new FileBasedPdfDataSourceImpl(file, (int)file.length()); + if (logger_.isDebugEnabled()) + fileSize = file.length(); + + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + + FileBasedDataSink dataSink = null; + File outputFile = null; + try + { + outputFile = new File(output); + + dataSink = new FileBasedDataSink(outputFile); + } + catch (IOException e) + { + throw new PDFDocumentException(ErrorCode.CANNOT_WRITE_PDF, e); + } + + try { + processSign(pdfDataSource, connector, signature_mode, signature_type, pos_string, dataSink); + } catch (Exception e) { + // Exception caught in order to delete file based datasink + if (outputFile != null && outputFile.exists()) + { + logger_.debug("Deleting output file on error."); + boolean deleted = outputFile.delete(); + if (!deleted) + { + logger_.error("Couldn't delete output file " + output); + } + } + if (e instanceof PresentableException) { + throw (PresentableException)e; + } else { + throw new PresentableException(ErrorCode.UNKNOWN_ERROR, e); + } + } + + // 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 PresentableException + { + 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 = 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 TextDataSourceImpl(text); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Very strange: UTF-8 character encoding not supported.", e); + } + } + else + { + dataSource = new FileBasedPdfDataSourceImpl(file, (int)file.length()); + } + } + catch (IOException e) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + + List results = processVerify(new DataSourceHolder(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); + } + + + } + + /** + * Extracts the extension from a file name string. + * + *

+ * The extension of a file name is whatever text follows the last '.'. + *

+ * + * @param file_name + * The file name. + * @return Returns the extension. If the file name ends with the '.', then an + * empty string is returned. If the file name doesn't contain any '.' + * or file_name is null, null is returned. + */ + public static String extractExtension(String file_name) + { + if (file_name == null) + { + return null; + } + + int dot_index = file_name.lastIndexOf('.'); + if (dot_index < 0) + { + return null; + } + return file_name.substring(dot_index + 1); + } + + public static void processSign(PdfDataSource pdfDataSource, String connector, String signature_mode, String signature_type, String pos_string, DataSink dataSink) throws PresentableException + { + pdfDataSource = 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; + + } + } + + PdfASID signatorId = translateSignatureModeToPdfASID(signature_mode); + + // TODO MOA detached signing is not allowed at the commandline +// logger_.debug("Suggested sign algorithm = " + signatorId); + if (connector.equals("moa")) + { + // TODO: possible new implementation of moa where is commandline call + // supported + // it should be checked in config file is it allowed to use MOA detached + // from command line. +// String msg = "Hinweis: Der MOA Detached Connector ist fuer die Kommandozeile nicht geeignet. Die Signatur wird daher im alten Base64 enveloping Format ausgefuehrt."; +// System.out.println(msg); +// logger_.warn(msg); +// +// if (signature_mode.equals(VALUE_SIGNATURE_MODE_BINARY)) +// { +// signatorId = BinarySignator_1_0_0.MY_ID; +// } +// if (signature_mode.equals(VALUE_SIGNATURE_MODE_TEXTUAL)) +// { +// signatorId = TextualSignator_1_0_0.MY_ID; +// } + } +// logger_.debug("Finally used sign algorithm = " + signatorId); + + String connectorId = CommandlineConnectorChooser.chooseCommandlineConnectorForSign(connector); + + PdfAS.signCommandline(pdfDataSource, dataSink, signatorId, connectorId, signature_type, null, pos, null, null); + +// PdfAS.sign(algorithm, pdfDataSource, dataSink, signature_type, connector, pos); + } + + public static List processVerify(DataSourceHolder dataSource, String connector, int verify_which) throws PresentableException + { + VerificationFilterParameters parameters = SettingsHelper.readVerificationFilterParametersFromSettings(); + ExtractionStage es = new ExtractionStage(); + + List signature_holders = es.extractSignatureHolders(dataSource, parameters); + + if (signature_holders.isEmpty()) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_NOT_SIGNED, "Document is unsigned."); + } + + List holders_to_verify = signature_holders; + + // verify_which - optional argument in command line/web + if (verify_which >= 0) + { + if (verify_which >= signature_holders.size()) + { + throw new SignatureException(312, "The selected signature to be verified doesn't exist."); + } + + SignatureHolder holder = (SignatureHolder) signature_holders.get(verify_which); + holders_to_verify = new ArrayList(); + holders_to_verify.add(holder); + } + + List results = PdfAS.verifySignatureHolders(holders_to_verify, connector, false, null); + + return results; + } + + // TODO old method - remove + // /** + // * Generates a suitable output file name for the output regarding the type + // of + // * the sign_result. + // * + // * @param input + // * The input file name. + // * @param sign_result + // * The sign result. + // * @return Returns the output file name. + // */ + // protected static String generateOutputFileNameFromInput(String input, + // SignResult sign_result) + // { + // String output = input + "_out"; + // if (sign_result.getMimeType().equals(DetachedSignator_1_0_0.MIME_TYPE)) + // { + // output += ".xml"; + // } + // else + // { + // output += ".pdf"; + // } + // + // return output; + // } + + protected static String generateOutputFileNameFromInput(String input, String sig_mode) + { + String output = input + "_out"; + if (sig_mode.equals("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 PresentableException 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"); + //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(); + Set 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 + { + return SignatureTypes.getInstance().getSignatureTypes().contains(signature_type); + + // exthex: uuuaaaahhhhh WHY??? wprinz again?, dont do that. Use List.contains(o), please + // take a java course and read: http://www.amazon.de/Java-f%C3%BCr-Dummies-Barry-Burd/dp/382662999X +// 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(List results, PrintWriter writer) throws SettingNotFoundException + { + Iterator it = results.iterator(); + while (it.hasNext()) + { + SignatureResponse result = (SignatureResponse) it.next(); + formatSignatureResponse(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(List results) throws SettingNotFoundException + { + int toreturn = 0; + Iterator it = results.iterator(); + while (it.hasNext()) + { + SignatureResponse result = (SignatureResponse) it.next(); + + toreturn += Integer.valueOf(result.getSignatureCheckCode()).intValue(); + } + return toreturn; + } + + + /** + * Formats the SignatureResponse. + * + * @param result + * The SignatureResponse to be printed. + * @param writer + * The output sink to write the formatted text to. + * @throws SettingNotFoundException + * Forwarded exception. + */ + public static void formatSignatureResponse(SignatureResponse result, PrintWriter writer) throws SettingNotFoundException + { + + writer.println(" Zertifikat:"); + writer.println(" Signator: " + result.getX509SubjectName()); + writer.println(" Aussteller: " + result.getX509IssuerName()); + writer.println(" Seriennummer: " + result.getX509SerialNumber()); + 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.getCertificateCheckCode() + " - " + result.getCertificateCheckInfo()); + writer.println(" Signatur-Check:"); + writer.println(" " + result.getSignatureCheckCode() + " - " + result.getSignatureCheckInfo()); + writer.println(" Manifest-Check:"); + writer.println(" " + result.getSignatureManifestCheckCode() + " - " + result.getSignatureManifestCheckInfo()); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorException.java new file mode 100644 index 0000000..9969056 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorException.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * This exception is thrown when a Connector encounters an exception during sign + * or verify. + * + * @author wprinz + */ +public class ConnectorException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 4321130695505581234L; + + /** + * @param error_code + * @param message + * @param cause + */ + public ConnectorException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public ConnectorException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public ConnectorException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + public ConnectorException(PresentableException cause) + { + super(cause.getErrorCode(), cause); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java new file mode 100644 index 0000000..eb90c5e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ConnectorFactoryException.java @@ -0,0 +1,74 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ConnectorFactoryException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + +/** + * This exception is thrown when the connector factory encounters an error + * during providing a connector. + * + *

+ * The most likely case for this exception is that a wrong connector identifier + * was provided. + *

+ * + * @author wprinz + */ +public class ConnectorFactoryException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -1398538795243257880L; + + /** + * @param message + */ + public ConnectorFactoryException(String message) + { + super(ErrorCode.SETTINGS_EXCEPTION, message); + } + +// /** +// * @param message +// * @param cause +// */ +// public ConnectorFactoryException(String message, Throwable cause) +// { +// super(message, cause); +// } + + /** + * @param cause + */ + public ConnectorFactoryException(Throwable cause) + { + super(ErrorCode.SETTINGS_EXCEPTION, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java new file mode 100644 index 0000000..dc35582 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/ErrorCodeException.java @@ -0,0 +1,318 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ErrorCodeException.java,v 1.1 2006/08/03 07:47:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; + +/** + * This exception should be inherit, if an exception should be shown as a + * feedback message in user interfaces. + * + *

+ * The error code is an integer number. The error codes are defined in an + * separate configuration file, readed be the SettingsReader. If the + * SettingsReader can not initialized, a corresponding error message can not + * read! + *

+ *

+ * The error code can be seen a a replacement of the exception message. For all + * intents and purposes, the error code should be used to provide exceptional + * feedback to the user. Nevertheless, if possible, a debug message String (the + * message parameter) should still be provided giving in depth developer + * descriptions of the problem. These message strings will then show up in the + * log files accordingly. + *

+ * + * @author wlackner + * @author wprinz (enforced error code) + * + * @deprecated + * + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class ErrorCodeException extends PresentableException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 2071967845179686593L; + + /** + * Template key getting error messages + */ + private static final String ERROR_CODE_KEY = "error.code."; + + /** + * The default error message + */ + private static final String DEFAULT_ERROR_MESSAGE = "Fehler Code:"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(ErrorCodeException.class); + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The default error code + */ + private int error_code_ = -1; + + /** + * If an external application is called + */ + private String externalErrorCode_ = null; + + /** + * If an external application is called + */ + private String externalErrorMessage_ = null; + + /** + * Constructor that sets the error code. + * + * @param error_code + * The error code. + */ + public ErrorCodeException(final int error_code) + { + super(error_code, "just an error code"); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Inherit Constructor from Exception, + * + * @param error_code + * The error code. + * @param message + * The in depth developer provided error message. + * @see Exception + */ + public ErrorCodeException(final int error_code, String message) + { + super(error_code, message); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Inherit Constructor from Exception, + * + * @param error_code + * The error code. + * @param message + * The in depth developer provided error message. + * @param cause + * The cause of this exception. + * @see Exception + */ + public ErrorCodeException(final int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Inherit Constructor from Exception, + * + * @param error_code + * The error code. + * @param cause + * The cause of this exception. + * @see Exception + */ + public ErrorCodeException(final int error_code, Throwable cause) + { + super(error_code, cause); + this.error_code_ = error_code; + loadSettings(); + } + + /** + * Load the settings file. Call the SettingsReader instance. + */ + private void loadSettings() + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message, e); + } + } + } + + /** + * Return the manually stored error code. The error code is only a key for a + * configurable error message. The error code and its corresponding message + * have to be declared in an separate property file, loaded by the + * SettingsReader + * + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + * @return Returns the errorCode. + */ + public int getErrorCode() + { + return this.error_code_; + } + + /** + * Set a special error code in case of commuicating this error in an user + * interface. The error code is only a key for a configurable error message. + * The error code and its corresponding message have to be declared in an + * separate property file, loaded by the SettingsReader + * + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + * @param error_code + * The error code to be set. + */ + public void setErrorCode(final int error_code) + { + this.error_code_ = error_code; + } + + /** + * Set a special error code in case of commuicating this error in an user + * interface. The error code is a key for an external application error + * message. The error code and its corresponding message have to be declared + * by the external tool that used. + * + * @param errorCode + * The errorCode to set. + */ + public void setExternalErrorCode(String errorCode) + { + externalErrorCode_ = errorCode; + } + + /** + * Returns an external error code that is set manually + * + * @return the external error code if set, null otherwise + */ + public String getExternalErrorCode() + { + return externalErrorCode_; + } + + /** + * Set a special error message in case of commuicating this error in an user + * interface. The error message and its corresponding error code have to be + * declared by the external tool that used. + * + * @param errorMessage + */ + public void setExternalErrorMessage(String errorMessage) + { + externalErrorMessage_ = errorMessage; + } + + /** + * Returns an external error message that is set manually + * + * @return the external error message if set, null otherwise + */ + public String getExternalErrorMessage() + { + return externalErrorMessage_; + } + + /** + * Checks if an external error message is set. + * + * @return returns true if a message is set, false + * otherwise + */ + public boolean hasExternalErrorMessage() + { + return (externalErrorMessage_ != null); + } + + /** + * Get the configured error message that corresponds to the error code. If the + * config file can't be read, or an error code is not declared in the config + * file, the default error message would be returned. + * + * @return an error message that can be used for ui communication + */ + public String getErrorCodeMessage() + { + String err_msg = null; + if (settings_ != null) + { + err_msg = settings_.getSetting(ERROR_CODE_KEY + error_code_, DEFAULT_ERROR_MESSAGE + error_code_); + } + return err_msg; + } + + /** + * Get the configured error message that corresponds to the given error code. + * If the config file can't be read, or an error code is not declared in the + * config file, the default error message would be returned. + * + * @return an error message that can be used for ui communication + */ + public static String getErrorCodeMessage(int errorCode) + { + SettingsReader settings = null; + String err_msg = DEFAULT_ERROR_MESSAGE + errorCode; + try + { + settings = SettingsReader.getInstance(); + err_msg = settings.getSetting(ERROR_CODE_KEY + errorCode, DEFAULT_ERROR_MESSAGE + errorCode); + } + catch (SettingsException e) + { + logger_.error(e.getMessage(), e); + } + return err_msg; + } + + /** + * Checks if the exception has an ErrorCode state. + * + * @return true if an ErrorCode does exist false otherwise + */ + public boolean hasErrorCode() + { + return error_code_ != 0; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java new file mode 100644 index 0000000..ae3a2f8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/InvalidIDException.java @@ -0,0 +1,55 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: InvalidIDException.java,v 1.1 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * Thrown when parsing an ID ("Kennzeichnung") fails. + * @author wprinz + */ +public class InvalidIDException extends SignatureException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7945398356854048254L; + + public InvalidIDException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + public InvalidIDException(int error_code, String message) + { + super(error_code, message); + } + + public InvalidIDException(int error_code, Throwable cause) + { + super(error_code, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java new file mode 100644 index 0000000..0f8f145 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/NormalizeException.java @@ -0,0 +1,62 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: NormalizeException.java,v 1.1 2006/08/03 07:47:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + + +/** + * This exception is thrown by the processing a normalizer. + * + * @author wlackner + */ +public class NormalizeException extends PresentableException { + + /** + * SVUID. + */ + private static final long serialVersionUID = -4080682145462891501L; + + /** + * @param error_code + * @param message + * @param cause + */ + public NormalizeException(String message, Throwable cause) + { + super(ErrorCode.NORMALIZER_EXCEPTION, message, cause); + } + + /** + * @param error_code + * @param message + */ + public NormalizeException(String message) + { + super(ErrorCode.NORMALIZER_EXCEPTION, message); + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/OutOfMemoryException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/OutOfMemoryException.java new file mode 100644 index 0000000..ec2ccb3 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/OutOfMemoryException.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +public class OutOfMemoryException extends PresentableException { + + private static final long serialVersionUID = 1L; + + public OutOfMemoryException(int errorCode, String message, Throwable cause) { + super(errorCode, message, cause); + } + + public OutOfMemoryException(int errorCode, String message) { + super(errorCode, message); + } + + public OutOfMemoryException(int errorCode, Throwable cause) { + super(errorCode, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java new file mode 100644 index 0000000..7fb4c8d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PDFDocumentException.java @@ -0,0 +1,70 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFDocumentException.java,v 1.1 2006/08/03 07:47:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +/** + * This exception is thrown in case of problems using pdf librarys. + * + * @author wlackner + */ +public class PDFDocumentException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -4595955288382226408L; + + /** + * @param error_code + * @param message + * @param cause + */ + public PDFDocumentException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public PDFDocumentException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public PDFDocumentException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java new file mode 100644 index 0000000..5697edc --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PlaceholderException.java @@ -0,0 +1,66 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PlaceholderException.java,v 1.1 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + +/** + * @author wprinz + */ +public class PlaceholderException extends PDFDocumentException +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -9149805408421810170L; + + + protected String field = null; + protected int missing = -1; + + public PlaceholderException(String field, int missing) + { + super(ErrorCode.PLACEHOLDER_EXCEPTION, field + ":" + missing); + + this.field = field; + this.missing = missing; + } + + public void setField (String field) + { + this.field = field; + } + + public String getField() + { + return this.field; + } + + public int getMissing() + { + return this.missing; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java new file mode 100644 index 0000000..40d7181 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/PresentableException.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PresentableException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; + +/** + * This exception should be the base for all exceptions that are to be presented + * to the user. + * + *

+ * For example, exceptions that signal that a pdf file is corrupt should be + * represented as presentable exceptions so that the user interface frontends + * can present according texts. + *

+ * + * @see PdfAsException + * + * @author wprinz + */ +public class PresentableException extends PdfAsException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -102406558526000792L; + + public PresentableException(int errorCode, String message, Throwable cause) + { + super(errorCode, message, cause); + } + + public PresentableException(int errorCode, String message) + { + super(errorCode, message); + } + + public PresentableException(int errorCode, Throwable cause) + { + super(errorCode, cause); + } + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java new file mode 100644 index 0000000..6c140eb --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingNotFoundException.java @@ -0,0 +1,77 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SettingNotFoundException.java,v 1.1 2006/08/03 07:47:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + +/** + * This exception is thrown by the SettingsReader if a property key is not + * found. + * + * @author wlackner + */ +public class SettingNotFoundException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7502191288775676006L; + + /** + * @param error_code + * @param message + * @param cause + */ + public SettingNotFoundException(String message, Throwable cause) + { + super(ErrorCode.SETTING_NOT_FOUND, message, cause); + } + + /** + * @param error_code + * @param message + */ + public SettingNotFoundException(String message) + { + super(ErrorCode.SETTING_NOT_FOUND, message); + } + + /** + * @param error_code + * @param cause + */ + public SettingNotFoundException(Throwable cause) + { + super(ErrorCode.SETTING_NOT_FOUND, cause); + } + + protected SettingNotFoundException(int errorCode, String message) + { + super(errorCode, message); + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java new file mode 100644 index 0000000..a43de6a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SettingsException.java @@ -0,0 +1,74 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SettingsException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + +/** + * Thrown when the settings couldn't be loaded. + * + *

+ * This is most likely the case when the config file isn't found or when the + * settings are corrupt. + *

+ * + * @author wprinz + */ +public class SettingsException extends PresentableException { + + /** + * SVUID. + */ + private static final long serialVersionUID = -99979541706943372L; + + /** + * @param message + */ + public SettingsException(String message) { + super(ErrorCode.SETTINGS_EXCEPTION, message); + } + + /** + * @param message + * @param cause + */ + public SettingsException(String message, Throwable cause) { + super(ErrorCode.SETTINGS_EXCEPTION, message, cause); + } + + public SettingsException(int errorCode, String message, Throwable cause) { + super(errorCode, message, cause); + } + + public SettingsException(int errorCode, String message) { + super(errorCode, message); + } + + public SettingsException(int errorCode, Throwable cause) { + super(errorCode, cause); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java new file mode 100644 index 0000000..e9e6af0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatorFactoryException.java @@ -0,0 +1,47 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatorFactoryException.java,v 1.1 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + +/** + * Exception coming out of the SignatorFactory. + * @author wprinz + */ +public class SignatorFactoryException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -4051644056058970435L; + + public SignatorFactoryException(String message) + { + super(ErrorCode.SETTINGS_EXCEPTION, message); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java new file mode 100644 index 0000000..5b0d458 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureException.java @@ -0,0 +1,79 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureException.java,v 1.1 2006/08/03 07:47:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + + +/** + * This exception is thrown by the processing a signature. + * + * @author wlackner + */ +public class SignatureException extends PresentableException { + + /** + * SVUID. + */ + private static final long serialVersionUID = 6387300820234118374L; + + /** + * @param error_code + * @param message + * @param cause + */ + public SignatureException(int error_code, String message, Throwable cause) + { + super(error_code, message, cause); + } + + /** + * @param error_code + * @param message + */ + public SignatureException(int error_code, String message) + { + super(error_code, message); + } + + /** + * @param error_code + * @param cause + */ + public SignatureException(int error_code, Throwable cause) + { + super(error_code, cause); + } + + /** + * @param error_code + * @param cause + */ + public SignatureException(PresentableException cause) + { + super(cause.getErrorCode(), cause); + } + + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java new file mode 100644 index 0000000..279d46f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/SignatureTypesException.java @@ -0,0 +1,75 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureTypesException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + +/** + * Exception for Signature Type problems. + * + * @author wprinz + */ +public class SignatureTypesException extends PresentableException +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7899273202684297943L; + + /** + * @param message + */ + public SignatureTypesException(String message) + { + super(ErrorCode.SIGNATURE_TYPES_EXCEPTION, message); + } + +// /** +// * @param message +// * @param cause +// */ +// public SignatureTypesException(String message, Throwable cause) +// { +// super(ErrorCode.SIGNATURE_TYPES_EXCEPTION, message, cause); +// } + + // /** + // * @param cause + // */ + // public SignatureTypesException(Throwable cause) + // { + // super(ErrorCode.SIGNATURE_TYPES_EXCEPTION, cause); + // } + + /** + * @param cause + */ + public SignatureTypesException(PresentableException cause) + { + super(cause.getErrorCode(), cause); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java new file mode 100644 index 0000000..8fbdda7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/exceptions/WebException.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: WebException.java,v 1.2 2006/08/25 17:10:34 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.exceptions; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; + + +/** + * Exception for web problems. + * @author wlackner + */ +public class WebException extends PresentableException { + + /** + * SVUID. + */ + private static final long serialVersionUID = 4329890155872840492L; + +// /** +// * @param error_code +// * @param message +// * @param cause +// */ +// public WebException(int error_code, String message, Throwable cause) +// { +// super(error_code, message, cause); +// } +// +// /** +// * @param error_code +// * @param message +// */ +// public WebException(int error_code, String message) +// { +// super(error_code, message); +// } +// + + /** + * @param error_code + * @param cause + */ + public WebException(Throwable cause) + { + super(ErrorCode.WEB_EXCEPTION, cause); + } + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java new file mode 100644 index 0000000..4076129 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundBlock.java @@ -0,0 +1,230 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: FoundBlock.java,v 1.2 2006/10/31 08:07:29 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.util.ArrayList; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Contains all the information about a found Block in text extracton. + * + *

+ * This is basically the ordered list of found captions. + *

+ * + * @author wprinz + */ +public class FoundBlock +{ + /** + * The ordered list of found keys. + */ + public List found_keys = null; + + /** + * The end index of the block. + */ + public int end_index = 0; + + /** + * The type of the block. + */ + public SignatureTypeDefinition std = null; + + /** + * Returns the first key of this block. + * + * @return Returns the first key of this block. + */ + public FoundKey getFirstKey() + { + return (FoundKey) this.found_keys.get(found_keys.size() - 1); + } + + /** + * Returns the last key of this block. + * + * @return Returns the last key of this block. + */ + public FoundKey getLastKey() + { + return (FoundKey) this.found_keys.get(0); + } + + /** + * Returns the size of this block. + * + *

+ * Note that this doesn't give the exact size of the block, but rather a value + * suirable for comparison. + *

+ * + * @return Returns the size of this block. + */ + public int getSize() + { + int size = getLastKey().start_index - getFirstKey().start_index; + return size; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "FoundBlock: std=" + this.std.getType() + ", #=" + this.found_keys.size() + ", size = " + getSize(); + } + + /** + * Tells, if this block is semantically equal to the other block. + * + * Two blocks are semantically equal, if all the required fields (except SIG_ID) have the + * same captions in the same order. + * + * @param other_block + * The other block. + * @return Returns true, of this block is semantically equal to the other one, + * false otherwise. + */ + public boolean isSemanticallyEqual(FoundBlock other_block) + { + return this.std.isSemanticallyEqual(other_block.std); + +// List this_keys = filterOutNonRequiredFoundKeys(filterOutSIG_ID(this.found_keys)); +// List other_keys = filterOutNonRequiredFoundKeys(filterOutSIG_ID(other_block.found_keys)); +// +// if (this_keys.size() != other_keys.size()) +// { +// return false; +// } +// +// for (int i = 0; i < this_keys.size(); i++) +// { +// FoundKey this_found_key = (FoundKey) this_keys.get(i); +// FoundKey other_found_key = (FoundKey) other_keys.get(i); +// +// if (!this_found_key.isSemanticallyEqual(other_found_key)) +// { +// return false; +// } +// } +// return true; + } + + /** + * Filters out all non required keys from the List of found keys. + * + * @param found_keys The List of found keys. + * + * @return Returns the subset List which contains only the required keys. + */ + protected static List filterOutNonRequiredFoundKeys (List found_keys) + { + List required_found_keys = new ArrayList(found_keys.size()); + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey this_found_key = (FoundKey) found_keys.get(i); + + if (!SignatureTypes.isRequiredKey(this_found_key.key)) + { + continue; + } + + required_found_keys.add(this_found_key); + } + return required_found_keys; + } + + /** + * Filters out a SIG_ID found key. + * @param found_keys The List of found keys. + * @return Returns the subset List which contains all keys but the SIG_ID. + */ + protected static List filterOutSIG_ID (List found_keys) + { + List nonsigid_found_keys = new ArrayList(found_keys.size()); + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey this_found_key = (FoundKey) found_keys.get(i); + + if (this_found_key.key.equals(SignatureTypes.SIG_ID)) + { + continue; + } + + nonsigid_found_keys.add(this_found_key); + } + return nonsigid_found_keys; + } + + /** + * Tells, if this block is strictly semantically equal to the other block. + * + * Two blocks are strictly semantically equal, if they contain the same keys with the + * same captions in the same order. + * + * @param other_block + * The other block. + * @return Returns true, of this block is semantically equal to the other one, + * false otherwise. + */ + public boolean isStrictlySemanticallyEqual(FoundBlock other_block) + { + if (this.found_keys.size() != other_block.found_keys.size()) + { + return false; + } + + for (int i = 0; i < this.found_keys.size(); i++) + { + FoundKey this_found_key = (FoundKey) this.found_keys.get(i); + FoundKey other_found_key = (FoundKey) other_block.found_keys.get(i); + + if (!this_found_key.isSemanticallyEqual(other_found_key)) + { + return false; + } + } + return true; + } + + + public FoundKey getDateFoundKey () + { + for (int i = 0; i < this.found_keys.size(); i++) + { + FoundKey found_key = (FoundKey) this.found_keys.get(i); + if (found_key.key.equals(SignatureTypes.SIG_DATE)) + { + return found_key; + } + } + throw new RuntimeException("There is no SIG_DATE in the list of found_keys. This must not happen."); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java new file mode 100644 index 0000000..b8e9609 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/FoundKey.java @@ -0,0 +1,104 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: FoundKey.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +/** + * Holds the information of one found key. + * @author wprinz + */ +public class FoundKey +{ + /** + * The type of the key. + */ + public String key = null; + + /** + * The caption of the key. + */ + public String caption = null; + + /** + * The start index of the caption in the text. + */ + public int start_index = -1; + + /** + * + * @param key The type of the key. + * @param caption The caption of the key. + * @param start_index The start index of the caption in the text. + */ + public FoundKey(String key, String caption, int start_index) + { + this.key = key; + this.caption = caption; + this.start_index = start_index; + } + + /** + * Returns the key. + * @return Returns the key. + */ + public String getKey() + { + return this.key; + } + + /** + * Returns the start_index. + * @return Returns the start_index. + */ + public int getStartIndex() + { + return this.start_index; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return this.key + "(" + this.caption + ")@" + this.start_index; + } + + /** + * Tells, if this FoundKey is semantically equal to the other FoundKey. + * + *

+ * Two FoundKeys are semantically equal if their key and caption are the same. + *

+ * + * @param other_found_key + * The other FoundKey. + * @return Returns true if the two keys are semantically equal. + */ + public boolean isSemanticallyEqual(FoundKey other_found_key) + { + return this.key.equals(other_found_key.key) && this.caption.equals(other_found_key.caption); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java new file mode 100644 index 0000000..5471d86 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignResult.java @@ -0,0 +1,104 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignResult.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.io.Serializable; + +/** + * This class holds the signed document, which is given by the mime type and the + * binary data. + * + * @author wprinz + */ +public class SignResult implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -6664489317508509973L; + + /** + * The mime type of the data specifying the type of the document. + */ + protected String mime_type = null; + + /** + * The binary data of the document. + */ + protected byte[] data = null; + + /** + * Constructor. + * + * @param document_mime_type + * The mime type of the data specifying the type of the document. + * @param document_data + * The binary data of the document. + */ + public SignResult(String document_mime_type, byte[] document_data) + { + if (document_mime_type == null || document_mime_type.length() == 0) + { + throw new IllegalArgumentException("Please provide a valid Mime Type for the SignResult. " + document_mime_type); + } + if (document_data == null) + { + throw new IllegalArgumentException("Please provide document data. " + document_data); + } + + this.mime_type = document_mime_type; + this.data = document_data; + } + + /** + * Returns the binary data. + * + * @return Returns the binary data. + */ + public byte[] getData() + { + return this.data; + } + + /** + * Returns the mime type. + * + * @return Returns the mime type. + */ + public String getMimeType() + { + return this.mime_type; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "SignResult:" + this.mime_type + "," + this.data.length; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java new file mode 100644 index 0000000..88a6ea1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Signator.java @@ -0,0 +1,93 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Signator.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; + +/** + * The basic interface for signator algorithms. + * + * @author wprinz + */ +public interface Signator +{ + /** + * Returns the PdfASID of this Connector. + * + *

+ * This should always return the MY_ID static field of the connector. Dont't + * forget to override this. + *

+ *

+ * Within connector code always use this method so that code reuse through + * derivation can take place correctly. + *

+ * + * @return Returns the PdfASID of this Connector. + */ + public PdfASID getMyId(); + + /** + * This is called before the data is sent to the connector. + * + * @param pdf + * The PDF document to be signed. + * @param signature_type + * The type/profile of the signature to apply. + * @param pos + * The table position. If null, the position is read from the + * profile, if this is null too, the position is computed. + * @param has_SIG_ID + * Tells the algorithm, id a SIG_ID field will be required after + * signing. Algorithms with fixed formatted signature blocks need to + * know this. + * @return Returns the IncrementalUpdateInformation. + * @throws PresentableException + * Forwarded exception. + */ + public IncrementalUpdateInformation prepareSign(PdfDataSource pdfDataSource, + String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException; + + /** + * This is called after the data has been signed by the connector. + * + *

+ * Replaces all the left out placeholders with their values retrieved from the + * signation process. + *

+ * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + * Forwarded exception. + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java new file mode 100644 index 0000000..ccb414d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/SignatorFactory.java @@ -0,0 +1,226 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatorFactory.java,v 1.2 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import at.gv.egiz.pdfas.impl.signator.textual.TextualSignator_1_2_0; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.SignatorFactoryException; +import at.knowcenter.wag.egov.egiz.framework.signators.BinarySignator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.signators.BinarySignator_1_1_0; +import at.knowcenter.wag.egov.egiz.framework.signators.DetachedSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.signators.DetachedfTextualSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.signators.TextualSignator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.signators.TextualSignator_1_1_0; + +/** + * This factory creates instances of Signator classes corresponding to the given + * PdfAS Algorithm IDs. + * + * @author wprinz + */ +public abstract class SignatorFactory +{ + /** + * The Vendor. + */ + public static final String VENDOR = "bka.gv.at"; //$NON-NLS-1$ + + /** + * The binary Signator algorithm. + */ + public static final String TYPE_BINARY = "binaer"; //$NON-NLS-1$ + + /** + * The textual Signator algorithm. + */ + public static final String TYPE_TEXTUAL = "text"; //$NON-NLS-1$ + + /** + * This signator is only for testing the framework. + */ + public static final String TYPE_TEST = "testalgo"; //$NON-NLS-1$ + + /** + * This signator is only for testing the framework. + */ + public static final String TYPE_DETACHED_TEXTUAL = "detachedtext"; //$NON-NLS-1$ + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_0_0 = "v1.0.0"; //$NON-NLS-1$ + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_1_0 = "v1.1.0"; //$NON-NLS-1$ + + /** + * This application's current algorithm versions. + */ + public static final String VERSION_1_2_0 = "v1.2.0"; //$NON-NLS-1$ + + + /** + * The most recent binary algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_BINARY_SIGNATOR_ID = BinarySignator_1_1_0.MY_ID; + + /** + * The most recent textual algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_TEXTUAL_SIGNATOR_ID = TextualSignator_1_2_0.MY_ID; + + /** + * The most recent test algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_DETACHED_SIGNATOR_ID = DetachedfTextualSignator_1_0_0.MY_ID; + + /** + * The most recent test algorithm this application provides. + */ + public static final PdfASID MOST_RECENT_DETACHEDTEXT_SIGNATOR_ID = DetachedfTextualSignator_1_0_0.MY_ID; + + + /** + * Creates a Signator for the given ID. + * + * @param id + * The ID of the Signator to be created. + * @return Returns the created Signator object. + * @throws SignatorFactoryException + * Thrown, if there is no appropriate Signator for the given ID. + */ + public static Signator createSignator(PdfASID id) throws SignatorFactoryException + { + if (!id.getVendor().equals(VENDOR)) + { + throw new SignatorFactoryException("The vendor '" + id.getVendor() + "' is unrecognized by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + if (id.getType().equals(TYPE_BINARY)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new BinarySignator_1_0_0(); + } + if (id.getVersion().equals(VERSION_1_1_0)) + { + return new BinarySignator_1_1_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + if (id.getType().equals(TYPE_TEXTUAL)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new TextualSignator_1_0_0(); + } + if (id.getVersion().equals(VERSION_1_1_0)) + { + return new TextualSignator_1_1_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + if (id.getType().equals(TYPE_TEST)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new DetachedSignator_1_0_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + if (id.getType().equals(TYPE_DETACHED_TEXTUAL)) + { + if (id.getVersion().equals(VERSION_1_0_0)) + { + return new DetachedfTextualSignator_1_0_0(); + } + + throw new SignatorFactoryException("The version '" + id.getVersion() + "' of type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + throw new SignatorFactoryException("The type '" + id.getType() + "' is not supported by this SignatorFactory. (id='" + id + "')"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * Creates the most recent signator the application provides for the given + * type. + * + * @param signator_type + * The type of the signator to be created (see the type field of + * PdfASID). + * @return Returns the created Signator instance. + * @throws SignatorFactoryException + * Thrown, if the type is unknown. + */ + public static Signator createMostRecentSignator(String signator_type) throws SignatorFactoryException + { + PdfASID id = null; + if (signator_type.equals(TYPE_BINARY)) + { + id = MOST_RECENT_BINARY_SIGNATOR_ID; + } + if (signator_type.equals(TYPE_TEXTUAL)) + { + id = MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + if (signator_type.equals(TYPE_TEST)) + { + id = MOST_RECENT_TEXTUAL_SIGNATOR_ID; + } + + if (id == null) + { + throw new SignatorFactoryException("The type '" + signator_type + "' is not supported by this SignatorFactory."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return createSignator(id); + } + + /** + * Returns the list of available Signator algorithms of this application. + * + *

+ * Use createMostRecentSignator to create the most recent signator for the + * type. + *

+ * + * @return Returns the list of available Signator algorithms of this + * application. + */ + public static String[] getAvailableTyes() + { + String[] types = new String[] { TYPE_BINARY, TYPE_TEXTUAL, TYPE_TEST }; + return types; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java new file mode 100644 index 0000000..0bab96f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/VerificationFilter.java @@ -0,0 +1,569 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: VerificationFilter.java,v 1.5 2006/10/31 08:07:20 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.impl.vfilter.VerificationFilterImpl; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.verificators.BinaryVerificator_1_0_0; +import at.knowcenter.wag.egov.egiz.framework.verificators.TextualVerificator_1_0_0; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.Placeholder; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.egov.egiz.pdf.TextualSignatureHolder; +import at.knowcenter.wag.exactparser.ParseDocument; +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference; +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; + + +/** + * This filter transforms an arbitrary input pdf into an ordered List of + * SignatureHolders for verification. + * + *

+ * The pdf document is parsed and the signature blocks (textual, binary, etc.) + * are extracted as verifyable SignatureHolder objects in the order they appear + * in the document. + *

+ * + * @deprecated use the new at.gv.egiz.framework instead + * + * @author wprinz + * @author amavriqi + */ +public class VerificationFilter +{ + public static final byte[] EGIZ_DICT_NAME = { 'E', 'G', 'I', 'Z', 'S', 'i', + 'g', 'D', 'i', 'c', 't' }; + + public static final byte[] EGIZ_KZ_NAME = { 'I', 'D' }; + + //tzefferer: flag for accepting post-sign modifications + public static final String ALLOW_POST_SIGN_MODIFICATIONS = "allow_post_sign_modifications"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(VerificationFilter.class); + + /** + * Default constructor. + */ + public VerificationFilter() + { + // empty block. + } + + /** + * Extracts the List of SignatureHolders from the given PDF document. + * + * @param pdf + * The PDF document. + * @return Returns the ordered List of SignatureHolder objects (the first + * signature will be at index 0) extracted from the document or an + * empty list, if none could be found. + * @throws PresentableException + */ + public List extractSignaturesFromPdf(final byte[] pdf) throws PresentableException + { + return extractSignaturesFromPdf(pdf, false); + } + + //@deprecated + public List extractSignaturesFromPdf(final byte[] pdf, boolean ignorePostSignModificationsRestriction) throws PresentableException + { + + // tzefferer: get allow_post_sign_modifications property from property file + SettingsReader settings = SettingsReader.getInstance(); + String allow_post_sign_mods = settings.getSetting(ALLOW_POST_SIGN_MODIFICATIONS, "false"); + boolean supressException = "true".equalsIgnoreCase(settings.getSetting(VerificationFilterImpl.SUPRESS_EXCEPTION_WHEN_LAST_UIBLOCK_IS_NO_SIGNATURE, "false")); + + List holders = new ArrayList(); + + List blocks = null; + try + { + blocks = ParseDocument.parseDocument(pdf); + } + catch (Exception e) + { + logger_.debug("Error while parsing Document.", e); + throw new PDFDocumentException(201, e); + } + +// for (int i = 0; i < blocks.size(); i++) +// { +// FooterParseResult bpr = (FooterParseResult) blocks.get(i); +// // logger_.debug("block[" + i + "] from " + bpr.start_index + " to +// // " + bpr.next_index); +// } + + unrollLinearization(blocks); + + boolean signature_block_detected = false; + + for (int i = 0; i < blocks.size(); i++) + { + boolean current_block_contains_signature = false; + FooterParseResult bpr = (FooterParseResult) blocks.get(i); + + int prev_end = 0; + if (i > 0) + { + FooterParseResult prev_bpr = (FooterParseResult) blocks.get(i - 1); + prev_end = prev_bpr.next_index; + } + + // logger_.debug("block from " + prev_end + " to " + + // bpr.next_index); + + if (containsEGIZDict(pdf, bpr)) + { + logger_.debug("Parsing Binary Sig:"); + + PdfASID kz = extractKZFromEGIZBlock(pdf, bpr); + + if (!kz.toString().equals(BinaryVerificator_1_0_0.MY_ID.toString())) + { + logger_.debug("Warning: Binary Kennzeichnung not recognized:" + kz.toString()); + } + + Verificator verificator = new BinaryVerificator_1_0_0(); + List binary_holders = verificator.parseBlock(pdf, bpr, prev_end); + + holders.addAll(binary_holders); + + // tzefferer: check if signatures have been detected in current block + if(binary_holders.size() > 0) + { + signature_block_detected = true; + current_block_contains_signature = true; + } + + logger_.debug(":Parsing Binary Sig END - holders.size = " + holders.size()); + } + else + { + // TODO: make better - already deprecated + //amavriqi: skip checking for old sigs becouse of performance issues + String old_text_sigs = SettingsReader.getInstance().getSetting("check_old_textual_sigs", "false"); + + //amavriqi: if old textual signatures not checked for then + // no need to check Incremental Block 0 + if(old_text_sigs.equalsIgnoreCase("false") && (prev_end == 0)) + { + continue; + } + logger_.debug("Extracting text for: " + prev_end + " to " + bpr.next_index); + + Verificator verificator = new TextualVerificator_1_0_0(); + List text_holders = verificator.parseBlock(pdf, bpr, prev_end); + logger_.debug("text_holders = " + text_holders.size()); + + // tzefferer: check if signatures have been detected in current block + if(text_holders.size() > 0) + { + signature_block_detected = true; + current_block_contains_signature = true; + } + + // TODO: make better - already deprecated + //amavriqi: only if old textual signatures are checked for + if(old_text_sigs.equalsIgnoreCase("true")){ + if (prev_end == 0) + { + String rest_text = null; + if (!text_holders.isEmpty()) + { + TextualSignatureHolder first_holder = (TextualSignatureHolder) text_holders.get(0); + rest_text = first_holder.getSignedText(); + } + else + { + //a.m. + logger_.debug("Incemental block" + prev_end + " and there are " + text_holders.size() + " text holders"); + logger_.debug("Checking for older textual Signatures"); + logger_.debug("Extracting text to " + bpr.next_index); + rest_text = PdfAS.extractNormalizedTextTextual(pdf, bpr.next_index); + } + + List old_holders = PdfAS.extractSignatureHoldersTextual(rest_text, true); + + logger_.debug("Found old holders = " + old_holders.size()); + if (!old_holders.isEmpty()) + { + // there must be only one old holder. + holders.add(0, old_holders.get(0)); + } + } + } + if (!text_holders.isEmpty()) + { + List actual_text_holders = throwOutBinHolders(text_holders); + holders.addAll(actual_text_holders); + } + + logger_.debug(":Extracting tex END - holders.size = " + holders.size()); + } + + // tzefferer: check if illegal modifications have been performed on the document after performing a signation + if (!("true".equalsIgnoreCase(allow_post_sign_mods)) && !ignorePostSignModificationsRestriction) + { + if (signature_block_detected && !current_block_contains_signature) + { + if (!supressException) { + throw new PDFDocumentException(ErrorCode.MODIFIED_AFTER_SIGNATION, "Das Dokument wurde nach erfolgter Signierung verändert."); + } + + } + } + } + + for (int i = 0; i < holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) holders.get(i); + + PdfASID kz = holder.getSignatureObject().getKZ(); + if (kz != null) + { + checkKZ(kz); + } + } + + return holders; + } + + /** + * Checks, if the given KZ is recognized by this application or logs a warning if it isn't. + * @param kz The Kennzeichnung. + */ + protected void checkKZ (PdfASID kz) + { + if (!kz.getVendor().equals(SignatorFactory.VENDOR)) + { + logger_.warn("The vendor " + kz.getVendor() + " isn't known by this application."); + } + if (!kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + logger_.warn("The version " + kz.getVersion() + " istn't supported by this application. This might cause problems."); + } + } + + /** + * Throws out SignatureHolders with a binary KZ. + * + * @param text_holders + * The List of SignatureHolder objects. + * @return Returns the List of SignatureHolder objects, where no object has + * binary KZ. + */ + private List throwOutBinHolders(List text_holders) + { + List actual_text_holders = new ArrayList(); + for (int i = 0; i < text_holders.size(); i++) + { + SignatureHolder sh = (SignatureHolder) text_holders.get(i); + PdfASID kz = null; + try + { + kz = sh.getSignatureObject().getKZ(); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + if (kz != null && kz.getType().equals(SignatorFactory.TYPE_BINARY)) + { + logger_.info("Throwing out binary signature: " + kz); + continue; + } + actual_text_holders.add(sh); + } + return actual_text_holders; + } + + /** + * Removes the linearization footer from the list of update blocks. + * + * @param blocks + * The list of FooterParseResult objects in \prev order. + */ + protected void unrollLinearization(List blocks) + { + int linearization_index = -1; + for (int i = 0; i < blocks.size(); i++) + { + FooterParseResult bpr = (FooterParseResult) blocks.get(i); + + if (bpr.sxpr.xref_index == 0) + { + if (linearization_index >= 0) + { + throw new RuntimeException("There is more than one linearization block! index = " + i); + } + linearization_index = i; + } + } + + if (linearization_index >= 0) + { + // logger_.debug("The document is linearized - unrolling + // linearization block " + linearization_index); + blocks.remove(linearization_index); + } + } + + /** + * Extracts the List of SignatureHolders from the given plain text document. + * + *

+ * Note that this can only extract text signatures. + *

+ * + * @param raw_text + * The plain text document. + * @return Returns the ordered List of SignatureHolder objects (the first + * signature will be at index 0) extracted from the document or an + * empty list, if none could be found. + * @throws SignatureException + * @throws PDFDocumentException + * @throws SignatureTypesException + * @throws NormalizeException + */ + public List extractSignaturesFromPlainText(final String raw_text) throws PDFDocumentException, SignatureException, SignatureTypesException, NormalizeException + { + String normalized_text = PdfAS.normalizeText(raw_text); + + //List text_holders = PdfAS.extractSignatureHoldersTextual(normalized_text, false); + List text_holders = AbsoluteTextSignature.extractSignatureHoldersFromText(normalized_text); + + String rest_text = normalized_text; + if (!text_holders.isEmpty()) + { + TextualSignatureHolder holder = (TextualSignatureHolder) text_holders.get(0); + rest_text = holder.getSignedText(); + } + + List old_holders = PdfAS.extractSignatureHoldersTextual(rest_text, true); + if (!old_holders.isEmpty()) + { + text_holders.addAll(0, old_holders); + } + + List actual_text_holders = throwOutBinHolders(text_holders); + + return actual_text_holders; + } + + /** + * Tells, if the given incremental update block contains a binary signature. + * + *

+ * According to definition, if a block is a binary block, it must/cannot + * contain other signatures than this one. + *

+ * + * @param block + * The incremental update block. + * @return Returns true, if this block is a binary signature block, false + * otherwise. + */ + protected boolean containsEGIZDict(final byte[] pdf, + final FooterParseResult block) + { + int dict_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, EGIZ_DICT_NAME); + if (dict_index <= 0) + { + return false; + } + + return true; + } + + /** + * Extracts the PDF AS ID of the egiz block. + * + * @param pdf + * The pdf. + * @param block + * The IU block. + * @return Returns the extracted PDF AS ID. + * @throws PDFDocumentException + * Forwarded exception. + * @throws InvalidIDException + * Forwarded exception. + */ + protected PdfASID extractKZFromEGIZBlock(final byte[] pdf, + final FooterParseResult block) throws PDFDocumentException, InvalidIDException + { + int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, VerificationFilter.EGIZ_DICT_NAME); + if (egiz_index < 0) + { + throw new PDFDocumentException(301, "egiz_index = " + egiz_index); + } + + IndirectObjectReferenceParseResult egiz_dict_iorpr = (IndirectObjectReferenceParseResult) block.tpr.dpr.values.get(egiz_index); + // logger_.debug("egiz_dict_ir = " + egiz_dict_iorpr.ior.object_number + // + " " + egiz_dict_iorpr.ior.generation_number); + + IndirectObjectReference ior = egiz_dict_iorpr.ior; + + final int egiz_dict_offset = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(block.xpr, ior); + // logger_.debug("egiz_dict_offset = " + egiz_dict_offset); + + ObjectParseResult obj = PDFUtils.parseObject(pdf, egiz_dict_offset); + DictionaryParseResult egiz_dict = (DictionaryParseResult) obj.object; + + int kz_index = PDFUtils.indexOfName(pdf, egiz_dict.names, EGIZ_KZ_NAME); + if (kz_index < 0) + { + throw new PDFDocumentException(301, "kz_index = " + kz_index); + } + ArrayParseResult kz_apr = (ArrayParseResult) egiz_dict.values.get(kz_index); + + String kz_string = restoreKZ(pdf, kz_apr); + PdfASID kz = new PdfASID(kz_string); + + return kz; + } + + /** + * Restores the Kennzeichnung String from an Array. + * + * @param pdf + * The PDF. + * @param kz_apr + * The Array, as parsed from the EGIZ Dict. + * @return Returns the restored KZ. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static String restoreKZ(byte[] pdf, ArrayParseResult kz_apr) throws PDFDocumentException + { + try + { + List partition = new ArrayList(); + + for (int i = 0; i < kz_apr.elements.size() / 2; i++) + { + NumberParseResult start_npr = (NumberParseResult) kz_apr.elements.get(i * 2); + NumberParseResult length_npr = (NumberParseResult) kz_apr.elements.get(i * 2 + 1); + + StringInfo si = new StringInfo(); + si.string_start = start_npr.number; + si.string_length = length_npr.number; + + partition.add(si); + } + + String KZ = Placeholder.reconstructStringFromPartition(pdf, partition, BinarySignature.ENCODING_WIN); + return KZ; + } + catch (IOException e1) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e1); + } + } + + + protected static void printFoundHolders (String list_caption, List found_holders, PrintStream writer) + { + writer.println("------------------------------------"); + writer.println(list_caption + ": #=" + found_holders.size()); + + for (int i = 0; i < found_holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) found_holders.get(i); + String kz = "invalid"; + try + { + PdfASID kz_id = holder.getSignatureObject().getKZ(); + if (kz_id == null) + { + kz = "old signature"; + } + else + { + kz = kz_id.toString(); + } + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + writer.println(" holder[" + i + "]: " + holder.getSignatureObject().getSignationType() + ", KZ=" + kz); + } + + writer.println(":" + list_caption); + writer.println("------------------------------------"); + + } + + // TODO old code - remove +// public static void main(String[] args) throws IOException, PresentableException +// { +// SettingsReader.initializeForCommandLine(); +// +// File in = new File(args[0]); +// FileInputStream fis = new FileInputStream(in); +// byte[] pdf = new byte[(int) in.length()]; +// fis.read(pdf); +// fis.close(); +// +// String text = PdfAS.extractNormalizedTextTextual(pdf, pdf.length);; +// +// VerificationFilter vf = new VerificationFilter(); +// //List found = vf.extractSignaturesFromPdf(pdf); +// +// List found = vf.extractSignaturesFromPlainText(text); +// +// printFoundHolders("Final Holders", found, System.out); +// } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java new file mode 100644 index 0000000..5a8228e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/Verificator.java @@ -0,0 +1,62 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Verificator.java,v 1.1 2006/08/25 17:07:21 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework; + +import java.util.List; + +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + + +/** + * Given an Incremental Update Block and the corresponding PDF, a verificator + * extracts all Signatures of its type and returns them as valitatable + * SignatureHolders. + * + * @deprecated replaced by the one in framework + * + * @author wprinz + */ +public interface Verificator +{ + /** + * Parses the given document/Block for signatures of this type. + * + * @param pdf + * The whole pdf document. A Verificator must only access the + * document up to its given block (block.next_index) and must not + * modify any byte in the pdf array. + * @param block + * The incremental update block. + * @param start_of_whole_block + * The start of the incremental update block (the end of the previous + * block) - If 0, this is the first block (the original Document). + * @return Returns the List of SignatureHolder objects found for this block. + */ + public List parseBlock(final byte[] pdf, final FooterParseResult block, + int start_of_whole_block) throws PresentableException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java new file mode 100644 index 0000000..46245d2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_0_0.java @@ -0,0 +1,285 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinarySignator_1_0_0.java,v 1.1 2006/08/25 17:07:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.signator.IncrementalUpdateHelper; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; +import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureFieldDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +import com.lowagie.text.pdf.PdfPTable; + +/** + * Signs the document binary. + * + *

+ * In prepareSign, an Incremental Update is created that contains the Signature + * block and the egiz dictionary. For formatting the layout, variable values are + * filled with placeholders. After the layout has been fixed, all variable + * fields (all holes in the byte ranges) are replaced with 0. This document is + * then base64 encoded and signed. + *

+ *

+ * In finishSign, the variable fields (values, /Cert) are replaced with the + * values according to the encoding. + *

+ * + * @deprecated moved to new-framework + * + * @author wprinz + */ +public class BinarySignator_1_0_0 implements Signator +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * Default constructor. + */ + public BinarySignator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(PdfDataSource pdf, String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException + { + try + { + SignatureObject signature_object = PdfAS.createSignatureObjectFromType(signature_type); + signature_object.fillValues((char) BinarySignature.LAYOUT_PLACEHOLDER, has_SIG_ID, false); + + signature_object.setKZ(getMyId()); + + PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(signature_object); + + PositioningInstruction pi = PdfAS.determineTablePositioning(pos, signature_type, pdf, pdf_table); + + List all_field_definitions = signature_object.getSignatureTypeDefinition().getFieldDefinitions(); + List variable_field_definitions = new ArrayList(); + for (int i = 0; i < all_field_definitions.size(); i++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) all_field_definitions.get(i); + if (sfd.placeholder_length > 0) + { + if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false) + { + continue; + } + variable_field_definitions.add(sfd); + } + } + + //check if signature block is invisible, and if so and if also signature block is positioned + //on a new page, prevent pdf-as to do that, because why should make a new page just for an invisible block + //added by rpiazzi + if (signature_object.getSignatureTypeDefinition().getInvisibleFieldDefinitions().size()==SignatureTypes.REQUIRED_SIG_KEYS.length) { + if (pi.isMakeNewPage()) { + int pageNumber = pi.getPage(); + pi = new PositioningInstruction(false, pageNumber-1, 0, 0); + } + } + //end added + + IncrementalUpdateInformation iui = IncrementalUpdateHelper.writeIncrementalUpdate(pdf, pdf_table, signature_type, pi, variable_field_definitions, all_field_definitions, null, null, null); + + String temp_string = iui.temp_ir_number + " " + iui.temp_ir_generation + " obj"; //$NON-NLS-1$//$NON-NLS-2$ + byte[] temp_bytes = temp_string.getBytes("US-ASCII"); //$NON-NLS-1$ + int temp_start = ByteArrayUtils.lastIndexOf(iui.signed_pdf, temp_bytes); + byte[] stream_bytes = new byte[] { '>', '>', 's', 't', 'r', 'e', 'a', 'm', 0x0A }; + int stream_start = ByteArrayUtils.indexOf(iui.signed_pdf, temp_start, stream_bytes); + iui.content_stream_start = stream_start + stream_bytes.length; + + // update the stream indices + Iterator it = iui.replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + + Iterator sit = ri.replaces.iterator(); + while (sit.hasNext()) + { + StringInfo si = (StringInfo) sit.next(); + si.string_start += iui.content_stream_start; + } + } + // update KZ list indices: + it = iui.kz_list.iterator(); + while (it.hasNext()) + { + StringInfo si = (StringInfo) it.next(); + si.string_start += iui.content_stream_start; + } + + BinarySignature.markByteRanges(iui); + + // byte [] old_signed_pdf = iui.signed_pdf; + iui.signed_pdf = BinarySignature.prepareDataToSign(iui.signed_pdf, iui.byte_ranges); + + reduceToIUBlock(iui); + + iui.signature_data = formSignatureData(iui); + + return iui; + + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new PDFDocumentException(201, e); + } + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException + { + restoreSignedPdf(iui); + + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.BINARY_ID); + fillReplacesWithValues(iui); + + BinarySignature.replaceCertificate(iui); + BinarySignature.replacePlaceholders(iui); + + SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, iui.signed_pdf); + return sign_result; + } + + /** + * Reads the signature values from the signed signature object and fills the + * corresponding value in the Replaces array. + * + * @param iui + * The IncrementalUpdateInformation. + */ + protected void fillReplacesWithValues(IncrementalUpdateInformation iui) + { + Iterator it = iui.replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + + ri.value = iui.signed_signature_object.retrieveStringValue(ri.sfd.field_name); + } + } + + protected void reduceToIUBlock(IncrementalUpdateInformation iui) + { + byte[] iu_block = new byte[iui.signed_pdf.length - iui.original_document.getLength()]; + System.arraycopy(iui.signed_pdf, iui.original_document.getLength(), iu_block, 0, iu_block.length); + + iui.signed_pdf = null; + iui.sign_iui_block = iu_block; + } + + protected void restoreSignedPdf(IncrementalUpdateInformation iui) + { + iui.signed_pdf = new byte[iui.original_document.getLength() + iui.sign_iui_block.length]; + + try + { + InputStream is = iui.original_document.createInputStream(); + is.read(iui.signed_pdf, 0, iui.original_document.getLength()); + is.close(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + + System.arraycopy(iui.sign_iui_block, 0, iui.signed_pdf, iui.original_document.getLength(), iui.sign_iui_block.length); + } + + /** + * Forms the SignatureData to be used for signing. + * + * @param iui + * The IncrementalUpdateInformation. + * @return Returns the SignatureData to be used for signing. + */ + protected SignatureData formSignatureData(IncrementalUpdateInformation iui) + { + // String document_text = + // BinarySignature.retrieveSignableTextFromData(iui.signed_pdf, + // iui.signed_pdf.length); // signed_pdf.length); + // + // byte[] data; + // try + // { + // data = document_text.getBytes("UTF-8"); //$NON-NLS-1$ + // } + // catch (UnsupportedEncodingException e) + // { + // throw new RuntimeException("Very strange: UTF-8 character encoding not + // supported.", e); //$NON-NLS-1$ + // } + DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, iui.sign_iui_block); + SignatureData signature_data = new SignatureDataImpl(ds, PdfAS.PDF_MIME_TYPE); + + return signature_data; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_1_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_1_0.java new file mode 100644 index 0000000..2cb99c2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/BinarySignator_1_1_0.java @@ -0,0 +1,83 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinarySignator_1_0_0.java,v 1.1 2006/08/25 17:07:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import java.io.ByteArrayInputStream; + +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.input.CompoundPdfDataSourceImpl; +import at.gv.egiz.pdfas.framework.input.DataSource; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; + +/** + * Signs the document binary. + * + *

+ * This just differs from version 1.0.0 in the fact that the signature data is + * the actual binary PDF instead of a Base64 encoding. + *

+ * + * @see BinarySignator_1_0_0 + * + * @deprecated moved to nc-framework + * + * @author wprinz + */ +public class BinarySignator_1_1_0 extends BinarySignator_1_0_0 +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_1_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * Overrides the SignatureData generation of the BinarySignator 1.0.0 so that + * the SignatureData is the actual binary PDF instead of a Base64 encoding. + * + * @see at.knowcenter.wag.egov.egiz.framework.signators.BinarySignator_1_0_0#formSignatureData(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + */ + protected SignatureData formSignatureData(IncrementalUpdateInformation iui) + { + DataSource ds = new CompoundPdfDataSourceImpl(iui.original_document, iui.sign_iui_block); + SignatureData signature_data = new SignatureDataImpl(ds, PdfAS.PDF_MIME_TYPE); + + return signature_data; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java new file mode 100644 index 0000000..9ffeefe --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedSignator_1_0_0.java @@ -0,0 +1,125 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: DetachedSignator_1_0_0.java,v 1.1 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; + +/** + * This signator is just for testing purposes. + * + *

+ * It doesn't modify the original document, but simply returns the XML signature + * response as the signed document. + *

+ * + * @author wprinz + */ +public class DetachedSignator_1_0_0 implements Signator +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEST, SignatorFactory.VERSION_1_0_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * The Mime Type. + */ + public static final String MIME_TYPE = "text/xml"; //$NON-NLS-1$ + + /** + * Default constructor. + */ + public DetachedSignator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(PdfDataSource pdf, + String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException + { + IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + iui.original_document = pdf; + iui.signature_type = signature_type; + iui.pos = pos; + + String document_text = PdfAS.extractNormalizedTextTextual(pdf); + iui.nonTextObjectInfos = PdfAS.extractNonTextualObjects(pdf); + // logger_.debug("signed_text = " + document_text); + + DataSource ds = new TextDataSourceImpl(document_text); + iui.signature_data = new SignatureDataImpl(ds, MIME_TYPE, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ + + return iui; + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException + { + try + { + String response = iui.signed_signature_object.response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + byte[] response_bytes = response.getBytes("UTF-8"); //$NON-NLS-1$ + + SignResult sign_result = new SignResult(MIME_TYPE, response_bytes); + return sign_result; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new PDFDocumentException(300, e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java new file mode 100644 index 0000000..1559246 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/DetachedfTextualSignator_1_0_0.java @@ -0,0 +1,133 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import java.io.UnsupportedEncodingException; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; + +/** + * Signs a document textually. + * + *

+ * In prepareSign, the document text is extracted and normalized. + *

+ *

+ * In finishSign, the signed SignatureObject is transformed into a Signature + * block, which is then written as an Incremental Update. + *

+ * + * @author wprinz + */ +public class DetachedfTextualSignator_1_0_0 implements Signator +{ + /** + * The Mime Type. + */ + public static final String MIME_TYPE = "text/xml"; //$NON-NLS-1$ + + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_DETACHED_TEXTUAL, SignatorFactory.VERSION_1_0_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * Default constructor. + */ + public DetachedfTextualSignator_1_0_0() + { + // Default constructor. + } + + /** + *

+ * The parameter has_SIG_ID is not used by this Signator because it doesn't + * pre-format the signature block. + *

+ * + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(PdfDataSource pdf, + String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException + { + IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + iui.original_document = pdf; + iui.signature_type = signature_type; + iui.pos = pos; + + String document_text = PdfAS.extractNormalizedTextTextual(pdf, "cp1252"); + iui.nonTextObjectInfos = PdfAS.extractNonTextualObjects(pdf); + // logger_.debug("signed_text = " + document_text); + + DataSource ds = new TextDataSourceImpl(document_text); + iui.signature_data = new SignatureDataImpl(ds, MIME_TYPE, "UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$ + + return iui; + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException + { + try + { + String response = iui.signed_signature_object.response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + byte[] response_bytes = response.getBytes("UTF-8"); //$NON-NLS-1$ + + SignResult sign_result = new SignResult(MIME_TYPE, response_bytes); + return sign_result; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new PDFDocumentException(300, e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java new file mode 100644 index 0000000..ff92cd1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_0_0.java @@ -0,0 +1,136 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import java.util.ArrayList; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.gv.egiz.pdfas.impl.signator.IncrementalUpdateHelper; +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.SignResult; +import at.knowcenter.wag.egov.egiz.framework.Signator; +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.pdf.TextualSignature; +import at.knowcenter.wag.egov.egiz.sig.SignatureDataImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.SignatureObjectHelper; + +import com.lowagie.text.pdf.PdfPTable; + +/** + * Signs a document textually. + * + *

+ * In prepareSign, the document text is extracted and normalized. + *

+ *

+ * In finishSign, the signed SignatureObject is transformed into a Signature + * block, which is then written as an Incremental Update. + *

+ * + * @deprecated moved to new-framework + * + * @author wprinz + */ +public class TextualSignator_1_0_0 implements Signator +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_0_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + + /** + * Default constructor. + */ + public TextualSignator_1_0_0() + { + // Default constructor. + } + + /** + *

+ * The parameter has_SIG_ID is not used by this Signator because it doesn't + * pre-format the signature block. + *

+ * + * @see at.knowcenter.wag.egov.egiz.framework.Signator#prepareSign(byte[], + * String, TablePos, boolean) + */ + public IncrementalUpdateInformation prepareSign(PdfDataSource pdf, + String signature_type, TablePos pos, boolean has_SIG_ID) throws PresentableException + { + IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + iui.original_document = pdf; + iui.signature_type = signature_type; + iui.pos = pos; + + String document_text = PdfAS.extractNormalizedTextTextual(pdf); + iui.nonTextObjectInfos = PdfAS.extractNonTextualObjects(pdf); + // logger_.debug("signed_text = " + document_text); + + DataSource ds = new TextDataSourceImpl(document_text); + iui.signature_data = new SignatureDataImpl(ds, "text/plain", "UTF-8"); + + return iui; + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#finishSign(at.knowcenter.wag.egov.egiz.pdf.IncrementalUpdateInformation) + */ + public SignResult finishSign(IncrementalUpdateInformation iui) throws PresentableException + { + // PdfAS.prefixID(iui.signed_signature_object, PdfAS.TEXT_ID); + + iui.signed_signature_object.kz = getMyId().toString(); + + SignatureObject so = SignatureObjectHelper.convertSignSignatureObjectToSignatureObject(iui.signed_signature_object, iui.signature_type); + + PdfPTable pdf_table = PdfAS.createPdfPTableFromSignatureObject(so); + + PositioningInstruction pi = PdfAS.determineTablePositioning(iui.pos, iui.signature_type, iui.original_document, pdf_table); + + IncrementalUpdateInformation signed_iui = IncrementalUpdateHelper.writeIncrementalUpdate(iui.original_document, pdf_table, iui.signature_type, pi, null, null, null, null, null); + + SignResult sign_result = new SignResult(PdfAS.PDF_MIME_TYPE, signed_iui.signed_pdf); + return sign_result; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_1_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_1_0.java new file mode 100644 index 0000000..42a5856 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/signators/TextualSignator_1_1_0.java @@ -0,0 +1,53 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignator_1_0_0.java,v 1.3 2006/10/31 08:07:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.signators; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * Signs a document textually. + * + * @see TextualSignator_1_0_0 + * + * @author wprinz + */ +public class TextualSignator_1_1_0 extends TextualSignator_1_0_0 +{ + /** + * The Pdf-AS ID of this Signator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_1_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Signator#getMyId() + */ + public PdfASID getMyId() + { + return MY_ID; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java new file mode 100644 index 0000000..1ec1568 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_0_0.java @@ -0,0 +1,396 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinaryVerificator_1_0_0.java,v 1.3 2006/10/11 08:03:22 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.verificators; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.impl.vfilter.helper.VerificationFilterBinaryHelper; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.framework.VerificationFilter; +import at.knowcenter.wag.egov.egiz.framework.Verificator; +import at.knowcenter.wag.egov.egiz.pdf.BinaryBlockInfo; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignature; +import at.knowcenter.wag.egov.egiz.pdf.BinarySignatureHolder; +import at.knowcenter.wag.egov.egiz.pdf.Placeholder; +import at.knowcenter.wag.egov.egiz.pdf.ReplaceInfo; +import at.knowcenter.wag.egov.egiz.pdf.StringInfo; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference; +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NameParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ParseResult; + +/** + * The BinaryVerificator parses the EGIT Dictionary and extracts the signature + * holder from it. + * + * @deprecated moved to the new framework + * + * @author wprinz + */ +public class BinaryVerificator_1_0_0 implements Verificator +{ + /** + * The Pdf-AS ID of this Verificator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_0_0); + + /** + * Use this to override the MY_ID field. + * + * @return Returns the Id of this Verificator. + */ + protected PdfASID getMyId() + { + return MY_ID; + } + + /** + * The /ODS key in the EGIZ Dict. + */ + public static final byte[] EGIZ_ODS_NAME = new byte[] { 'O', 'D', 'S' }; + + /** + * The /ID key in the EGIZ Dict. + */ + public static final byte[] EGIZ_KZ_NAME = VerificationFilter.EGIZ_KZ_NAME; + + /** + * The /ByteRange key in the EGIZ Dict. + */ + public static final byte[] EGIZ_BYTE_RANGE_NAME = new byte[] { 'B', 'y', 't', 'e', 'R', 'a', 'n', 'g', 'e' }; + + /** + * The /replaces key in the EGIZ Dict. + */ + public static final byte[] EGIZ_REPLACES_NAME = new byte[] { 'r', 'e', 'p', 'l', 'a', 'c', 'e', 's' }; + + /** + * The /encodings key in the EGIZ Dict. + */ + public static final byte[] EGIZ_ENCODINGS_NAME = new byte[] { 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g', 's' }; + + /** + * The /Cert key in the EGIZ Dict. + */ + public static final byte[] EGIZ_CERT_NAME = new byte[] { 'C', 'e', 'r', 't' }; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BinaryVerificator_1_0_0.class); + + /** + * Default constructor. + */ + public BinaryVerificator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Verificator#parseBlock(byte[], + * at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(byte[] pdf, FooterParseResult block, int start_of_whole_block) throws PresentableException + { + int egiz_index = PDFUtils.indexOfName(pdf, block.tpr.dpr.names, VerificationFilter.EGIZ_DICT_NAME); + if (egiz_index < 0) + { + throw new PDFDocumentException(ErrorCode.COULDNT_VERIFY, "egiz_index = " + egiz_index); + } + + IndirectObjectReferenceParseResult egiz_dict_iorpr = (IndirectObjectReferenceParseResult) block.tpr.dpr.values.get(egiz_index); + + IndirectObjectReference ior = egiz_dict_iorpr.ior; + + final int egiz_dict_offset = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(block.xpr, ior); + + ObjectParseResult obj = PDFUtils.parseObject(pdf, egiz_dict_offset); + DictionaryParseResult egiz_dict = (DictionaryParseResult) obj.object; + + NumberParseResult ods_npr = (NumberParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_ODS_NAME); + + ArrayParseResult kz_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_KZ_NAME); + PdfASID kz = null; +// String kz_string = VerificationFilter.restoreKZ(pdf, kz_apr); + String kz_string = VerificationFilterBinaryHelper.restoreKZ(pdf, kz_apr); + kz = new PdfASID(kz_string); + if (!kz_string.equals(getMyId().toString())) + { + logger_.warn("Warning: Kennzeichnung not recognized:" + kz_string); + } + + ArrayParseResult byte_ranges_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_BYTE_RANGE_NAME); + + ArrayParseResult replaces_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_REPLACES_NAME); + + ArrayParseResult encodings_apr = (ArrayParseResult) getRequiredValueOfKey(pdf, egiz_dict, EGIZ_ENCODINGS_NAME); + + ArrayParseResult cert_apr = (ArrayParseResult) getValueOfKey(pdf, egiz_dict, EGIZ_CERT_NAME); + byte[] cert = null; + if (cert_apr != null && !cert_apr.elements.isEmpty()) + { + LiteralStringParseResult lspr = (LiteralStringParseResult) cert_apr.elements.get(0); + int str_length = lspr.content_end_index - lspr.content_start_index; + byte[] encoded = new byte[str_length]; + System.arraycopy(pdf, lspr.content_start_index, encoded, 0, encoded.length); + + cert = Placeholder.unescapePDFString(encoded); + } + + int num_byte_ranges = byte_ranges_apr.elements.size() / 2; + List byte_ranges = new ArrayList(); + for (int i = 0; i < num_byte_ranges; i++) + { + NumberParseResult start_npr = (NumberParseResult) byte_ranges_apr.elements.get(2 * i); + NumberParseResult length_npr = (NumberParseResult) byte_ranges_apr.elements.get(2 * i + 1); + + StringInfo si = new StringInfo(); + si.string_start = start_npr.number; + si.string_length = length_npr.number; + byte_ranges.add(si); + } + + StringInfo sis[] = new StringInfo[num_byte_ranges - 1]; + for (int i = 0; i < num_byte_ranges - 1; i++) + { + StringInfo prev = (StringInfo) byte_ranges.get(i); + StringInfo next = (StringInfo) byte_ranges.get(i + 1); + + StringInfo hole = new StringInfo(); + hole.string_start = prev.string_start + prev.string_length; + hole.string_length = next.string_start - hole.string_start; + + sis[i] = hole; + } + + int n = replaces_apr.elements.size(); + byte[][] brevs = new byte[n][]; + for (int i = 0; i < n; i++) + { + NameParseResult lspr = (NameParseResult) replaces_apr.elements.get(i); + + byte[] brev = new byte[3]; + System.arraycopy(pdf, lspr.name_start_index, brev, 0, brev.length); + + brevs[i] = brev; // SignatureTypes.convertBrevToType(brev); + } + + n = encodings_apr.elements.size(); + byte[][] encodings = new byte[n][]; + for (int i = 0; i < n; i++) + { + NameParseResult lspr = (NameParseResult) encodings_apr.elements.get(i); + + byte[] enc = new byte[3]; + System.arraycopy(pdf, lspr.name_start_index, enc, 0, enc.length); + encodings[i] = enc; + } + + BinaryBlockInfo bbi = new BinaryBlockInfo(); + bbi.replaces = BinarySignature.reconstructReplaces(pdf, brevs, sis, encodings); + bbi.signed_size = ods_npr.number; + + // BinaryBlockInfo bbi = BinarySignature.retrieveEgizDictInformation(pdf, + // ior.object_number, ior.generation_number, egiz_dict_offset); + + // byte[] original_pdf = BinarySignature.restoreEgizDictInformation(pdf, + // bbi); + + byte[] signed_pdf = BinarySignature.prepareDataToSign(pdf, byte_ranges); + // String signed_text = + // BinarySignature.retrieveSignableTextFromData(signed_pdf, + // signed_pdf.length); // has been moved into the BinarySignatureHolder + + SignatureObject signature_object = new SignatureObject(); + String default_type = SettingsReader.getInstance().getValueFromKey(SignatureTypes.DEFAULT_TYPE); + signature_object.setSigType(default_type); + signature_object.initByType(); + + signature_object.setKZ(kz); + + if (cert != null) + { + try + { + // ByteArrayInputStream bais = new ByteArrayInputStream(cert); + // CertificateFactory cf = CertificateFactory.getInstance("X.509"); + // X509Certificate certificate = (X509Certificate) + // cf.generateCertificate(bais); + + // trim zero bytes. - the base 64 cert must not have zero bytes. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < cert.length; i++) + { + if (cert[i] != 0) + { + baos.write(cert[i]); + } + } + byte[] b64 = baos.toByteArray(); + + signature_object.storeNewCertificateInLocalStore(b64); + } + catch (Exception e) + { + logger_.error(e.getMessage(), e); + } + + } + + Iterator rit = bbi.replaces.iterator(); + while (rit.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) rit.next(); + + String type = SignatureTypes.convertBrevToType(ri.brev); + + // signature_object.setSigValue(ri.type, ri.value); + if (type.equals(SignatureTypes.SIG_DATE)) + { + signature_object.setSignationDate(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_ISSUER)) + { + signature_object.setSignationIssuer(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_VALUE)) + { + signature_object.setSignationValue(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_NUMBER)) + { + signature_object.setSignationSerialNumber(ri.value); + continue; + } + + if (type.equals(SignatureTypes.SIG_ID)) + { + signature_object.setSignationIDs(ri.value); + continue; + } + } + + // FIXME This blows up the session !!!!! + PdfDataSource ds = new ByteArrayPdfDataSourceImpl(signed_pdf, signed_pdf.length); + BinarySignatureHolder signature_holder = new BinarySignatureHolder(ds, signature_object); + + List holders = new ArrayList(); + holders.add(signature_holder); + return holders; + } + + /** + * Retrieves the value of the key from the dictionary. + * + * @param pdf + * The PDF. + * @param egiz_dict + * The dictionary. + * @param name + * The name of the key. + * @return Returns the value of the key. An exception is thrown if the key + * doesn't exist. + * @throws PDFDocumentException + * Thrown, if the key doesn't exist in the dictionary. + */ + protected ParseResult getRequiredValueOfKey(byte[] pdf, DictionaryParseResult egiz_dict, byte[] name) throws PDFDocumentException + { + final int index = PDFUtils.indexOfName(pdf, egiz_dict.names, name); + checkIndex(index); + ParseResult value = (ParseResult) egiz_dict.values.get(index); + return value; + } + + /** + * Throws an excaption, if the index is lower than 0. + * + * @param name_index + * The index. + * @throws PDFDocumentException + * Thrown, if the index is lower than 0. + */ + protected void checkIndex(int name_index) throws PDFDocumentException + { + if (name_index < 0) + { + throw new PDFDocumentException(ErrorCode.COULDNT_VERIFY, "The name wasn't found in the egiz dict."); + } + } + + /** + * Retrieves the value of the key from the dictionary. + * + * @param pdf + * The PDF. + * @param egiz_dict + * The dictionary. + * @param name + * The name of the key. + * @return Returns the key's value, or null if the dictionary didn't contain + * that key. + */ + protected ParseResult getValueOfKey(byte[] pdf, DictionaryParseResult egiz_dict, byte[] name) + { + final int index = PDFUtils.indexOfName(pdf, egiz_dict.names, name); + if (index < 0) + { + return null; + } + ParseResult value = (ParseResult) egiz_dict.values.get(index); + return value; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_1_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_1_0.java new file mode 100644 index 0000000..c1d94c1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/BinaryVerificator_1_1_0.java @@ -0,0 +1,44 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.framework.verificators; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; + +/** + * @author wprinz + * + */ +public class BinaryVerificator_1_1_0 extends BinaryVerificator_1_0_0 +{ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_BINARY, SignatorFactory.VERSION_1_1_0); + + /** + * @see at.knowcenter.wag.egov.egiz.framework.verificators.BinaryVerificator_1_0_0#getMyId() + */ + protected PdfASID getMyId() + { + return MY_ID; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java new file mode 100644 index 0000000..58302be --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_1_0_0.java @@ -0,0 +1,147 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualVerificator_1_0_0.java,v 1.5 2006/11/28 07:45:09 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.verificators; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.framework.Verificator; +import at.knowcenter.wag.egov.egiz.pdf.AbsoluteTextSignature; +import at.knowcenter.wag.egov.egiz.pdf.SignatureHolder; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + + +/** + * The textual verificator. + * + *

+ * All holders of the document so far including the block itself are extracted. + * If at least one has been found it is checked that this one doesn't belong to + * a previous block. + *

+ *

+ * Note that the KZ is not explicitely checked here, so this algorithm will find + * all blocks. + *

+ *

+ * Note that it will not find old style blocks as they don't have the SIG_KZ. + *

+ * + * @deprecated moved to the new framework + * + * @author wprinz + */ +public class TextualVerificator_1_0_0 implements Verificator +{ + /** + * The Pdf-AS ID of this Verificator. + */ + public static final PdfASID MY_ID = new PdfASID(SignatorFactory.VENDOR, SignatorFactory.TYPE_TEXTUAL, SignatorFactory.VERSION_1_0_0); + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(TextualVerificator_1_0_0.class); + + /** + * Default constructor. + */ + public TextualVerificator_1_0_0() + { + // Default constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Verificator#parseBlock(byte[], + * at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(byte[] pdf, FooterParseResult block, + int start_of_whole_block) throws PresentableException + { + String block_text = PdfAS.extractNormalizedTextTextual(pdf, block.next_index); + + logger_.debug("Scanning block:"); + //List signature_holders = PdfAS.extractSignatureHoldersTextual(block_text, false); + List signature_holders = AbsoluteTextSignature.extractSignatureHoldersFromText(block_text); + logger_.debug(": end of Scanning block"); + + // logger_.debug("signature_holders = " + signature_holders.size()); + + if (signature_holders.isEmpty()) + { + return signature_holders; + } + + List text_holder_candidates = null; + if (start_of_whole_block > 0) + { + text_holder_candidates = new ArrayList(); + + String prev_text = PdfAS.extractNormalizedTextTextual(pdf, start_of_whole_block); + + logger_.debug("Scanning prev block:"); + //List prev_signature_holders = PdfAS.extractSignatureHoldersTextual(prev_text, false); + List prev_signature_holders = AbsoluteTextSignature.extractSignatureHoldersFromText(prev_text); + logger_.debug(": end of Scanning prev block"); + + // logger_.debug("prev_signature_holders = " + + // prev_signature_holders.size()); + + for (int i = prev_signature_holders.size(); i < signature_holders.size(); i++) + { + SignatureHolder holder = (SignatureHolder) signature_holders.get(i); + text_holder_candidates.add(holder); + } + } + else + { + logger_.debug("there is no prev - so all found signatures are possible candidates."); + text_holder_candidates = signature_holders; + } + + List text_holders = new ArrayList(); + for (int i = 0; i < text_holder_candidates.size(); i++) + { + SignatureHolder holder = (SignatureHolder) text_holder_candidates.get(i); + if (!holder.getSignatureObject().isTextual()) + { + logger_.debug("Skipping found signature block because it's not textual."); + continue; + } + text_holders.add(holder); + } + + return text_holders; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java new file mode 100644 index 0000000..98940d6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/framework/verificators/TextualVerificator_pdfasold.java @@ -0,0 +1,106 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualVerificator_pdfasold.java,v 1.3 2006/10/11 08:03:22 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.framework.verificators; + +import java.io.ByteArrayInputStream; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.framework.Verificator; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; + + +/** + * This Verificator extracts a PDF-AS old signature from the original document. + * + * @author wprinz + */ +public class TextualVerificator_pdfasold implements Verificator +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(TextualVerificator_1_0_0.class); + + /** + * Default Constructor. + */ + public TextualVerificator_pdfasold() + { + // Default Constructor. + } + + /** + * @see at.knowcenter.wag.egov.egiz.framework.Verificator#parseBlock(byte[], at.knowcenter.wag.exactparser.parsing.results.FooterParseResult, int) + */ + public List parseBlock(byte[] pdf, FooterParseResult block, + int start_of_whole_block) throws PresentableException + { + if (start_of_whole_block != 0) + { + throw new PDFDocumentException(201, "The PDF-AS-old Verificator can only be applied on original documents."); + } + + String normalized_text = PdfAS.extractNormalizedTextTextual(pdf, block.next_index); + + logger_.debug("Scanning block:"); + List signature_holders = PdfAS.extractSignatureHoldersTextual(normalized_text, true); + logger_.debug(": end of Scanning block"); + + +// List signature_holders = new ArrayList(); +// +// SignatureTypes sig_types = SignatureTypes.getInstance(); +// List signatureTypes_ = sig_types.getSignatureTypeDefinitions(); +// +// boolean can_separate = true; +// int endIndex = normalized_text.length(); +// String signed_text = normalized_text; +// +// SignatureBlock sig_block = new SignatureBlock(signatureTypes_); +// can_separate = sig_block.separateBlockFromRawText(signed_text, true); +// if (can_separate) +// { +// endIndex = sig_block.getStartIndex(); +// signed_text = signed_text.substring(0, endIndex); +// +// SignatureObject sig_object = sig_block.getSignatureObject(); +// +// SignatureHolder holder = new SignatureHolder(); +// holder.signed_text = signed_text; +// holder.signature_object = sig_object; +// signature_holders.add(0, holder); +// } + + return signature_holders; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIException.java new file mode 100644 index 0000000..9074ded --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIException.java @@ -0,0 +1,77 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.api; + +/** + * @author Thomas Knall + */ +public class LDAPAPIException extends Exception { + + private static final long serialVersionUID = 1L; + + private Exception exception; + + public Exception getException() { + return this.exception; + } + + public String getMessage() { + String message = super.getMessage(); + if (message == null && exception != null) { + return exception.getMessage(); + } else { + return message; + } + } + + public LDAPAPIException(String message, Exception exception) { + super(message); + this.exception = exception; + } + + public LDAPAPIException(String message) { + super(message); + this.exception = null; + } + + public LDAPAPIException(Exception exception) { + super(); + this.exception = exception; + } + + public LDAPAPIException() { + super(); + this.exception = null; + + } + + public String toString() { + if (exception != null) { + return exception.toString(); + } else { + return super.toString(); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactory.java new file mode 100644 index 0000000..51ae84f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactory.java @@ -0,0 +1,55 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.api; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; +import at.knowcenter.wag.egov.egiz.sig.LDAPAPI; + +/** + * @author Thomas Knall + */ +public abstract class LDAPAPIFactory { + + private static LDAPAPIFactory ldapAPIfactoryInstance; + private final Logger log = Logger.getLogger(LDAPAPIFactory.class); + + protected LDAPAPIFactory() { + } + + public static synchronized LDAPAPIFactory getInstance(LDAPIssuerNameFilter ldapIssuerNameFilter) { + if (ldapAPIfactoryInstance == null) { + ldapAPIfactoryInstance = new LDAPAPIFactoryImpl(ldapIssuerNameFilter); + } + return ldapAPIfactoryInstance; + } + + public static LDAPAPIFactory getInstance() { + return getInstance(null); + } + + public abstract LDAPAPI createLDAPAPI(String implClassURI) throws LDAPAPIException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactoryImpl.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactoryImpl.java new file mode 100644 index 0000000..61fbaed --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIFactoryImpl.java @@ -0,0 +1,92 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.api; + +import java.util.Hashtable; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; +import at.knowcenter.wag.egov.egiz.sig.LDAPAPI; + +/** + * @author Thomas Knall + */ +public class LDAPAPIFactoryImpl extends LDAPAPIFactory { + + private static final Logger log = Logger.getLogger(LDAPAPIFactoryImpl.class); + + // mapping +// private Hashtable ldapImpls; + private Hashtable ldapImpls; + + private LDAPIssuerNameFilter ldapIssuerNameFilter; + + protected LDAPAPIFactoryImpl(LDAPIssuerNameFilter ldapIssuerNameFilter) { + this.ldapImpls = new Hashtable(); + this.ldapIssuerNameFilter = ldapIssuerNameFilter; + } + + private LDAPAPI instantiatelAPIImpl(String implClassURI) throws LDAPAPIException { + if (implClassURI == null) { + throw new NullPointerException("URI of implementing class must not be null."); + } + if (implClassURI.length() == 0) { + throw new IllegalArgumentException("URI of implementing class must not be empty."); + } + log.info("Trying to instantiate \"" + LDAPAPI.class.getName() + "\" implementation \"" + implClassURI + "\"..."); + LDAPAPI ldapAPIImpl = null; + try { + Class clazz = Class.forName(implClassURI); + Object ldapAPIImplObj = clazz.newInstance(); + if (!(ldapAPIImplObj instanceof LDAPAPI)) { + throw new LDAPAPIException("Declared class does not implement \"" + LDAPAPI.class.getName() + "\"."); + } + ldapAPIImpl = (LDAPAPI) ldapAPIImplObj; + log.info("LDAPAPI implementation successfully instantiated."); + ldapAPIImpl.setIssuerNameFilter(this.ldapIssuerNameFilter); + } catch (InstantiationException e) { + throw new LDAPAPIException("Declared implementation of \"" + LDAPAPI.class.getName() + "\" cannot be instantiated."); + } catch (IllegalAccessException e) { + throw new LDAPAPIException("Declared implementation of \"" + LDAPAPI.class.getName() + "\" cannot be instantiated (illegal access)."); + } catch (ClassNotFoundException e) { + throw new LDAPAPIException("Unable to find class \"" + implClassURI + "\" as implementation of \"" + LDAPAPI.class.getName() + "\"."); + } + return ldapAPIImpl; + } + + public synchronized LDAPAPI createLDAPAPI(String implClassURI) throws LDAPAPIException { + if (implClassURI == null || implClassURI.length() == 0) { + // use internal implementation + implClassURI = LDAPAPIImpl.class.getName(); + } + LDAPAPI impl = (LDAPAPI) this.ldapImpls.get(implClassURI); + if (impl == null) { + impl = this.instantiatelAPIImpl(implClassURI); + this.ldapImpls.put(implClassURI, impl); + } + return impl; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIImpl.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIImpl.java new file mode 100644 index 0000000..57c471f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/api/LDAPAPIImpl.java @@ -0,0 +1,148 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.api; + +import iaik.utils.Util; +import iaik.x509.X509Certificate; + +import java.math.BigInteger; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPClient; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPClientFactory; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPException; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPMapping; +import at.knowcenter.wag.egov.egiz.sig.LDAPAPI; + +/** + * @author Thomas Knall + */ +public class LDAPAPIImpl implements LDAPAPI { + + private final Logger log = Logger.getLogger(this.getClass()); + + /** + * Prefix for specific entry in config properties file. + */ + private static final String PROP_LDAP_PREFIX = "ldap_mapping"; + + private static final String PROP_ISSUER_NAME_POSTFIX = "issuer_name"; + + private static final String PROP_LDAP_URL_POSTFIX = "url"; + + private static final String PROP_SERIAL_ATTR_POSTFIX = "serial_attr"; + + private static final String LDAP_FACTORY_IDENTIFIER = "PDF-AS LDAP Support"; + + private LDAPClientFactory ldapClientFactory; + + private LDAPIssuerNameFilter ldapIssuerNameFilter; + + protected LDAPAPIImpl() { + this.ldapClientFactory = null; + this.ldapIssuerNameFilter = null; + } + + private void initializeFactoryImpl() { + if (this.ldapClientFactory == null) { + try { + SettingsReader settings = SettingsReader.getInstance(); + + this.ldapClientFactory = LDAPClientFactory.getInstance(LDAP_FACTORY_IDENTIFIER); + this.ldapClientFactory.setLDAPIssuerNameFilter(this.ldapIssuerNameFilter); + + List mappingKeys = settings.getKeys(PROP_LDAP_PREFIX); + if (mappingKeys != null) { + Iterator it = mappingKeys.iterator(); + while (it.hasNext()) { + String keyPrefix = PROP_LDAP_PREFIX + "." + (String) it.next() + "."; + String issuerName = settings.getSetting(keyPrefix + PROP_ISSUER_NAME_POSTFIX); + String ldapURL = settings.getSetting(keyPrefix + PROP_LDAP_URL_POSTFIX); + String serialAttr = settings.getSetting(keyPrefix + PROP_SERIAL_ATTR_POSTFIX, + null); + + LDAPMapping ldapMapping = new LDAPMapping(issuerName, ldapURL, serialAttr); + this.ldapClientFactory.registerMapping(ldapMapping); + } + } else { + StringBuffer buffer = new StringBuffer(); + buffer.append(PROP_LDAP_PREFIX).append(".foo.").append(PROP_ISSUER_NAME_POSTFIX) + .append(", "); + buffer.append(PROP_LDAP_PREFIX).append(".foo.").append(PROP_LDAP_URL_POSTFIX) + .append(", "); + buffer.append(PROP_LDAP_PREFIX).append(".foo.").append(PROP_SERIAL_ATTR_POSTFIX); + this.log.warn("There are no LDAP mappings (" + buffer.toString() + + ") declared within config file."); + } + + } catch (SettingsException e) { + this.log.error(e.getMessage(), e); + } catch (SettingNotFoundException e) { + this.log.error(e.getMessage(), e); + } catch (LDAPException e) { + this.log.error(e.getMessage(), e); + } + ; + } + } + + public byte[] loadBase64CertificateFromLDAP(String serialNumber, String issuer) { + this.initializeFactoryImpl(); + byte[] base64CertData = null; + try { + List clients = this.ldapClientFactory.createClients(issuer); + Iterator clientIt = clients.iterator(); + X509Certificate x509certificate = null; + while (clientIt.hasNext() && x509certificate == null) { + LDAPClient client = (LDAPClient) clientIt.next(); + try { + x509certificate = client.retrieveCertificate(new BigInteger(serialNumber)); + } catch (LDAPException e) { + this.log.error(e.getMessage(), e); + } + } + if (x509certificate != null) { + base64CertData = Util.Base64Encode(x509certificate.toByteArray()); + } + } catch (LDAPException e) { + this.log.error(e.getMessage(), e); + } + return base64CertData; + } + + public void setIssuerNameFilter(LDAPIssuerNameFilter filter) throws LDAPAPIException { + if (this.ldapClientFactory != null) { + throw new LDAPAPIException("LDAPIssuerNameFilter must be applied before mappings are registered."); + } + this.ldapIssuerNameFilter = filter; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClient.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClient.java new file mode 100644 index 0000000..1425856 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClient.java @@ -0,0 +1,88 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.x509.X509Certificate; + +import java.math.BigInteger; +import java.net.URL; + +/** + * @author Thomas Knall + */ +public interface LDAPClient { + + /** + * Returns the ldap url this client was registered for. + * + * @return The ldap url linked with this client. + */ + URL getUrl(); + + /** + * Sets the ldap url this client should be registered for. + * + * @param ldapURL + * The ldap url linked with this client. + */ + void setUrl(URL ldapURL); + + /** + * Returns the attribute name that represents the serial number. + * + * @return The attribute name representing the serial number. + */ + String getSerialNumberAttrName(); + + /** + * Sets the attribute name that represents the serial number. + * + * @param serialNumberAttrName + * The attribute name representing the serial number. + */ + void setSerialNumberAttrName(String serialNumberAttrName); + + /** + * Retrieves the certificate(s) matching the filter {@code filter}. + * + * @param filter + * The filter for the ldap request. + * @return An array of certificates matching the filter {@code filter}. + * @throws LDAPException + * Is thrown in case of error. + */ + X509Certificate[] retrieveCertificates(String filter) throws LDAPException; + + /** + * Retriebes the certificate with the serial number {@code serialNumber}. + * + * @param serialNumber + * The serial number of the required certificate. + * @return The certificate with the serial number {@code serialNumber}. + * @throws LDAPException + * Is thrown in case of error. + */ + X509Certificate retrieveCertificate(BigInteger serialNumber) throws LDAPException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactory.java new file mode 100644 index 0000000..d88d0b8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactory.java @@ -0,0 +1,102 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.asn1.structures.Name; + +import java.util.Hashtable; +import java.util.List; + +import org.apache.log4j.Logger; + + +/** + * @author Thomas Knall + */ +public abstract class LDAPClientFactory { + + private final Logger log = Logger.getLogger(getClass()); + + protected static final String DEFAULT_IDENTIFIER = "default LDAPClientFactory"; + + /** + * Mapping of category/identifier to LDAPClientFactory. + * Allows the usage of multiple independently configured LDAPClientFactoryImpls. + */ +// private static Hashtable ldapClientFactoryInstances = new Hashtable(); + private static Hashtable ldapClientFactoryInstances = new Hashtable(); + + private LDAPMappingStore ldapMappingStore; + + protected LDAPClientFactory() { + this.ldapMappingStore = new LDAPMappingStore(); + } + + public List getMappings(String issuerName) throws LDAPException { + return this.ldapMappingStore.getMappings(issuerName); + } + + public List getMapping(Name name) { + return this.ldapMappingStore.getMappings(name); + } + + public void resetMappings() { + this.ldapMappingStore.clearStore(); + } + + public boolean hasBeenConfigured() { + return !this.ldapMappingStore.isEmpty(); + } + + public synchronized void registerMapping(LDAPMapping ldapMapping) { + this.ldapMappingStore.addMapping(ldapMapping); + } + + public void setLDAPIssuerNameFilter(LDAPIssuerNameFilter filter) throws LDAPException { + if (this.hasBeenConfigured()) { + throw new LDAPException("Not allowed to set filter after registration of mappings."); + } + this.ldapMappingStore = new LDAPMappingStore(filter); + } + + public boolean isLDAPIssuerNameFilter() { + return this.ldapMappingStore.isLDAPIssuerNameFilter(); + } + + public static synchronized LDAPClientFactory getInstance(String identifier) { + LDAPClientFactory ldapClientFactoryInstance = (LDAPClientFactory) ldapClientFactoryInstances.get(identifier); + if (ldapClientFactoryInstance == null) { + ldapClientFactoryInstance = new LDAPClientFactoryImpl(); + ldapClientFactoryInstances.put(identifier, ldapClientFactoryInstance); + } + return ldapClientFactoryInstance; + } + + public static synchronized LDAPClientFactory getInstance() { + return getInstance(DEFAULT_IDENTIFIER); + } + + public abstract List createClients(String issuerName) throws LDAPException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactoryImpl.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactoryImpl.java new file mode 100644 index 0000000..ae3cbc1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientFactoryImpl.java @@ -0,0 +1,118 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.asn1.ObjectID; +import iaik.asn1.structures.Name; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.log4j.Logger; + +/** + * @author Thomas Knall + */ +public final class LDAPClientFactoryImpl extends LDAPClientFactory { + + private final Logger log = Logger.getLogger(getClass()); + + private Hashtable ldapClients; + + protected LDAPClientFactoryImpl() { + this.ldapClients = new Hashtable(); + } + + public static String rfc2253Name2Domain(Name name) { + Object[] values = name.getRDNValues(ObjectID.domainComponent); + if (values == null) { + return null; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < values.length; i++) { + buffer.append(values[i]); + if (i+1 < values.length) { + buffer.append("."); + } + } + return buffer.toString(); + } + + public static String rfc2253Name2Domain(String nameString) throws RFC2253NameParserException { + RFC2253NameParser nameParser = new RFC2253NameParser(nameString); + return rfc2253Name2Domain(nameParser.parse()); + } + + private List instantiateLDAPClients(String issuerName) throws LDAPException { + if (!super.hasBeenConfigured()) { + log.warn(super.getClass().getName() + " has not been configured yet."); + } + List ldapClients = new ArrayList(); + List mappings = super.getMappings(issuerName); + if (mappings == null || mappings.isEmpty()) { + try { + String alternativeURLString = rfc2253Name2Domain(issuerName); + if (alternativeURLString == null || alternativeURLString.length() == 0) { + throw new LDAPException("Neither issuer name \"" + issuerName + "\" has been registered nor domain components were provided."); + } + alternativeURLString = "ldap://" + alternativeURLString; + log.warn("Issuer name \"" + issuerName + "\" has not been registered; trying to instantiate client for url \"" + alternativeURLString + "\"..."); + LDAPClient client = new LDAPClientImpl(alternativeURLString); + ldapClients.add(client); + } catch (RFC2253NameParserException e) { + throw new LDAPException(e); + } + } else { + log.debug("Instantiating LDAP clients for " + ArrayUtils.toString(mappings.toArray()) + "."); + Iterator mappingIt = mappings.iterator(); + while (mappingIt.hasNext()) { + LDAPMapping mapping = (LDAPMapping) mappingIt.next(); + ldapClients.add(new LDAPClientImpl(mapping)); + } + } + return ldapClients; + } + + public synchronized List createClients(String issuerName) throws LDAPException { + if (issuerName == null) { + throw new NullPointerException("Issuer name must not be null."); + } + if (issuerName.length() == 0) { + throw new IllegalArgumentException("Issuer name must not be empty."); + } + List ldapClientList = (List) ldapClients.get(issuerName); + if (ldapClientList == null) { + ldapClientList = instantiateLDAPClients(issuerName); + ldapClients.put(issuerName, ldapClientList); + } + return Collections.unmodifiableList(ldapClientList); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientImpl.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientImpl.java new file mode 100644 index 0000000..808a345 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPClientImpl.java @@ -0,0 +1,214 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.x509.X509Certificate; +import iaik.x509.net.ldap.LdapURLConnection; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.log4j.Logger; + +public final class LDAPClientImpl implements LDAPClient { + + // constants + protected static final String DEFAULT_LDAP_ATTR_SERIAL_NUMBER = "eidCertificateSerialNumber"; + private static final iaik.x509.net.ldap.Handler LDAP_HANDLER = new iaik.x509.net.ldap.Handler(); + + private static final long TIME_ON_BLACKLIST_IN_SECONDS = 300; // block failed urls for 5 min + private static final int READ_TIMEOUT = 15; + private static final int CONNECTION_TIMEOUT = 15; + + private Logger log = Logger.getLogger(getClass()); + + // fields + private URL url; + private String serialNumberAttrName; + private long timeStampForBlackList; + + // constructors + protected LDAPClientImpl() { + this.setSerialNumberAttrName(DEFAULT_LDAP_ATTR_SERIAL_NUMBER); + this.timeStampForBlackList = 0; + } + + protected LDAPClientImpl(URL url) { + this(); + this.setUrl(url); + } + + protected LDAPClientImpl(String urlString) throws LDAPException { + this(); + try { + this.setUrl(new URL(null, urlString, LDAP_HANDLER)); + } catch (MalformedURLException e) { + throw new LDAPException(e); + } + } + + protected LDAPClientImpl(LDAPMapping ldapMapping) { + this(); + this.setUrl(ldapMapping.getLdapURL()); + this.setSerialNumberAttrName(ldapMapping.getSerialNumberAttrName()); + } + + + // getter/setter + + /* + * @see at.iaik.commons.ldap.LDAPClient#getUrl() + */ + public URL getUrl() { + return this.url; + } + + /* + * @see at.iaik.commons.ldap.LDAPClient#setUrl(java.net.URL) + */ + public void setUrl(URL ldapURL) { + if (ldapURL == null) { + throw new NullPointerException("LDAP url must not be null."); + } + this.url = ldapURL; + } + + /* + * @see at.iaik.commons.ldap.LDAPClient#getSerialNumberAttrName() + */ + public String getSerialNumberAttrName() { + return this.serialNumberAttrName; + } + + /* + * @see at.iaik.commons.ldap.LDAPClient#setSerialNumberAttrName(java.lang.String) + */ + public void setSerialNumberAttrName(String serialNumberAttrName) { + if (serialNumberAttrName != null && serialNumberAttrName.length() == 0) { + throw new IllegalArgumentException("Serial number attribute name must not be empty"); + } + this.serialNumberAttrName = serialNumberAttrName != null ? serialNumberAttrName : DEFAULT_LDAP_ATTR_SERIAL_NUMBER; + } + + // service methods + + /* + * @see at.iaik.commons.ldap.LDAPClient#retrieveCertificates(java.lang.String) + */ + public X509Certificate[] retrieveCertificates(String filter) throws LDAPException { + if (filter == null) { + throw new NullPointerException("Filter string must not be null."); + } + if (filter.length() == 0) { + throw new IllegalArgumentException("Filter string must not be empty."); + } + + X509Certificate[] certs = new X509Certificate[] { }; + + long now = System.currentTimeMillis(); + if (this.timeStampForBlackList + TIME_ON_BLACKLIST_IN_SECONDS * 1000 >= now) { + long remaining = TIME_ON_BLACKLIST_IN_SECONDS - ((now - this.timeStampForBlackList) / 1000); + log.warn("LDAP connections to URL \"" + this.getUrl().toString() + "\" are blocked for " + remaining + " (" + TIME_ON_BLACKLIST_IN_SECONDS + ") seconds due to previous errors."); + return certs; + } + + LdapURLConnection ldapURLConnection = null; + try { + this.validateData(); + ldapURLConnection = (LdapURLConnection) this.url.openConnection(); + log.debug("Setting timeout for LDAPClient: connection timeout = " + CONNECTION_TIMEOUT + " seconds, read timeout = " + READ_TIMEOUT + " seconds."); + ldapURLConnection.setReadTimeout(READ_TIMEOUT * 1000); + ldapURLConnection.setConnectTimeout(CONNECTION_TIMEOUT * 1000); + + // search for end enity certificates + ldapURLConnection.setRequestProperty( + LdapURLConnection.RP_ATTRIBUTE_DESCRIPTION, + LdapURLConnection.AD_USER_CERTIFICATE + ); + + // search subtree + ldapURLConnection.setRequestProperty( + LdapURLConnection.RP_SEARCH_SCOPE, + LdapURLConnection.SEARCH_SCOPE_SUBTREE + ); + + //set filter + ldapURLConnection.setRequestProperty( + LdapURLConnection.RP_FILTER, + filter + ); + + // connect to the ldap server an read results + log.debug("Connecting to \"" + this.url.toString() + "\"."); + certs = (X509Certificate[]) ldapURLConnection.getContent(); + log.debug("Result of LDAP query received (" + (certs != null ? certs.length : 0) + " result(s))."); + } catch (IOException e) { + this.timeStampForBlackList = System.currentTimeMillis(); + log.warn("Unable to get certificate from \"" + this.getUrl().toString() + "\". LDAPClient is now blocking that URL for " + TIME_ON_BLACKLIST_IN_SECONDS + " seconds."); + throw new LDAPException(e); + } finally { + if (ldapURLConnection != null) { + ldapURLConnection.disconnect(); + } + } + return certs; + } + + /* + * @see at.iaik.commons.ldap.LDAPClient#retrieveCertificate(java.math.BigInteger) + */ + public X509Certificate retrieveCertificate(BigInteger serialNumber) throws LDAPException { + if (serialNumber == null) { + throw new NullPointerException("Serial number must not be null"); + } + this.validateData(); + X509Certificate[] certs = retrieveCertificates("(" + this.serialNumberAttrName + "=" + serialNumber + ")"); + if (certs.length > 1) { + throw new LDAPException("There was more than one certificate with serial number " + serialNumber + "."); + } else if (certs.length == 0) { + return null; + } + return certs[0]; + } + + // misc + public void validateData() throws LDAPException { + if (this.url == null) { + throw new LDAPException("LDAP URL must not be null."); + } + if (this.serialNumberAttrName == null || this.serialNumberAttrName.length() == 0) { + throw new LDAPException("LDAP key for serial number is null or empty."); + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("ldapURL = ").append(this.url); + buffer.append(", serialNumberAttrName = ").append(this.serialNumberAttrName); + return buffer.toString(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPException.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPException.java new file mode 100644 index 0000000..3b36e6d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPException.java @@ -0,0 +1,50 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + + +/** + * @author Thomas Knall + */ +public class LDAPException extends Exception { + + private static final long serialVersionUID = 1L; + + public LDAPException() { + super(); + } + + public LDAPException(Exception exception) { + super(exception); + } + + public LDAPException(String message, Exception exception) { + super(message, exception); + } + + public LDAPException(String message) { + super(message); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPIssuerNameFilter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPIssuerNameFilter.java new file mode 100644 index 0000000..e483d2c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPIssuerNameFilter.java @@ -0,0 +1,43 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.asn1.structures.Name; + +/** + * @author Thomas Knall + */ +public interface LDAPIssuerNameFilter { + + /** + * Applies some kind of filtering on the distinguished name. This can be used + * for normalization. + * + * @param name + * The original distinguished name. + * @return The new filtered distinguished name. + */ + Name applyFilter(Name name); + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMapping.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMapping.java new file mode 100644 index 0000000..502d88b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMapping.java @@ -0,0 +1,181 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.asn1.structures.Name; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; + +import org.apache.log4j.Logger; + +/** + * @author Thomas Knall + */ +public class LDAPMapping { + + // constants + public static final String PROPERTIES_KEY_ISSUER_NAME = "issuer.name"; + public static final String PROPERTIES_KEY_LDAP_URL = "ldap.url"; + public static final String PROPERTIES_KEY_SERIAL_ATTR_NAME = "serialnumber.attrname"; + + private final Logger log = Logger.getLogger(getClass()); + private static final iaik.x509.net.ldap.Handler LDAP_HANDLER; + + // fields + private Name issuerName; + private URL ldapURL; + private String serialNumberAttrName; + + // static initialization + static { + LDAP_HANDLER = new iaik.x509.net.ldap.Handler(); + } + + // constructors + protected LDAPMapping() { + this.setSerialNumberAttrName(LDAPClientImpl.DEFAULT_LDAP_ATTR_SERIAL_NUMBER); + } + + public LDAPMapping(Name issuerName, URL ldapURL) { + this(issuerName, ldapURL, null); + } + + public LDAPMapping(Name issuerName, URL ldapURL, String serialNumberAttrName) { + this(); + this.setIssuerName(issuerName); + this.setLdapURL(ldapURL); + this.setSerialNumberAttrName(serialNumberAttrName); + } + + public LDAPMapping(String issuerNameString, String ldapURLString) throws LDAPException { + this(issuerNameString, ldapURLString, null); + } + + public LDAPMapping(String issuerNameString, String ldapURLString, String serialNumberAttrName) throws LDAPException { + this(); + this.setIssuerName(issuerNameString); + this.setLdapURL(ldapURLString); + this.setSerialNumberAttrName(serialNumberAttrName); + } + + public LDAPMapping(Properties properties) throws LDAPException { + this(); + if (properties == null) { + throw new NullPointerException("Properties must not be null."); + } + String in = properties.getProperty(PROPERTIES_KEY_ISSUER_NAME); + String sn = properties.getProperty(PROPERTIES_KEY_LDAP_URL); + String snan = properties.getProperty(PROPERTIES_KEY_SERIAL_ATTR_NAME); + if (in == null || in.length() == 0) { + throw new LDAPException("Property \"" + PROPERTIES_KEY_ISSUER_NAME + "\" must not be null or empty."); + } + if (sn == null || sn.length() == 0) { + throw new LDAPException("Property \"" + PROPERTIES_KEY_LDAP_URL + "\" must not be null or empty."); + } + this.setIssuerName(in); + this.setLdapURL(sn); + this.setSerialNumberAttrName(snan); + } + + // getter/setter + public Name getIssuerName() { + return this.issuerName; + } + + public String getIssuerNameAsString() { + return this.issuerName.getName(); + } + + public void setIssuerName(Name issuerName) { + if (issuerName == null) { + throw new NullPointerException("Issuer name must not be null."); + } + this.issuerName = issuerName; + } + + public void setIssuerName(String issuerNameString) throws LDAPException { + RFC2253NameParser parser = new RFC2253NameParser(issuerNameString.trim()); + try { + this.setIssuerName(parser.parse()); + } catch (RFC2253NameParserException e) { + throw new LDAPException(e); + } + } + + public URL getLdapURL() { + return this.ldapURL; + } + + public void setLdapURL(URL ldapURL) { + if (ldapURL == null) { + throw new NullPointerException("LDAP url must not be null."); + } + this.ldapURL = ldapURL; + } + + public void setLdapURL(String ldapURLString) throws LDAPException { + try { + this.setLdapURL(new URL(null, ldapURLString.trim(), LDAP_HANDLER)); + } catch (MalformedURLException e) { + throw new LDAPException(e); + } + } + + public String getSerialNumberAttrName() { + return this.serialNumberAttrName; + } + + public void setSerialNumberAttrName(String serialNumberAttrName) { + if (serialNumberAttrName != null && serialNumberAttrName.length() == 0) { + throw new IllegalArgumentException("Serial number attribute name must not be empty"); + } + this.serialNumberAttrName = serialNumberAttrName != null ? serialNumberAttrName.trim() : LDAPClientImpl.DEFAULT_LDAP_ATTR_SERIAL_NUMBER; + } + + // misc + public void validateData() throws LDAPException { + if (this.issuerName == null) { + throw new LDAPException("Issuer name must not be null."); + } + if (this.ldapURL == null) { + throw new LDAPException("LDAP url must not be null."); + } + if (serialNumberAttrName == null || serialNumberAttrName.length() == 0) { + throw new LDAPException("Serial number attribute name must not be null or empty"); + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("issuerName = ").append(this.issuerName != null ? this.issuerName.getName() : null); + buffer.append(", ldapURL = ").append(this.ldapURL); + buffer.append(", serialNumberAttrName = ").append(this.serialNumberAttrName); + return buffer.toString(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMappingStore.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMappingStore.java new file mode 100644 index 0000000..f36dc8c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/ldap/client/LDAPMappingStore.java @@ -0,0 +1,102 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.ldap.client; + +import iaik.asn1.structures.Name; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +import org.apache.log4j.Logger; + +/** + * @author Thomas Knall + */ +public class LDAPMappingStore { + +// private Hashtable storedMappings; + private Hashtable storedMappings; + private LDAPIssuerNameFilter issuerNameFilter; + private Logger log = Logger.getLogger(getClass()); + + public LDAPMappingStore(LDAPIssuerNameFilter issuerNameFilter) { + this.storedMappings = new Hashtable(); + this.issuerNameFilter = issuerNameFilter; + } + + public LDAPMappingStore() { + this(null); + } + + public void clearStore() { + this.storedMappings = new Hashtable(); + } + + public boolean isEmpty() { + return this.storedMappings.isEmpty(); + } + + public boolean isLDAPIssuerNameFilter() { + return this.issuerNameFilter != null; + } + + public void addMapping(LDAPMapping mapping) { + Name name = mapping.getIssuerName(); + if (issuerNameFilter != null) { + name = this.issuerNameFilter.applyFilter(name); + } + List mappingList = (List) this.storedMappings.get(name); + if (mappingList == null) { + mappingList = new ArrayList(); + this.storedMappings.put(name, mappingList); + } + log.debug("Adding mapping \"" + mapping + "\" for \"" + name.getName() + "\"."); + mappingList.add(mapping); + } + + public List getMappings(Name name) { + if (issuerNameFilter != null) { + name = this.issuerNameFilter.applyFilter(name); + } + return (List) this.storedMappings.get(name); + } + + public List getMappings(String nameString) throws LDAPException { + RFC2253NameParser parser = new RFC2253NameParser(nameString); + Name name; + try { + name = parser.parse(); + } catch (RFC2253NameParserException e) { + throw new LDAPException(e); + } + if (issuerNameFilter != null) { + name = this.issuerNameFilter.applyFilter(name); + } + return this.getMappings(name); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java new file mode 100644 index 0000000..fd59d34 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java @@ -0,0 +1,956 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: AbsoluteTextSignature.java,v 1.1 2006/10/31 08:08:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.framework.FoundBlock; +import at.knowcenter.wag.egov.egiz.framework.FoundKey; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; + +/** + * Contains methods and helpers that implement the absolute text signature. + * + * @author wprinz + */ +public class AbsoluteTextSignature +{ + + /** + * The logger definition. + */ + private static final Logger logger = ConfigLogger.getLogger(AbsoluteTextSignature.class); + + /** + * Returns a List of SignatureTypeDefinitions that can be extracted from text. + * + *

+ * These SignatureTypeDefinitions are all text extractable, which means that they define all required fields as visible. + *

+ *

+ * This method filters out all SignatureTypeDefinitions that are not text extractable. + *

+ * + * @return Returns a List of SignatureTypeDefinitions that can be extracted from text. + * @throws SignatureTypesException F.e. + */ + public static List getSignatureTypesForTextAnalysis() throws SignatureTypesException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + List allSignatureTypes = sig_types.getSignatureTypeDefinitions(); + + List textSignatureTypes = new ArrayList(allSignatureTypes.size()); + Iterator it = allSignatureTypes.iterator(); + while (it.hasNext()) + { + SignatureTypeDefinition std = (SignatureTypeDefinition) it.next(); + if (!std.isTextExtractable()) + { + logger.debug("The profile " + std.getType() + " is not text extractable and is thereby not used for text analysis."); + continue; + } + textSignatureTypes.add(std); + } + + return textSignatureTypes; + } + + /** + * Extracts all signature holders from a given text. + * + *

+ * First the latest signature holder is extracted. Then the latest signature + * holder in the rest text, which is the second latest one, is extracted. Then + * the third latest signature holder is extracted and so forth until no more + * signature holders are found. + *

+ * + * @param text + * The text. + * @return Returns the List of extracted signature holders ordered by their + * date ascendingly (the lowest, earliest date first, the latest, + * newest date last). An empty list is returned if no signature + * holders were found. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * F.e. + */ + public static List extractSignatureHoldersFromText(String text) throws SignatureException, SignatureTypesException + { + List holders = new ArrayList(); + String current_text = text; + for (;;) + { + TextualSignatureHolder signature_holder = extractLatestBlock(current_text); + if (signature_holder == null) + { + break; + } + holders.add(0, signature_holder); + current_text = signature_holder.getSignedText(); + } + return holders; + } + + /** + * Extracts the latest signature block from the given text and creates a + * SignatureHolder object that can be verified. + * + * @param text + * The text. + * @return Returns the SignatureObject extracted from the text, or null, if no + * latest block was found. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * F.e. + */ + public static TextualSignatureHolder extractLatestBlock(String text) throws SignatureException, SignatureTypesException + { + FoundBlock latest_block = findLatestBlock(text); + if (latest_block == null) + { + return null; + } + String reconstructed_text = cutOutBlock(text, latest_block); + SignatureObject so = createSignatureObjectFromFoundBlock(text, latest_block); + TextualSignatureHolder tsh = new TextualSignatureHolder(reconstructed_text, so); + return tsh; + } + + /** + * Finds the latest signature block for a given text. + * + *

+ * The latest block is the one with the highest, most recent date. Usually + * this block will be extracted (cut out) of the text which will result in the + * originally signed text of this signature to be verified using the cut out + * data. + *

+ * + * @param text + * The text to be analyzed. + * @return Returns the latest found block or null, if there was none. + * @throws SignatureException + * F.e. + * @throws SignatureTypesException + * F.e. + */ + public static FoundBlock findLatestBlock(String text) throws SignatureException, SignatureTypesException + { + List signatureTypes_ = getSignatureTypesForTextAnalysis(); + + List found_potential_candidates = new ArrayList(); + + for (int i = 0; i < signatureTypes_.size(); i++) + { + SignatureTypeDefinition block_type = (SignatureTypeDefinition) signatureTypes_.get(i); + List found_candidates_for_type = findPotentialSignaturesForProfile(text, block_type); + + found_potential_candidates.addAll(found_candidates_for_type); + } + + if (found_potential_candidates.isEmpty()) + { + logger.debug("no candidates found at all"); + return null; + } + + List found_candidates = new ArrayList(); + logger.debug("checking block integrity"); + for (int i = 0; i < found_potential_candidates.size(); i++) + { + FoundBlock found_block = (FoundBlock) found_potential_candidates.get(i); + String date_value = getDateValue(text, found_block); + try + { + EGIZDate date = EGIZDate.parseFromString(date_value); + + logger.debug("found_block = " + date + " - " + found_block); + + checkBlockIntegrity(text, found_block); + found_candidates.add(found_block); + } + catch (Exception e) + { + logger.debug("Exception while checking the integrity of the found block " + found_block + ". Ignoring this block.", e); + } + } + + sortFoundBlocksByDate(text, found_candidates); + if (logger.isDebugEnabled()) + { + logger.debug("sorted blocks:"); + for (int i = 0; i < found_candidates.size(); i++) + { + FoundBlock found_block = (FoundBlock) found_candidates.get(i); + + String date_value = getDateValue(text, found_block); + EGIZDate date = EGIZDate.parseFromString(date_value); + + logger.debug(" #" + i + ": " + date + " - " + found_block); + } + } + + List latest_blocks = filterLastDateEqualBlocks(text, found_candidates); + if (logger.isDebugEnabled()) + { + logger.debug("latest blocks:"); + for (int i = 0; i < latest_blocks.size(); i++) + { + FoundBlock found_block = (FoundBlock) latest_blocks.get(i); + + String date_value = getDateValue(text, found_block); + EGIZDate date = EGIZDate.parseFromString(date_value); + + logger.debug(" #" + i + ": " + date + " - " + found_block); + } + } + + // The semantic equality check has been outdated by the + // advanced choosing algorithm. + // boolean semantic_equality = + // PdfAS.checkForSemanticEquality(latest_blocks); + // logger.debug("semantic_equality = " + semantic_equality); + // if (!semantic_equality) + // { + // throw new SignatureException(314, "The latest blocks weren't semantically + // equal."); + // } + + FoundBlock latest_block = chooseMostPossibleBlock(latest_blocks); + + logger.debug("latest block = " + latest_block); + return latest_block; + } + + /** + * Finds the List of potential blocks within the given text for the given + * profile. + * + * @param text + * The text, in which potential block are to be sought. + * @param block_type + * The profile for which the text is to be sought. + * @return Returns the List of potential FoundBlocks or an empty List if none + * could be found. + */ + public static List findPotentialSignaturesForProfile(String text, + SignatureTypeDefinition block_type) + { + logger.debug("find potential signatures for " + block_type.getType()); + List found_blocks = new ArrayList(); + + final boolean old_style = false; + + Vector keys = block_type.getRevertSortedKeys(); + Vector captions = block_type.getRevertSortedCaptions(); + + String last_key = (String) keys.get(0); + logger.debug("last_key = " + last_key); + String last_caption = (String) captions.get(0); + logger.debug("last_caption = " + last_caption); + String current_last_caption= last_caption; + List found_last_captions = findIndicesWithStartingNL(text, last_caption); + if (last_key.equals(SignatureTypes.SIG_ID)) + { + logger.debug("Last key is SIG_ID, so it may not be present. Searching for the previous to last key."); + String prevlast_key = (String) keys.get(1); + String prevlast_caption = (String) captions.get(1); + current_last_caption = prevlast_caption; + List found_prevlast_captions = findIndicesWithStartingNL(text, prevlast_caption); + if (!found_prevlast_captions.isEmpty()) + { + found_last_captions.addAll(found_prevlast_captions); + } + } + if (logger.isDebugEnabled()) + { + logger.debug("found " + found_last_captions.size() + " last captions."); + for (int i = 0; i < found_last_captions.size(); i++) + { + logger.debug(" found last caption at index " + found_last_captions.get(i)); + } + } + + for (int lci = 0; lci < found_last_captions.size(); lci++) + { + int last_caption_index = ((Integer) found_last_captions.get(lci)).intValue(); + logger.debug("resolving signature block from last caption index " + last_caption_index); + int potential_block_end = findEndOfValue(text, last_caption_index); + if (potential_block_end == (last_caption_index + current_last_caption.length()+1)) + { + potential_block_end = findEndOfValue(text, potential_block_end); + } + + // FIXME: complete HOTFIX + /* + int extendedValueEnd = potential_block_end; + String cv; + do { + extendedValueEnd = findEndOfValue(text, extendedValueEnd); + cv = text.substring(last_caption_index + current_last_caption.length()+1, extendedValueEnd); + } while (extendedValueEnd < text.length()); + */ + + logger.debug("potential_block_end = " + potential_block_end); + List found_keys = PdfAS.findBlockInText(text.substring(0, potential_block_end), block_type, old_style); // findRestKeys(text, + // keys, + // captions, + // last_caption_index); + + if (found_keys == null) + { + logger.debug("Not all other captions could be found for the last_caption_index " + last_caption_index + " ==> discarding this index."); + + continue; + } + + // sort found keys ascendingly + PdfAS.sortFoundKeysAscendingly(found_keys); + + boolean reverse_check_ok = reverseCheckFoundKeys(text, found_keys); + if (!reverse_check_ok) + { + logger.debug("The reverse check ruled this list of found keys out ==> they are discarded."); + + continue; + } + + logger.debug("The reverse check proved this list of found keys out ==> adding them as potential candidates."); + + FoundBlock found_block = new FoundBlock(); + found_block.std = block_type; + found_block.found_keys = found_keys; + found_block.end_index = potential_block_end;//findEndOfValue(text, last_caption_index); + found_blocks.add(found_block); + } + + logger.debug("found " + found_blocks.size() + " potential signatures for " + block_type.getType()); + return found_blocks; + } + + /** + * Finds all indices of the given subtext (starting at a new line) within a + * given text. + * + *

+ * This is usually used to find the indices of the last captions. + *

+ * + * @param text + * The text to be searched. + * @param subtext + * The subtext to be sought. + * @return Returns the List of found indices. + */ + public static List findIndicesWithStartingNL(String text, String subtext) + { + List found_indices = new ArrayList(); + + // // for some reason "^" + subtext doesn't work as a pattern + // String pattern = "\n" + subtext; + // Pattern p = Pattern.compile(pattern); + // Matcher m = p.matcher(text); + // + // while (m.find()) + // { + // int found_index = m.start() + 1; // +1 removes the newline + // found_indices.add(new Integer(found_index)); + // } + + int search_from_index = 0; + for (;;) + { + int found_index = text.indexOf("\n" + subtext, search_from_index); + if (found_index < 0) + { + break; + } + found_index += 1; // The +1 compensates the "\n" + found_indices.add(new Integer(found_index)); + search_from_index = found_index + subtext.length(); + } + return found_indices; + } + + /** + * Finds the other keys/captions according to their order starting from the + * last_caption index upwards. + * + * @param text + * The text. + * @param keys + * The list of keys. + * @param captions + * The list of captions. + * @param last_caption_index + * The index of the last caption. + * @return Returns the List of found keys, if all keys could be found, or null + * if not all keys could be found. + */ + public static List findRestKeys(String text, List keys, List captions, + int last_caption_index) + { + List found_keys = new ArrayList(); + + FoundKey last_caption_found_key = new FoundKey((String) keys.get(0), (String) captions.get(0), last_caption_index); + found_keys.add(last_caption_found_key); + + String rest_text = text.substring(0, last_caption_index); + + for (int i = 1; i < captions.size(); i++) + { + String sought_caption = (String) captions.get(i); + int index = rest_text.lastIndexOf(sought_caption); + + if (index < 0) + { + return null; + } + FoundKey found_key = new FoundKey((String) keys.get(i), (String) captions.get(i), index); + found_keys.add(0, found_key); + + rest_text = rest_text.substring(0, index); + } + + return found_keys; + } + + /** + * Performs a reverse (top to bottom) search for the found keys and checks + * that these indices are the same as those that were found during the regular + * (bottom up) search. + *

+ * If a reverse check proves that the found keys are not at the same positions + * as during regular search, this list of found keys should be discarded. + *

+ * + * @param text + * The text. + * @param found_keys + * The found keys to be reversely checked. + * @return Returns true, if all (also the non required) captions could be + * found at the same indices as during regular search, false + * otherwise. + */ + public static boolean reverseCheckFoundKeys(String text, List found_keys) + { + int search_from_index = ((FoundKey) found_keys.get(0)).start_index; + for (int i = 0; i < found_keys.size(); i++) + { + FoundKey found_key = (FoundKey) found_keys.get(i); + + int reverse_found_index = text.indexOf(found_key.caption, search_from_index); + + // dferbas fix #331 ?? + + if (reverse_found_index < 0) + { + throw new RuntimeException("The caption " + found_key.caption + " wasn't found in the text during reverse checking - there is something wrong."); + } + + if (reverse_found_index != found_key.start_index) + { + logger.debug("The index for caption " + found_key.caption + " wasn't proved during reverse checking."); + return false; + } + search_from_index = found_key.start_index + found_key.caption.length(); + } + return true; + } + + /** + * Finds the end of the value in the text. + * + *

+ * This simply scans for a '\n' from a given start index. The line up to and + * inclusive the '\n' is considered to be the value. + *

+ *

+ * Note that this method does NOT find the accurate value, if the value goes + * over multiple lines! This may bear a serious problem. Usually this method + * is only used to finding the end of the last value in a found block, because + * mid- values are exactly determined by their start index and the start of + * the next caption. Nevertheless, if the last value spans over multiple + * lines, this method will not retrieve it completely. + *

+ * + * @param text + * The text. + * @param start_index + * The start index from where the end of the value is sought. + * @return Returns the end index of the value, which is the index of the first + * character not belonging to the value anymore (the character after + * the '\n'). + */ + public static int findEndOfValue(String text, int start_index) + { + int newline_index = text.indexOf('\n', start_index); + if (newline_index < 0) + { + return text.length(); + } + return newline_index + 1; + } + + /** + * Checks the integrity of a found block. + * + *

+ * This is an assertive function. + *

+ * + * @param text + * The text. + * @param found_block + * The found block. + */ + public static void checkBlockIntegrity(String text, FoundBlock found_block) + { + for (int i = 0; i < found_block.found_keys.size() - 1; i++) + { + FoundKey this_key = (FoundKey) found_block.found_keys.get(i); + FoundKey next_key = (FoundKey) found_block.found_keys.get(i + 1); + + int this_end_index = findEndOfValue(text, this_key.start_index); + if (this_end_index != next_key.start_index) + { + logger.debug("multi line value: " + this_key); + // throw new RuntimeException("The end index of found key " + this_key + + // " doesn't match the start index of found key " + next_key); + } + } + + FoundKey last_key = (FoundKey) found_block.found_keys.get(found_block.found_keys.size() - 1); + int end_of_block = findEndOfValue(text, last_key.start_index); + if (end_of_block == (last_key.start_index+last_key.caption.length()+1)) + { + end_of_block = findEndOfValue(text,end_of_block); + } + if (end_of_block != found_block.end_index) + { + throw new RuntimeException("The end index of last key " + last_key + " doesn't match the end index of the block " + found_block); + } + } + + /** + * Cuts out the given found block from the text. + * + * @param text + * The text. + * @param block + * The found block. + * @return Returns the rest text without the block. + */ + public static String cutOutBlock(String text, FoundBlock block) + { + int block_start_index = ((FoundKey) block.found_keys.get(0)).getStartIndex(); + int block_end_index = block.end_index; + + if (block_start_index == 0 && block_end_index == text.length()) + { + // the block is the whole text - the rest text is empty. + // This may happen if a (no-text) empty document contains a binary signature. + // Then the "signed text" of the binary signature is empty. + return ""; + } + + if (block_end_index == text.length()) + { + // if the block is at the end of the text, remove the "\n" before the + // block as well. + String pre = text.substring(0, block_start_index - 1); + return pre; + } + + String pre = text.substring(0, block_start_index); + String post = text.substring(block_end_index); + + String rest_text = pre + post; + return rest_text; + } + + /** + * Returns the value of the date field as String. + * + * @param text + * The text. + * @param block + * The found block. + * @return Returns the date value. + */ + public static String getDateValue(String text, FoundBlock block) + { + FoundKey date_key = block.getDateFoundKey(); + int date_value_start_index = date_key.start_index + date_key.caption.length(); + int date_value_end_index = findEndOfValue(text, date_value_start_index); + if (date_value_end_index == (date_value_start_index+1)) + { + date_value_end_index = findEndOfValue(text, date_value_end_index); + } + String date_value = text.substring(date_value_start_index, date_value_end_index).trim(); + logger.debug("DateString="+date_value); + return date_value; + } + + /** + * Creates a SignatureObject from a found block by extracting the + * corresponding values. + * + * @param text + * The text. + * @param found_block + * The found block. + * @return Returns the created SignatureObject. + * @throws SignatureTypesException + * F.e. + * @throws SignatureException + * F.e. + */ + public static SignatureObject createSignatureObjectFromFoundBlock( + String text, FoundBlock found_block) throws SignatureTypesException, SignatureException + { + SignatureObject signatureObject = new SignatureObject(); + + signatureObject.setSigType(found_block.std.getType()); + signatureObject.initByType(); + + int end_index = found_block.end_index; + for (int i = found_block.found_keys.size() - 1; i >= 0; i--) + { + FoundKey cur_key = (FoundKey) found_block.found_keys.get(i); + int start_index = cur_key.getStartIndex() + cur_key.caption.length(); + + String value = text.substring(start_index, end_index); + + signatureObject.setSigValueCaption(cur_key.getKey(), value, cur_key.caption); + + end_index = cur_key.getStartIndex(); + } + + return signatureObject; + + } + + /** + * Parses the EGIZDate from a found block and the given text. + * + * @param text + * The text. + * @param found_block + * The found block. + * @return Returns the parsed EGIZDate. + */ + public static EGIZDate getDateFromFoundBlock(String text, + FoundBlock found_block) + { + String date_value = getDateValue(text, found_block); + EGIZDate date = EGIZDate.parseFromString(date_value); + return date; + } + + /** + * Sorts the List of found blocks by date. + * + * @param text + * The text. + * @param found_blocks + * The List of found blocks. + */ + public static void sortFoundBlocksByDate(final String text, List found_blocks) + { + Collections.sort(found_blocks, new Comparator() + { + public int compare(Object arg0, Object arg1) + { + FoundBlock fb0 = (FoundBlock) arg0; + FoundBlock fb1 = (FoundBlock) arg1; + + EGIZDate date0 = getDateFromFoundBlock(text, fb0); + EGIZDate date1 = getDateFromFoundBlock(text, fb1); + return date0.compareTo(date1); + } + }); + } + + /** + * Given a List of FoundBlock objects, this method returns the last blocks of + * this list that have the same date. + * + *

+ * Usually a date sorted list (earliest first, latest last) will be provided + * to this method. Then the last date equal blocks are returned, which are the + * last blocks. + *

+ * + * @param text + * The text to retrieve the values of the fields from. + * @param found_blocks + * The List of FoundBlock objects. + * @return Returns the List of the last date equal blocks. + */ + public static List filterLastDateEqualBlocks(String text, List found_blocks) + { + List latest_blocks = new ArrayList(); + latest_blocks.add(found_blocks.get(found_blocks.size() - 1)); + for (int i = found_blocks.size() - 2; i >= 0; i--) + { + FoundBlock this_block = (FoundBlock) found_blocks.get(i); + FoundBlock succ_block = (FoundBlock) found_blocks.get(i + 1); + + EGIZDate this_date = getDateFromFoundBlock(text, this_block); + EGIZDate succ_date = getDateFromFoundBlock(text, succ_block); + + if (!this_date.equals(succ_date)) + { + break; + } + latest_blocks.add(0, this_block); + } + + return latest_blocks; + } + /** + * Chooses the most possible (best choice) block of the list of blocks. + * + *

+ * The strategy to find the most possible block is to choose the very one + * block with the maximum number of captions. This block has extracted most + * information from the text. + *

+ *

+ * If there are still multiple blocks with the same number of cations, the + * blocks are compared caption-wise. The block with all captions being longer + * or equal to all other blocks' captions wins. + *

+ * + * @param found_blocks + * The List of semantically equal blocks. + * @return Returns the best choice FoundBlock. + * @throws SignatureException + */ + public static FoundBlock chooseMostPossibleBlock(List found_blocks) throws SignatureException + { + // int largest_block_index = 0; + // FoundBlock largest_block = (FoundBlock) found_blocks.get(0); + // + // for (int i = 1; i < found_blocks.size(); i++) + // { + // FoundBlock current_block = (FoundBlock) found_blocks.get(i); + // + // if (current_block.found_keys.size() > largest_block.found_keys.size()) + // { + // largest_block = current_block; + // largest_block_index = i; + // } + // } + + List vertically_largest = filterVerticallyLargestBlocks(found_blocks); + if (logger.isDebugEnabled()) + { + logger.debug("vertically largest blocks:"); + for (int i = 0; i < vertically_largest.size(); i++) + { + FoundBlock found_block = (FoundBlock) vertically_largest.get(i); + logger.debug(" #" + i + ": " + found_block); + } + } + + List horizontally_largest = filterHorizontallyLargestBlocks(vertically_largest); + if (logger.isDebugEnabled()) + { + logger.debug("horizontally largest blocks:"); + for (int i = 0; i < horizontally_largest.size(); i++) + { + FoundBlock found_block = (FoundBlock) horizontally_largest.get(i); + logger.debug(" #" + i + ": " + found_block); + } + } + FoundBlock largest_block = (FoundBlock) horizontally_largest.get(0); + logger.debug("Chose largest block: " + largest_block); + return largest_block; + } + + /** + * Filters out all blocks but the vertically largest ones. + * + *

+ * A vertically largest block has the most found keys. + *

+ * + * @param found_blocks + * The List of FoundBlock objects to be filtered. + * @return Returns the List of the vertically largest FoundBlock objects. + */ + public static List filterVerticallyLargestBlocks(List found_blocks) + { + // determine the size of the largest block(s) + int largest_size = Integer.MIN_VALUE; + for (int i = 0; i < found_blocks.size(); i++) + { + FoundBlock fb = (FoundBlock) found_blocks.get(i); + final int current_size = fb.found_keys.size(); + if (current_size > largest_size) + { + largest_size = current_size; + } + } + + // keep all blocks that have the largest_size + List largest_blocks = new ArrayList(); + for (int i = 0; i < found_blocks.size(); i++) + { + FoundBlock fb = (FoundBlock) found_blocks.get(i); + if (fb.found_keys.size() < largest_size) + { + continue; + } + largest_blocks.add(fb); + } + return largest_blocks; + } + + /** + * Filters out all blocks but the horizonally largest ones. + * + *

+ * A vertically largest block has the most found keys. + *

+ * + * @param found_blocks + * The List of FoundBlock objects to be filtered. All of these + * FoundBlock objects must have the same number of found keys. + * @return Returns the List of the horizontally largest FoundBlock objects. + * @throws SignatureException + */ + public static List filterHorizontallyLargestBlocks(List found_blocks) throws SignatureException + { + List horizontally_largest = new ArrayList(); + FoundBlock largest_block = (FoundBlock) found_blocks.get(0); + horizontally_largest.add(largest_block); + + for (int i = 1; i < found_blocks.size(); i++) + { + FoundBlock fb = (FoundBlock) found_blocks.get(i); + + if (isHorizontallyEqual(fb, largest_block)) + { + horizontally_largest.add(fb); + continue; + } + + if (isHorizontallyLarger(fb, largest_block)) + { + horizontally_largest = new ArrayList(); + largest_block = fb; + horizontally_largest.add(largest_block); + } + else + { + if (!isHorizontallyLarger(largest_block, fb)) + { + // The block is neither equal nor larger nor lower. + // We cannot exactly determine which one to use. + throw new SignatureException(315, "The blocks are neither larger nor lower nor equal. Cannot decide which one to pick. fb = " + fb + ", largest_block = " + largest_block); + } + } + + } + + return horizontally_largest; + } + + protected static boolean isHorizontallyEqual(FoundBlock fb0, FoundBlock fb1) + { + final int num_keys = fb0.found_keys.size(); + if (num_keys != fb1.found_keys.size()) + { + throw new IllegalArgumentException("Cannot compare FoundBlock keys: fb0 doesn't have the same number of keys as fb1. " + fb0.found_keys.size() + " vs. " + fb1.found_keys.size()); + } + + for (int i = 0; i < num_keys; i++) + { + FoundKey fk0 = (FoundKey) fb0.found_keys.get(i); + FoundKey fk1 = (FoundKey) fb1.found_keys.get(i); + + if (fk0.caption.length() != fk1.caption.length()) + { + return false; + } + } + + return true; + } + + protected static boolean isHorizontallyLarger(FoundBlock fb0, FoundBlock fb1) + { + final int num_keys = fb0.found_keys.size(); + if (num_keys != fb1.found_keys.size()) + { + throw new IllegalArgumentException("Cannot compare FoundBlock keys: fb0 doesn't have the same number of keys as fb1. " + fb0.found_keys.size() + " vs. " + fb1.found_keys.size()); + } + + boolean larger = false; + + for (int i = 0; i < num_keys; i++) + { + FoundKey fk0 = (FoundKey) fb0.found_keys.get(i); + FoundKey fk1 = (FoundKey) fb1.found_keys.get(i); + + if (fk0.caption.length() == fk1.caption.length()) + { + continue; + } + + if (fk0.caption.length() > fk1.caption.length()) + { + larger = true; + continue; + } + + // if (fk0.caption.length() < fk1.caption.length()) + return false; + } + + return larger; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ActualTablePos.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ActualTablePos.java new file mode 100644 index 0000000..6c0e56c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ActualTablePos.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf; + +/** + * The actual table position where the signature was placed after signation. + * @author wprinz + */ +public class ActualTablePos +{ + public int page; + + public float x; + + public float y; + + public float width; + + public float height; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AdobeSignatureHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AdobeSignatureHelper.java new file mode 100644 index 0000000..e337e71 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AdobeSignatureHelper.java @@ -0,0 +1,272 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.utils.OgnlUtil; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.AcroFields; +import com.lowagie.text.pdf.PdfDictionary; +import com.lowagie.text.pdf.PdfFormField; +import com.lowagie.text.pdf.PdfName; +import com.lowagie.text.pdf.PdfNumber; +import com.lowagie.text.pdf.PdfObject; +import com.lowagie.text.pdf.PdfSignature; +import com.lowagie.text.pdf.PdfSignatureAppearance; +import com.lowagie.text.pdf.PdfStamper; +import com.lowagie.text.pdf.PdfString; + +/** + * Helper class for creating adobe signature attributes. + * + * @author dferbas + * + */ +public class AdobeSignatureHelper { + private static final String ADOBE_SIGN_FIELDNAME_KEY = "adobeSignFieldValue"; + + private static final String ADOBE_SIGN_REASONNAME_KEY = "adobeSignReasonValue"; + + private static final String ADOBE_SIG_ENABLED_KEY = "adobeSignEnabled"; + + private static Logger logger = Logger.getLogger(AdobeSignatureHelper.class); + + public static final String ADOBE_SIG_FILTER = "Adobe.PDF-AS"; + + public static final String ADOBE_SIG_TEXT_KEY = "adobeSignText"; + + private static final String ADOBE_VERIFY_URL_KEY = "verifyURL"; + + /** + * Writes Adobe-pdf signature entry with itext + * + * @param stamper + * @param si + * @param so + * @param atp + * @throws PresentableException + */ + public static void createAdobeSignatureField(PdfStamper stamper, SignatorInformation si, + SignatureObject so, ActualTablePos atp, StructContentHelper structHelper) throws PresentableException { + + try { + logger.debug("Creating adobe signature field."); + PdfSignatureAppearance sap = stamper.getSignatureAppearance(); + + String profileId = so.getSignatureTypeDefinition().getType(); + String fieldName = getAdobeFieldName(profileId); + // find field num + /* + int nexSigNum = 1; + String finalFieldName = fieldName + " #" + nexSigNum; + + while (stamper.getAcroFields().getField(finalFieldName) != null) { + nexSigNum++; + finalFieldName = fieldName + " #" + nexSigNum; + } + */ + + AcroFields af = stamper.getAcroFields(); + Iterator signatureNamesIt = af.getSignatureNames().iterator(); + PdfName referenceFilterName = new PdfName(ADOBE_SIG_FILTER); + int nextSigNum = 1; + while (signatureNamesIt.hasNext()) { + PdfDictionary dictionary = (PdfDictionary) af.getSignatureDictionary((String) signatureNamesIt.next()); + PdfObject filterName = dictionary.get(PdfName.FILTER); + if (filterName != null && filterName.isName()) { + PdfName name = (PdfName) filterName; + if (referenceFilterName.equals(name)) { + nextSigNum++; + } + } + } + String finalFieldName = fieldName + " #" + nextSigNum; + + sap.setCrypto(null, null, null, null); + // supress overlay text for visible signatures + sap.setLayer2Text(""); + sap.setLayer4Text(""); + + // the following line marks the sig block as adobe sig + // sap.setVisibleSignature(createRectangleFromTablePos(iui.actualTablePos), + // iui.actualTablePos.page, "PDF-AS-Signatur"); + sap.setVisibleSignature(new Rectangle(0, 0, 0, 0), atp.page, finalFieldName); + String subfilter = "unknown"; + if (so != null && so.getKZ() != null) { + subfilter = so.getKZ().toString(); + } else if (si != null) { + subfilter = si.getSignSignatureObject().kz; + } + PdfSignature sig = new PdfSignature(new PdfName(ADOBE_SIG_FILTER), new PdfName(subfilter)); + // the following fields are not shown by the reader, because its is no + // Standard filter + // sig.setLocation("location is not visible"); + // sig.setReason("reason is not visible"); + + // contact field is used to embed signature verification url for adobe handler + String verifyURL = getVerifyUrl(profileId); + if (!StringUtils.isEmpty(verifyURL)) { + sig.setContact(getVerifyUrl(profileId)); + } else { + logger.debug("No verify URL set -> verify URL is not embedded."); + } + // sig.setDate(new PdfDate()); + + String reason = getAdobeReasonName(profileId); + if (!StringUtils.isEmpty(reason)) { + sig.setReason(reason); + } + + + /* disabled in order to align adobe signature appearance for textual signatures with binary signatures + if (si != null) { + XMLGregorianCalendar c = DatatypeFactory.newInstance().newXMLGregorianCalendar( + si.getSignSignatureObject().date); + sig.setDate(new PdfDate(c.toGregorianCalendar())); + } + */ + + sig.setName(getAdobeSignText(profileId, si)); + sap.setCryptoDictionary(sig); + sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED); + + // content element is mandatory but empty + HashMap exc = new HashMap(); + exc.put(PdfName.CONTENTS, new Integer(2)); + + PdfNumber parentNum = structHelper.buildAdobeSigStructParent(); + if (parentNum != null) { + PdfFormField sigField = PdfFormField.createSignature(stamper.getWriter()); + sap.setSigFormField(sigField); + sigField.put(PdfName.STRUCTPARENT, parentNum); + structHelper.buildAdobeSigStruct(sigField, finalFieldName); + } + sap.preClose(exc); // *2+2 + + PdfDictionary dic = new PdfDictionary(); + dic.put(PdfName.CONTENTS, new PdfString((String) null).setHexWriting(true)); + sap.close(dic); + } catch (Exception ex) { + logger.error("error", ex); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "Error creating adobe signature attribute", ex); + } + } + + + /** + * Returns if adobe signature is enabled for the passed signature profile. + * Config key: {@value #ADOBE_SIG_ENABLED_KEY} + * @param sigProfile + * @return + */ + public static boolean isAdobeSignatureFieldEnabled(String sigProfile) { + return "true".equalsIgnoreCase( + getDefaultableConfigProperty(sigProfile, ADOBE_SIG_ENABLED_KEY, "false")); + } + + protected static Rectangle createRectangleFromTablePos(ActualTablePos pos) { + return new Rectangle(pos.x, pos.y, pos.x + pos.width, pos.y - pos.height); + } + + private static String getAdobeFieldName(String sigProfile) { + return getDefaultableConfigProperty(sigProfile, ADOBE_SIGN_FIELDNAME_KEY, "PDF-AS Signatur"); + } + + private static String getAdobeReasonName(String sigProfile) { + return getDefaultableConfigProperty(sigProfile, ADOBE_SIGN_REASONNAME_KEY, "Informationen zur Prüfung finden Sie unter http://www.signaturpruefung.gv.at"); + } + + private static String getVerifyUrl(String sigProfile) { + return getDefaultableConfigProperty(sigProfile, ADOBE_VERIFY_URL_KEY, "http://www.signaturpruefung.gv.at"); + } + + public static String getDefaultableConfigProperty(String sigProfile, String propName, String defaultValue) { + String confVal; + try { + confVal = SettingsReader.getInstance().getSetting( + "sig_obj." + sigProfile + "." + propName, + "default." + propName, + defaultValue); + } catch (SettingsException e) { + logger.warn("error reading " + propName + " from config. Using default: " + defaultValue, e); + return defaultValue; + } + return confVal; + } + + /** + * Evaluate name for adobe signature field. Get from config. Evaluate ognl if + * ok. + * + * @param sigProfile + * @param si + * @return + */ + private static String getAdobeSignText(String sigProfile, SignatorInformation si) { + String defaultName = "PDF-AS"; + try { + logger.debug("reading adobe sig name for profile: " + sigProfile); + String propKey = ADOBE_SIG_TEXT_KEY + ".textual"; + if (si == null) { + propKey = propKey.replaceAll("textual", "binary"); + } + String adobeStr = getDefaultableConfigProperty(sigProfile, propKey, defaultName); + + HashMap ognlCtx = new HashMap(); + OgnlUtil ognl = new OgnlUtil(ognlCtx); + if (ognl.containsExpression(adobeStr)) { + if (si == null) { + logger + .error(ADOBE_SIG_TEXT_KEY + + " ognl expressions not allowed for binary signatures (SignatorInformation not available)"); + return defaultName; + } + ognlCtx.put("si", si); + ognlCtx.put("sso", si.getSignSignatureObject()); + String res = ognl.compileMessage(adobeStr); + return res; + } else { + return adobeStr; + } + + } catch (Exception ex) { + logger.warn("error creating adobe sign text, using default '" + defaultName + "'", ex); + return defaultName; + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java new file mode 100644 index 0000000..2087712 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinaryBlockInfo.java @@ -0,0 +1,61 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinaryBlockInfo.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.List; + +/** + * Helper class that holds information about a binary signature block. + * + * @author wprinz + */ +public class BinaryBlockInfo +{ + /** + * The signed size, in bytes. + * + *

+ * This includes the block itself. + *

+ */ + public int signed_size = -1; + + /** + * The List of ReplaceInfo objects that specify the replaced strings. + */ + public List replaces = null; + +// /** +// * The start of the /ODS number in the PDF. +// */ +// public int ods_start = -1; +// +// /** +// * The start of the \replaces array in the PDF. +// */ +// public int array_start = -1; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java new file mode 100644 index 0000000..ece9525 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java @@ -0,0 +1,2145 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinarySignature.java,v 1.4 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.pdf.CaptionNotFoundException; +import at.gv.egiz.pdfas.exceptions.pdf.KZSettingNotFoundException; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.framework.output.DataSink; +import at.gv.egiz.pdfas.framework.signator.SignatorInformation; +import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderContext; +import at.gv.egiz.pdfas.placeholder.SignaturePlaceholderData; +import at.gv.egiz.pdfas.utils.PDFASUtils; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +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.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureFieldDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypeDefinition; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Image; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.BadPdfFormatException; +import com.lowagie.text.pdf.PRStream; +import com.lowagie.text.pdf.PdfArray; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfDictionary; +import com.lowagie.text.pdf.PdfImage; +import com.lowagie.text.pdf.PdfIndirectObject; +import com.lowagie.text.pdf.PdfIndirectReference; +import com.lowagie.text.pdf.PdfName; +import com.lowagie.text.pdf.PdfNumber; +import com.lowagie.text.pdf.PdfObject; +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.PdfReader; +import com.lowagie.text.pdf.PdfStamper; +import com.lowagie.text.pdf.PdfStamperImp; +import com.lowagie.text.pdf.PdfString; +import com.lowagie.text.pdf.PdfTemplate; + +/** + * Contains various extension functions to digitally sign documents. + * + *

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

+ * + * @author wprinz + */ +public abstract class BinarySignature +{ +//23.11.2010 changed by exthex - added replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) method + + protected static Log logger = LogFactory.getLog(BinarySignature.class); + /** + * The tolerance area of the line break algorithm. + * + * @see Placeholder#replacePlaceholderWithTolerance(byte[], List, byte[], int) + */ + public static final int LINE_BREAK_TOLERANCE = 10; + + /** + * The number of bytes left out for the certificate placeholder. + */ + public static final int CERTIFICATE_PLACEHOLDER_LENGTH = 10000; + + /** + * The number of bytes left out for the timestamp placeholder. + */ + public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; + + /** + * The placeholder character used to fill out Strings in the layout process. + */ + public static final byte LAYOUT_PLACEHOLDER = 'w'; + + /** + * This placeholder is used to fill out holes between the byte ranges before + * the document is signed. + */ + public static final byte SIGN_PLACEHOLDER = 0; + + /** + * The nil brev used to define an unrecognized value. + */ + public static final byte[] BREV_NIL = { 'n', 'i', 'l' }; + + /** + * The date brev. + */ + public static final byte[] BREV_DAT = { 'd', 'a', 't' }; + + /** + * The issure brev. + */ + public static final byte[] BREV_ISS = { 'i', 's', 's' }; + + /** + * The serial number brev. + */ + public static final byte[] BREV_SNR = { 's', 'n', 'r' }; + + /** + * The value brev. + */ + public static final byte[] BREV_VAL = { 'v', 'a', 'l' }; + + /** + * The SIG_ID brev. + */ + public static final byte[] BREV_SID = { 's', 'i', 'd' }; + + /** + * The SIG_ALG brev. + */ + public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; + + /** + * No explicit encoding. + */ + public static final byte[] ENCODING_NIL = { 'n', 'i', 'l' }; + + /** + * PDF WinAnsiEncoding. + */ + public static final byte[] ENCODING_WIN = { 'w', 'i', 'n' }; + + /** + * URL encoding. + */ + public static final byte[] ENCODING_URL = { 'u', 'r', 'l' }; + + /** + * The PDFName of the Egiz Dictionary. + * + *

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

+ */ + public static final PdfName EGIZ_DICT_NAME = new PdfName("EGIZSigDict"); + + /** + * The PDFName of the Original Document Size (ODS) field in an Egiz + * Dictionary. + * + *

+ * The ODS must be a positive integral number. + *

+ */ + public static final PdfName EGIZ_ODS_NAME = new PdfName("ODS"); + + /** + * The PDFName of the Kennzeichnung attribute. + */ + public static final PdfName EGIZ_KZ_NAME = new PdfName("ID"); + + /** + * The PDFName of the /replaces field in an Egiz Dictionary. + */ + public static final PdfName EGIZ_REPLACES_NAME = new PdfName("replaces"); + + /** + * The PDFName of the /encodings field in an Egiz Dictionary. + */ + public static final PdfName EGIZ_ENCODINGS_NAME = new PdfName("encodings"); + + /** + * The PDFName of the byte ranges array. + */ + public static final PdfName EGIZ_BYTERANGES_NAME = new PdfName("ByteRange"); + + /** + * The PdfName of the certificate array. + */ + public static final PdfName EGIZ_CERTIFICATE_NAME = new PdfName("Cert"); + + /** + * The PdfName of the Timestamp + */ + public static final PdfName EGIZ_TIMESTAMP_NAME = new PdfName("TimeStamp"); + + /** + * The PdfName of the data array that contains various egiz-dict data. + */ + public static final PdfName EGIZ_DATA_NAME = new PdfName("Data"); + + /** + * The PDFName of the Signature XObject field in an Egiz Dictionary. + * + *

+ * This must be an indirect reference to the XObject containing the Signature + * table. + *

+ */ + public static final PdfName EGIZ_XOBJ_NAME = new PdfName("SigXObject"); + + /** + * The number placeholder that is used to give numbers a fixed length. + */ + protected static final PdfNumber NUMBER_PLACEHOLDER = new PdfNumber(999999999); + + /** + * Extracts the signature text only. + * + *

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

+ * + * @param egiz_dict + * The Egiz Dictionary. + * + * @return Returns the signature text. + */ + public static String extractSignatureTextOnly(PdfDictionary egiz_dict) throws IOException + { + PdfIndirectReference xobj_ir = (PdfIndirectReference) egiz_dict.get(EGIZ_XOBJ_NAME); + PRStream temp_stream = (PRStream) PdfReader.getPdfObject(xobj_ir); + + byte[] stream_bytes = PdfReader.getStreamBytes(temp_stream); + + return Utils.extractPureTextFromContentStream(stream_bytes); + } + + /** + * Retrieves the size of the original document from the Egiz Dictionary. + * + * @param egiz_dict + * The Egiz Dictionary. + * @return Returns the size (in bytes) of the original document. + */ + public static int getOriginalDocumentSizeFromEgizDict(PdfDictionary egiz_dict) + { + PdfObject ods_obj = egiz_dict.get(EGIZ_ODS_NAME); + PdfNumber ods_number = (PdfNumber) PdfReader.getPdfObject(ods_obj); + + return ods_number.intValue(); + } + + /** + * Retrieves the previous Egiz dictionary from the given one, if a previous + * dictionary exists. + * + * @param egiz_dict + * The Egiz Dictionary. + * @return Returns the previous Egiz Dictionary, or null if there is none. + */ + public static PdfDictionary getPreviousFromEgizDict(PdfDictionary egiz_dict) + { + PdfObject prev_obj = egiz_dict.get(PdfName.PREV); + PdfDictionary previous_dict = (PdfDictionary) PdfReader.getPdfObject(prev_obj); + return previous_dict; + } + + /** + * Retrieves the Egiz Dictionary from the document if present. + * + * @param reader + * The reader to retrieve the dictionary from. + * @return Returns the Egiz Dictionary, if present, or returns null, if no + * egiz dictionary was found. + */ + public static PdfDictionary getEgizDictFromReader(PdfReader reader) + { + PdfIndirectReference dict_ir = getEgizDictIndRefFromReader(reader); + if (dict_ir == null) + { + return null; + } + + PdfDictionary egiz_dict = (PdfDictionary) PdfReader.getPdfObject(dict_ir); + + return egiz_dict; + } + + /** + * Retrieves the Egiz Dictionary's indirect reference from the reader. + * + * @param reader + * The reader. + * @return Returns the indirect reference of the Egiz Dictionary, or null, if + * none exists. + */ + public static PdfIndirectReference getEgizDictIndRefFromReader(PdfReader reader) + { + PdfDictionary catalog = reader.getCatalog(); + PdfIndirectReference dict_ir = (PdfIndirectReference) catalog.get(EGIZ_DICT_NAME); + return dict_ir; + } + + /** + * Retrieves the chain of Egiz Dictionaries from the reader. + * + *

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

+ * + * @param reader + * The reader. + * @return Returns the List of PdfDictionaries from the document. + */ + public static List getEgizDictChainFromReader(PdfReader reader) + { + List dicts = new ArrayList(); + + PdfDictionary current_dict = getEgizDictFromReader(reader); + if (current_dict != null) + { + dicts.add(0, current_dict); + + while ((current_dict = getPreviousFromEgizDict(current_dict)) != null) + { + dicts.add(0, current_dict); + } + } + + return dicts; + } + + /** + * Builds a digest of the given data. + * + * @param data + * The data to be digested. + * @param length + * The length of the data portion that should be used for digesting. + * This allows to build the digest only over parts of the data. + * @return Returns the created digest. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static byte[] buildDigest(final byte[] data, final int length) throws PDFDocumentException + { + MessageDigest sha_512 = null; + try + { + sha_512 = MessageDigest.getInstance("SHA-512"); + } + catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + throw new PDFDocumentException(202, "Digest algorithm not supported - NoSuchAlgorithmException", e); + } + + sha_512.reset(); + sha_512.update(data, 0, length); + byte[] digest = sha_512.digest(); + + return digest; + } + + /** + * Retrieves the signable text from the given document. + * + * @param data + * The data. + * @param ods + * The original document size. + * @return Returns the signable text. + */ + public static String retrieveSignableTextFromData(final byte[] data, final int ods) + { + // byte[] digest = buildDigest(data, ods); + String raw_text = CodingHelper.encodeBase64(data);// digest); // data); + + return raw_text; + } + + /** + * Fills the holes in the byte ranges with the SIGN_PLACEHOLDER. + * + * @param data + * The given byte ranged data. + * @param byte_ranges + * The byte ranges. + * @return Returns the filled text. + */ + public static byte[] prepareDataToSign(final byte[] data, final List byte_ranges) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Iterator it = byte_ranges.iterator(); + int last_end = 0; + while (it.hasNext()) + { + StringInfo si = (StringInfo) it.next(); + + for (int i = last_end; i < si.string_start; i++) + { + baos.write(SIGN_PLACEHOLDER); + } + + baos.write(data, si.string_start, si.string_length); + + last_end = si.string_start + si.string_length; + } + byte[] data_to_sign = baos.toByteArray(); + + return data_to_sign; + } + + // TODO old code - remove + // /** + // * Extracts the binary 'text' of a document. + // * + // *

+ // * If the document contains an Egiz Dictionary, which means that it is + // already + // * signed, the binary text is the Base64 coded string of the original + // document + // * followed by the Ascii representation of the signature block. + // *

+ // *

+ // * If the document does not contain an Egiz Dictionary, which means that it + // is + // * unsigned, only the binary Base64 coded original document is returned as + // * binary text. + // *

+ // *

+ // * This function is intented for being used instead of the "text extraction" + // * mechanism used in the plain text Egiz project. + // *

+ // * + // * @param doc + // * The file. + // * @return Returns the binary text of the document. + // * @throws PDFDocumentException + // * Forwarded exception. + // */ + // public static String extractTextBinary(File doc) throws + // PDFDocumentException + // { + // try + // { + // FileInputStream fis = new FileInputStream(doc); + // return extractTextBinary(fis); + // } + // catch (FileNotFoundException e) + // { + // throw new PDFDocumentException(202, e); + // } + // } + // + // /** + // * Extracts the text binary. + // * + // * @param is + // * @return Returns the binary text. + // * @throws PDFDocumentException + // */ + // public static String extractTextBinary(InputStream is) throws + // PDFDocumentException + // { + // try + // { + // // for some stupid reason this produces a read error if the is comes from + // // a + // // multipart servlet form..??? + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // int i = -1; + // int acc = 0; + // byte[] b = new byte[1000]; + // while ((i = is.read(b)) > 0) + // { + // acc += i; + // System.out.print(" " + i); + // baos.write(b, 0, i); + // } + // System.out.println("acc = " + acc); + // byte[] pdf = baos.toByteArray(); + // + // return extractTextBinary(pdf); + // } + // catch (IOException e) + // { + // throw new PDFDocumentException(202, e); + // } + // } + // + // /** + // * Extracts the signable text from a binary pdf document. + // * + // *

+ // * The signable text is the text that will be signed or verified afterwards. + // *

+ // * + // * @param pdf + // * The pdf document. + // * @return Returns the extracted text String. + // * @throws PDFDocumentException + // * Forwarded exception. + // */ + // public static String extractTextBinary(final byte[] pdf) throws + // PDFDocumentException + // { + // try + // { + // PdfReader reader = new PdfReader(new ByteArrayInputStream(pdf)); + // PdfDictionary egiz_dict = getEgizDictFromReader(reader); + // if (egiz_dict == null) + // { + // System.out.println("NO Egiz Dict found - whole doc = original doc"); + // + // int ods = pdf.length; + // return retrieveSignableTextFromData(pdf, ods); + // } + // + // String sig_text = extractSignatureTextOnly(egiz_dict); + // + // int ods = getOriginalDocumentSizeFromEgizDict(egiz_dict); + // + // String raw_text = retrieveSignableTextFromData(pdf, ods); + // raw_text += "\n"; + // raw_text += sig_text; + // + // return raw_text; + // } + // catch (IOException e) + // { + // throw new PDFDocumentException(202, e); + // } + // } + + // TODO obsolete code - remove + // /** + // * Retrieves the List of SignatureHolders containing the information of all + // * digital signatures of the given document. + // * + // *

+ // * If the List of SignatureHolders is empty, the document is not signed + // * anyways. + // *

+ // * + // * @param pdf + // * The complete pdf document. + // * @return Returns the List of SignatureHolders. + // * @throws PDFDocumentException + // * @throws SignatureTypesException + // * @throws SignatureException + // */ + // public static List extractSignatureHoldersBinary(final byte[] pdf) throws + // PDFDocumentException, SignatureTypesException, SignatureException + // { + // try + // { + // PdfReader reader = new PdfReader(new ByteArrayInputStream(pdf)); + // List chain = getEgizDictChainFromReader(reader); + // + // List signatures = new ArrayList(); + // Iterator it = chain.iterator(); + // while (it.hasNext()) + // { + // PdfDictionary dict = (PdfDictionary) it.next(); + // + // int ods = getOriginalDocumentSizeFromEgizDict(dict); + // String signature_text = extractSignatureTextOnly(dict); + // + // SignatureTypes sig_types = SignatureTypes.getInstance(); + // List types = sig_types.getSignatureTypeDefinitions(); + // SignatureBlock sig_block = new SignatureBlock(types); + // boolean could_separate = sig_block.separateBlockFromRawText(signature_text, + // false); + // + // if (could_separate) + // { + // SignatureObject sig_object = sig_block.getSignatureObject(); + // + // SignatureHolder holder = new BinarySignatureHolder(pdf, ods, sig_object); + // signatures.add(holder); + // } + // } + // + // return signatures; + // } + // catch (IOException e) + // { + // throw new PDFDocumentException(201, e); + // } + // } + + // /** + // * Signs a document with the given signature table using the Incremental + // * Update method. + // * + // *

+ // * The table containing the signature text will be appended. As specified by + // * the parameters, the signature will be appended to the last page, or a + // plain + // * new page will be created for the signature to hold. + // *

+ // *

+ // * The table will be completely wrapped by an XObject, which will also be + // * indirectly referenced by the Egiz Dictionary. This will ease the + // * verification process. + // *

+ // *

+ // * An Egiz Dictionary will be added to the new document that contains + // * information about the signature. Basically the size of the original + // * document and the reference of the signature table. + // *

+ // * + // * @param original_document + // * The file name of the original document. + // * @param new_document + // * The file name of the new document to be created. + // * @param pdf_table + // * The PdfPTable that contains the signature block. + // * @param pos_x + // * The x position where the table should be inserted. + // * @param pos_y + // * The y position where the table should be inserted (on the last + // * page). If this is negative, a new page will be appended to the + // * document. Then the table will be inserted on that new page using + // * the absolute value of pos_y. Note that pos_y specifies the top + // * line of the table. + // * @throws PresentableException + // * Forwarded exception. + // * + // * @see #writeIncrementalUpdate(byte[], PdfPTable, float, float, boolean) + // */ + // public static void writeIncrementalUpdate(String original_document, + // String new_document, PdfPTable pdf_table, float pos_x, float pos_y, + // int egiz_dict_num_replaces) throws PresentableException + // { + // try + // { + // File original_document_file = new File(original_document); + // FileInputStream fis = new FileInputStream(original_document_file); + // byte[] pdf = new byte[(int) original_document_file.length()]; + // fis.read(pdf); + // fis.close(); + // + // byte[] signed_pdf = writeIncrementalUpdate(pdf, pdf_table, pos_x, pos_y, + // egiz_dict_num_replaces); + // + // File new_document_file = new File(new_document); + // FileOutputStream fos = new FileOutputStream(new_document_file); + // fos.write(signed_pdf); + // fos.close(); + // } + // catch (IOException e) + // { + // throw new PresentableException(e); + // } + // } + + protected static int getLineBreakTolerance(IncrementalUpdateInformation iui) throws PDFDocumentException + { + SettingsReader settings; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new PDFDocumentException(e.getErrorCode(), e); + } + String phLineBreakTolerance = SignatureTypeDefinition.readPhLenStringFromSettings(settings, iui.signProfile, "line_break_tolerance"); + int lineBreakTolerance = LINE_BREAK_TOLERANCE; + if (phLineBreakTolerance != null) + { + lineBreakTolerance = Integer.parseInt(phLineBreakTolerance); + } + return lineBreakTolerance; + } + + protected static int getCertificatePlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException + { + SettingsReader settings; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new SettingNotFoundException(e); + } + String certPhLen = SignatureTypeDefinition.readPhLenStringFromSettings(settings, iui.signProfile, "certificate"); + int certLen = CERTIFICATE_PLACEHOLDER_LENGTH; + if (certPhLen != null) + { + certLen = Integer.parseInt(certPhLen); + } + return certLen; + } + + protected static int getTimestampPlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException + { + SettingsReader settings; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new SettingNotFoundException(e); + } + String phLen = SignatureTypeDefinition.readPhLenStringFromSettings(settings, iui.signProfile, "timestamp"); + int tsLen = TIMESTAMP_PLACEHOLDER_LENGTH; + if (phLen != null) + { + tsLen = Integer.parseInt(phLen); + } + return tsLen; + } + + /** + * Signs a document with the given signature table using the Incremental + * Update method. + * + *

+ * The table containing the signature text will be appended. As specified by + * the parameters, the signature will be appended to the last page, or a plain + * new page will be created for the signature to hold. + *

+ *

+ * The table will be completely wrapped by an XObject, which will also be + * indirectly referenced by the Egiz Dictionary. This will ease the + * verification process. + *

+ *

+ * An Egiz Dictionary will be added to the new document that contains + * information about the signature. Basically the size of the original + * document and the reference of the signature table. + *

+ * + * @param original_document + * The original document. + * @param pdf_table + * The PdfPTable that contains the signature block. + * @param pi + * The PositioningInstruction telling the algorithm where to place + * the signature block. + * @param invisible_field_definitions + * List of invisible field definitions to be added to the egiz dict. + * May be null or empty, if there are no invisible fields. + * @param invisibleKZString + * If not null, thins String is the KZ String to be written into the + * /Data array. + * @return Returns the new document. + * @throws PresentableException + * Forwarded exception. + */ + public static IncrementalUpdateInformation writeIncrementalUpdate(PdfDataSource original_document, DataSink written_pdf, PdfPTable pdf_table, String profile, PositioningInstruction pi, + List variable_field_definitions, List all_field_definitions, List invisible_field_definitions, String invisibleKZString, TimeStamper timeStamper, SignatorInformation si, SignatureObject so) throws PresentableException + { + try + { + IncrementalUpdateInformation iui = new IncrementalUpdateInformation(); + iui.original_document = original_document; + iui.start_index = original_document.getLength(); + iui.signProfile = profile; + iui.timeStamper = timeStamper; + + Document.compress = true; // exthex : compress now, excluding the xobject later + + // System.out.println("wprinz: STAMPING PDF"); + + // InputStream is = original_document.createInputStream(); + byte[] pdf_data = original_document.getAsByteArray(); + PdfReader reader = new PdfReader(pdf_data); + PDFASUtils.checkReaderPermissions(reader); + // is.close(); + + OutputStream baos = written_pdf.createOutputStream("application/pdf"); + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // IMPORTANT: append the new content to the original document using + // incremental updated + // The stamper allows this by setting append = true + boolean adobeSigField = AdobeSignatureHelper.isAdobeSignatureFieldEnabled(so.getSignatureTypeDefinition().getType()); + PdfStamper stamper = null; + if (adobeSigField) { + stamper = PdfStamper.createSignature(reader, baos, '\0', null, true); + } else { + stamper = new PdfStamper(reader, baos, '\0', true); + } + + if (pi.isMakeNewPage()) + { + int pdf_page_num = reader.getNumberOfPages(); + + Rectangle psize = reader.getPageSizeWithRotation(pdf_page_num); + Rectangle rect = new Rectangle(psize); + stamper.insertPage(pdf_page_num + 1, rect); + } + + if (pi.getPage() < 1 || pi.getPage() > stamper.getReader().getNumberOfPages()) + { + throw new PDFDocumentException(224, "The provided page (=" + pi.getPage() + ") is out of range."); + } + + if (SignaturePlaceholderContext.isSignaturePlaceholderDataSet() && + SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName() != null) + { + replacePlaceholder(stamper, pi.getPage(), SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName()); + } + + PdfContentByte content = stamper.getOverContent(pi.getPage()); + // content = StampContent einer PageStamp. + + // System.out.println("table_width = " + pdf_table.getTotalWidth() + ", + // table_height = " + pdf_table.getTotalHeight()); + + PdfTemplate table_template = content.createTemplate(pdf_table.getTotalWidth(), pdf_table.getTotalHeight()); + table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig + + // exthex + StructContentHelper structHelper = new StructContentHelper(stamper, content, pi.getPage()); + structHelper.prepareStructData(table_template); + + pdf_table.writeSelectedRows(0, -1, 0, pdf_table.getTotalHeight(), table_template); + + // table_template.moveTo(0, 0); + // table_template.lineTo(pdf_table.getTotalWidth(), + // pdf_table.getTotalHeight()); + // table_template.stroke(); + // table_template.moveTo(0, 0); + // table_template.lineTo(100, 100); + // table_template.stroke(); + + // pdf_table.writeSelectedRows(0, -1, SIGNATURE_BORDER / 2, + // table_position, content); + + + structHelper.beginSigBlockContent(); + + content.addTemplate(table_template, pi.getX(), pi.getY() - pdf_table.getTotalHeight()); + + structHelper.endSigBlockContent(); + + + ActualTablePos atp = new ActualTablePos(); + atp.page = pi.getPage(); + atp.x = pi.getX(); + atp.y = pi.getY(); // TODO is this correct or flipped? + atp.width = pdf_table.getTotalWidth(); + atp.height = pdf_table.getTotalHeight(); + iui.actualTablePos = atp; + + structHelper.buildFigureStructData(so, table_template); + structHelper.buildSigBlockStructData(); + structHelper.finishMainStructData(); + + structHelper.buildVerifyLinkStructData(table_template, atp); + + // For debugging print a 100x100 grid + // { + // Rectangle psize = reader.getPageSizeWithRotation(pos.page); + // float page_width = psize.width(); + // float page_height = psize.height(); + // for (float x = 0; x < page_width; x += 100) + // { + // content.moveTo(x, 0); + // content.lineTo(x, page_height); + // content.stroke(); + // } + // for (float y = 0; y < page_height; y += 100) + // { + // content.moveTo(0, y); + // content.lineTo(page_width, y); + // content.stroke(); + // } + // } + + // content.setLineWidth(10.0f); + // content.moveTo(0, 0); + // content.lineTo(100, 100); + // content.stroke(); + + // PdfIndirectReference page_ref = + // stamper.getWriter().getPageReference(signature_page); + // System.out.println("page_ref = " + page_ref.toString()); + + // PdfObject page_obj = PdfReader.getPdfObject(page_ref); + // System.out.println("page_obj = " + page_obj); + + // PdfDictionary page_dict = (PdfDictionary) page_obj; + // PdfObject resources_obj = page_dict.get(PdfName.RESOURCES); + // System.out.println("resources_obj = " + resources_obj); + // PdfDictionary resources = (PdfDictionary) + // PdfReader.getPdfObject(resources_obj); + // for (Iterator it = resources.getKeys().iterator(); it.hasNext();) + // { + // PdfName key = (PdfName) it.next(); + // PdfObject value = resources.get(key); + // System.out.println(" " + key + " = " + value); + // } + + // add the EGIZ dict: + if (variable_field_definitions != null) + { + createEgizDict(stamper, table_template, iui, variable_field_definitions, all_field_definitions, invisible_field_definitions, invisibleKZString); + } + + if (adobeSigField) { + AdobeSignatureHelper.createAdobeSignatureField(stamper, si, so, atp, structHelper); // here..., stamper is closed + } else { + stamper.close(); + } + // System.out.println("wprinz: STAMPING FINISHED"); + + // just to make sure the stream is really closed + baos.close();// + //org.apache.commons.io.FileUtils.writeByteArrayToFile(new java.io.File("C:/out.pdf"), ((at.gv.egiz.pdfas.impl.output.ByteArrayDataSink) written_pdf).getByteArray()); + // iui.signed_pdf = baos.toByteArray(); + + structHelper.removeCurrent(); + return iui; + } + catch (IOException e) + { + e.printStackTrace(); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); + } + catch (DocumentException e) + { + e.printStackTrace(); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); + } + } + + private static void replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) throws BadElementException, MalformedURLException, IOException, BadPdfFormatException, PresentableException { + Image img = Image.getInstance(SignaturePlaceholderData.class.getResource("empty.jpg")); + PdfImage pImg = new PdfImage(img, "Imwurscht", null); + PdfStamperImp stamperImp = (PdfStamperImp)stamper.getWriter(); + PdfIndirectObject ind = stamperImp.addToBody(pImg); + + PdfDictionary resources = stamper.getReader().getPageN(pageNr).getAsDict(PdfName.RESOURCES); + if (ind != null && resources != null) + { + PdfDictionary xobjDict = resources.getAsDict(PdfName.XOBJECT); + if (xobjDict != null) + { + xobjDict.put(new PdfName(placeholderName), ind.getIndirectReference()); + stamperImp.markUsed(resources); + } + else + { + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, new NullPointerException("Image dictionary not found in document structure!")); + } + } + else + { + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, new NullPointerException("Resource dictionary not found in document structure!")); + } + } + + + /** + * Creates the EGIZ Dictionary and adds it to the document. + * + * @param stamper + * The PdfStamper. + * @param table_template + * The Template of the Signature block. + * @param iui + * The IncrementalUpdateInformation. + * @param variable_field_definitions + * The field definitions. + * @throws IOException + * @throws SettingNotFoundException + * @throws CaptionNotFoundException + */ + protected static void createEgizDict(PdfStamper stamper, PdfTemplate table_template, IncrementalUpdateInformation iui, List variable_field_definitions, List all_field_definitions, + List invisible_field_definitions, String invisibleKZString) throws IOException, SettingNotFoundException, CaptionNotFoundException + { + // iui.temp_ir = table_template.getIndirectReference(); + iui.temp_ir_number = table_template.getIndirectReference().getNumber(); + iui.temp_ir_generation = table_template.getIndirectReference().getGeneration(); + + byte[] content_stream = table_template.toPdf(null); + iui.content_stream_length = content_stream.length; + + iui.replaces = determineReplacesInContentStream(content_stream, 0, content_stream.length, variable_field_definitions); + if (invisibleKZString == null) + { + iui.kz_list = determineKZ(content_stream, 0, content_stream.length, all_field_definitions); + } + else + { + StringInfo si = new StringInfo(); + si.string_start = -1; + si.string_length = invisibleKZString.length(); + + iui.kz_list = new ArrayList(); + iui.kz_list.add(si); + } + + // PdfIndirectReference previous_egiz_dict_ind_ref = + // getEgizDictIndRefFromReader(reader); + + PdfDictionary egiz_dict = new PdfDictionary(EGIZ_DICT_NAME); + egiz_dict.put(EGIZ_XOBJ_NAME, table_template.getIndirectReference()); + egiz_dict.put(EGIZ_ODS_NAME, NUMBER_PLACEHOLDER); + + // /ID + PdfArray kz_array = new PdfArray(); + for (int i = 0; i < iui.kz_list.size(); i++) + { + kz_array.add(NUMBER_PLACEHOLDER); // start + kz_array.add(NUMBER_PLACEHOLDER); // length + } + egiz_dict.put(EGIZ_KZ_NAME, kz_array); + + // ByteRanges + int num_replaces = calcNumReps(iui.replaces); + int num_holes = num_replaces + 1 + 1; + // +1 = the /encodings hole + // +1 = the /Cert + // +1 = the /Timestamp + if (iui.timeStamper != null) { + num_holes += 1; + } + boolean has_hidden_variable_fields = invisible_field_definitions != null && !invisible_field_definitions.isEmpty(); + if (has_hidden_variable_fields) + { + num_holes += invisible_field_definitions.size(); + } + int num_byte_ranges = num_holes + 1; + + PdfArray byte_ranges_array = new PdfArray(); + for (int i = 0; i < num_byte_ranges; i++) + { + byte_ranges_array.add(NUMBER_PLACEHOLDER); // start + byte_ranges_array.add(NUMBER_PLACEHOLDER); // length + } + egiz_dict.put(EGIZ_BYTERANGES_NAME, byte_ranges_array); + + PdfArray encodings_array = new PdfArray(); + encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the + // /encodings + encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the /Cert + + // array itself + PdfArray replaces_array = new PdfArray(); + replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the + // /encodings + replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the + // /Cert + + if (iui.timeStamper != null) { + encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the /Timestamp + replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the /timestamp + + } + + // hidden replaces + List hidden_replaces = null; + if (has_hidden_variable_fields) + { + hidden_replaces = new ArrayList(); + + Iterator it = invisible_field_definitions.iterator(); + while (it.hasNext()) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + byte[] brev = typeToBrev(sfd.field_name); + encodings_array.add(new PdfName(new String(ENCODING_WIN, "US-ASCII"))); + replaces_array.add(new PdfName(new String(brev, "US-ASCII"))); + + ReplaceInfo ri = new ReplaceInfo(); + ri.brev = brev; + ri.enc = ENCODING_WIN; + ri.sfd = sfd; + ri.replaces = new ArrayList(); + + StringInfo si = new StringInfo(); + si.string_start = -1; // to be determined later on + si.string_length = sfd.placeholder_length; + ri.replaces.add(si); + + hidden_replaces.add(ri); + } + } + + // content stream replaces + Iterator it = iui.replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + for (int i = 0; i < ri.replaces.size(); i++) + { + byte[] brev = typeToBrev(ri.sfd.field_name); + encodings_array.add(new PdfName(new String(ENCODING_WIN, "US-ASCII"))); + replaces_array.add(new PdfName(new String(brev, "US-ASCII"))); + } + } + egiz_dict.put(EGIZ_REPLACES_NAME, replaces_array); + + egiz_dict.put(EGIZ_ENCODINGS_NAME, encodings_array); + + PdfArray cert_array = new PdfArray(); + iui.cert_length = getCertificatePlaceholderLength(iui); + byte[] cert_bytes = new byte[iui.cert_length]; + for (int i = 0; i < cert_bytes.length; i++) + { + cert_bytes[i] = 0; + } + PdfString cert_placeholder = new PdfString(cert_bytes); + cert_array.add(cert_placeholder); + egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); + + // Timestamp + if (iui.timeStamper != null) { + // only if handler is available + PdfArray timestamp_array = new PdfArray(); + iui.timestamp_length = getTimestampPlaceholderLength(iui); + byte[] timestamp_bytes = new byte[iui.timestamp_length]; + for (int i = 0; i < timestamp_bytes.length; i++) + { + timestamp_bytes[i] = 0; + } + PdfString timestamp_placeholder = new PdfString(timestamp_bytes); + timestamp_array.add(timestamp_placeholder); + egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); + } + + + // /Data array with hidden information + if (has_hidden_variable_fields || invisibleKZString != null) + { + PdfArray hidden_fields_array = new PdfArray(); + + if (invisibleKZString != null) + { + PdfString str = new PdfString(invisibleKZString); + hidden_fields_array.add(str); + } + + if (has_hidden_variable_fields) + { + iui.replaces.addAll(0, hidden_replaces); + + for (int i = 0; i < invisible_field_definitions.size(); i++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) invisible_field_definitions.get(i); + byte[] placeholder = new byte[sfd.placeholder_length]; + for (int phIdx = 0; phIdx < placeholder.length; phIdx++) + { + placeholder[phIdx] = SIGN_PLACEHOLDER; + } + PdfString str = new PdfString(placeholder); + hidden_fields_array.add(str); + } + } + + egiz_dict.put(EGIZ_DATA_NAME, hidden_fields_array); + } + + + PdfIndirectObject dict_ref = stamper.getWriter().addToBody(egiz_dict); + // iui.egiz_dict_ir = dict_ref.getIndirectReference(); + iui.egiz_dict_ir_number = dict_ref.getIndirectReference().getNumber(); + iui.egiz_dict_ir_generation = dict_ref.getIndirectReference().getGeneration(); + + PdfIndirectReference root_ref = (PdfIndirectReference) stamper.getReader().getTrailer().get(PdfName.ROOT); + PdfDictionary root = (PdfDictionary) PdfReader.getPdfObject(root_ref); + // root.put(EGIZ_DICT_NAME, dict_ref.getIndirectReference()); + ((PdfStamperImp) stamper.getWriter()).markUsed(root); + + // PdfDictionary extra_cata = stamper.getWriter().getExtraCatalog(); + // extra_cata.put(dict_type, dict_ref.getIndirectReference()); + + ((PdfStamperImp) stamper.getWriter()).setEgizDictTrailerInfo(EGIZ_DICT_NAME, dict_ref.getIndirectReference()); + } + + /** + * Converts a field name (type) to the corresponding BREV. + * + * @param type + * The field name (type). + * @return Returns the corresponding BREV, or BREV_NIL if the type is not + * recognized. + */ + protected static byte[] typeToBrev(String type) + { + if (type.equals(SignatureTypes.SIG_DATE)) + { + return BREV_DAT; + } + if (type.equals(SignatureTypes.SIG_ISSUER)) + { + return BREV_ISS; + } + if (type.equals(SignatureTypes.SIG_VALUE)) + { + return BREV_VAL; + } + if (type.equals(SignatureTypes.SIG_NUMBER)) + { + return BREV_SNR; + } + if (type.equals(SignatureTypes.SIG_ID)) + { + return BREV_SID; + } + if (type.equals(SignatureTypes.SIG_ALG)) + { + return BREV_ALG; + } + + + return BREV_NIL; + } + + /** + * Updates the information in the egiz dictionary to reflect the real offsets + * of the byte ranges. + * + *

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

+ * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void markByteRanges(IncrementalUpdateInformation iui) throws PDFDocumentException + { + try + { + iui.byte_ranges = new ArrayList(); + + int num_digits = Integer.toString(NUMBER_PLACEHOLDER.intValue()).length(); + byte[] signed_pdf = iui.signed_pdf; + + String str = iui.egiz_dict_ir_number + " " + iui.egiz_dict_ir_generation + " obj"; + byte[] obj_bytes = ArrayUtils.add(str.getBytes("US-ASCII"), 0, (byte) 0x0A); + int obj_index = ByteArrayUtils.lastIndexOf(signed_pdf, obj_bytes); + int obj_start = obj_index + obj_bytes.length; + + String ods_str = "/ODS "; + byte[] ods_bytes = ods_str.getBytes("US-ASCII"); + int ods_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, ods_bytes); + int ods_start = ods_index + ods_bytes.length; + + String kz_str = "/ID["; + byte[] kz_bytes = kz_str.getBytes("US-ASCII"); + int kz_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, kz_bytes); + int kz_start = kz_index + kz_bytes.length; + + String br_str = "/ByteRange["; + byte[] br_bytes = br_str.getBytes("US-ASCII"); + int br_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, br_bytes); + int array_start = br_index + br_bytes.length; + + String enc_str = "/encodings["; + byte[] enc_bytes = enc_str.getBytes("US-ASCII"); + int enc_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, enc_bytes); + int enc_start = enc_index + enc_bytes.length; + + String cert_str = "/Cert[("; + byte[] cert_bytes = cert_str.getBytes("US-ASCII"); + int cert_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, cert_bytes); + int cert_start = cert_index + cert_bytes.length; + + //Timestamp + int timestamp_index = 0; + int timestamp_start = 0; + if (iui.timeStamper != null) { + String timestamp_str = "/TimeStamp[("; + byte[] timestamp_bytes = timestamp_str.getBytes("US-ASCII"); + timestamp_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, timestamp_bytes); + timestamp_start = timestamp_index + timestamp_bytes.length; + } + + replaceNumber(signed_pdf, ods_start, signed_pdf.length, num_digits); + + + int cur_pos = array_start; + int cur_br_start = 0; + + + // write the /encodings byte range + { + int num_replaces = calcNumReps(iui.replaces); + int num_holes = num_replaces + 1 + 1; + // +1 = the /encodings hole + // +1 = the /Cert + // +1 = the /Timestamp + if (iui.timeStamper != null) { + num_holes += 1; + } + + int enc_length = (1 + 3) * num_holes; + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = enc_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = enc_start + enc_length; + + iui.enc_start = enc_start; + iui.enc_length = enc_length; + } + + // write the /Cert byte range + { + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = cert_start - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = cert_start + iui.cert_length; + + iui.cert_start = cert_start; + } + + // write the /Timestamp byte range + if (iui.timeStamper != null) { + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = timestamp_start - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = timestamp_start + iui.timestamp_length; + + iui.timestamp_start = timestamp_start; + } + + // determine the /Data byte ranges if any + List ifd = iui.invisible_field_definitions; + if (!ifd.isEmpty() || iui.invisibleKZString != null) + { + String data_str = "/Data[("; + byte[] data_bytes = data_str.getBytes("US-ASCII"); + int data_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, data_bytes); + int data_start = data_index + data_bytes.length; + + int hole_start = data_start; + + if (iui.invisibleKZString != null) + { + StringInfo si = (StringInfo) iui.kz_list.get(0); + si.string_start = hole_start; + + hole_start += si.string_length + 2; + } + + for (int i = 0; i < ifd.size(); i++) + { + ReplaceInfo ri = (ReplaceInfo) iui.replaces.get(i); + StringInfo si = (StringInfo) ri.replaces.get(0); + si.string_start = hole_start; + + hole_start += si.string_length + 2; + } + + } + + Iterator rit = iui.replaces.iterator(); + while (rit.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) rit.next(); + + // byte [] value_bytes = ri.value.getBytes("ISO-8859-1"); + // int write_pos = 0; + + Iterator sit = ri.replaces.iterator(); + while (sit.hasNext()) + { + StringInfo si = (StringInfo) sit.next(); + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = si.string_start - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + cur_br_start = si.string_start + si.string_length; + } + + } + + StringInfo byte_range = new StringInfo(); + byte_range.string_start = cur_br_start; + byte_range.string_length = signed_pdf.length - cur_br_start; + iui.byte_ranges.add(byte_range); + + replaceNumber(signed_pdf, cur_pos, byte_range.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, byte_range.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + + + // update the Kennzeichnung byte ranges + cur_pos = kz_start; + for (int i = 0; i < iui.kz_list.size(); i++) + { + StringInfo si = (StringInfo) iui.kz_list.get(i); + + replaceNumber(signed_pdf, cur_pos, si.string_start, num_digits); + cur_pos += num_digits; + cur_pos += 1; + replaceNumber(signed_pdf, cur_pos, si.string_length, num_digits); + cur_pos += num_digits; + cur_pos += 1; + } + + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + + } + + /** + * Replaces the certificate placeholder with the certificate from the signed + * Signature Object. + * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void replaceCertificate(IncrementalUpdateInformation iui) throws PDFDocumentException + { + X509Certificate certificate = iui.signed_signature_object.getX509Certificate(); + try + { + byte[] der = certificate.getEncoded(); + byte[] encoded = CodingHelper.encodeBase64(der).getBytes("US-ASCII"); + byte[] escaped = Placeholder.escapePDFString(encoded); + if (escaped.length > iui.cert_length) + { + throw new PlaceholderException("certificate", escaped.length - iui.cert_length); + } + System.arraycopy(escaped, 0, iui.signed_pdf, iui.cert_start, escaped.length); + } + catch (CertificateEncodingException e) + { + throw new PDFDocumentException(300, e); + } + catch (UnsupportedEncodingException e) + { + throw new PDFDocumentException(300, e); + } + + // X509Cert cert = iui.signed_signature_object.getX509Cert(); + // // X509Certificate certificate = cert.getX509Certificate(); + // try + // { + // byte[] encoded = cert.getCertString().getBytes("US-ASCII"); // + // certificate.getEncoded(); + // byte[] escaped = Placeholder.escapePDFString(encoded); + // if (escaped.length > iui.cert_length) + // { + // throw new PlaceholderException("certificate", escaped.length - + // iui.cert_length); + // } + // System.arraycopy(escaped, 0, iui.signed_pdf, iui.cert_start, + // escaped.length); + // } + // // catch (CertificateEncodingException e) + // // { + // // throw new PDFDocumentException(300, e); + // // } + // catch (UnsupportedEncodingException e) + // { + // throw new PDFDocumentException(300, e); + // } + } + + /** + * Replaces the timestam placeholder with the timestamp from the signed + * Signature Object. + * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void replaceTimestamp(IncrementalUpdateInformation iui) throws PDFDocumentException + { + String timestamp = iui.signed_signature_object.getSigTimeStamp(); + if (timestamp != null) { + byte[] escaped = Placeholder.escapePDFString(timestamp.getBytes()); + if (escaped.length > iui.timestamp_length) + { + throw new PlaceholderException("timestamp", escaped.length - iui.timestamp_length); + } + System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); + } + } + + /** + * Replaces the placeholders with values from the signed SignatureObject. + * + * @param iui + * The IncrementalUpdateInformation. + * @throws PDFDocumentException + */ + public static void replacePlaceholders(IncrementalUpdateInformation iui) throws PDFDocumentException + { + final int lineBreakTolerance = getLineBreakTolerance(iui); + + final byte[] signed_pdf = iui.signed_pdf; + + // int num_replaces = calcNumReps(iui.replaces); + // int num_holes = num_replaces + 1 + 1; // +1 = the /encodings hole; +1 = + // the + // /Cert + + int encoding_entry_index = 0; + {// /encodings itself + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(ENCODING_NIL, 0, signed_pdf, enc_offset + 1, ENCODING_NIL.length); + encoding_entry_index++; + } + {// /Cert itself + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(ENCODING_NIL, 0, signed_pdf, enc_offset + 1, ENCODING_NIL.length); + encoding_entry_index++; + } + if (iui.signed_signature_object.getSigTimeStamp() != null) + {// /Timestamp itself + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(ENCODING_NIL, 0, signed_pdf, enc_offset + 1, ENCODING_NIL.length); + encoding_entry_index++; + } + + for (int i = 0; i < iui.replaces.size(); i++) + { + ReplaceInfo ri = (ReplaceInfo) iui.replaces.get(i); + + try + { + String value = ri.value; + + if (value == null) + { + value = ""; + } + + byte[] encoding = ENCODING_WIN; + byte[] replace_bytes = Placeholder.applyWinAnsiEncoding(value); + + String restored_value = Placeholder.unapplyWinAnsiEncoding(replace_bytes); + if (!value.equals(restored_value)) + { + // debug: + logger.warn("WinAnsiEncoding doesn't fit - using URL instead!"); + // /debug! + + replace_bytes = Placeholder.applyURLEncoding(value); + + encoding = ENCODING_URL; + } + + for (int string_index = 0; string_index < ri.replaces.size(); string_index++) + { + int enc_offset = iui.enc_start + encoding_entry_index * 4; + signed_pdf[enc_offset] = '/'; + System.arraycopy(encoding, 0, signed_pdf, enc_offset + 1, encoding.length); + encoding_entry_index++; + } + + Placeholder.replacePlaceholderWithTolerance(signed_pdf, ri.replaces, replace_bytes, lineBreakTolerance); + } + catch (PlaceholderException e) + { + throw new PlaceholderException(ri.sfd.field_name, e.getMissing()); + } + + } + } + + /** + * Calculates the number of actual String replaces from a given ReplaceInfo + * list. + *

+ * This is used to determine the number of actual replaces that has to be + * carried out. Accordingly to this number, entries in the dictionary are + * created. + *

+ * + * @param replaces + * The ReplaceInfo list. + * @return Returns the number of string replaces. + */ + protected static int calcNumReps(List replaces) + { + int number = 0; + Iterator it = replaces.iterator(); + while (it.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) it.next(); + number += ri.replaces.size(); + } + return number; + } + + /** + * Determines the List of ReplaceInfo objects of replaces in the content + * stream regarding the given field definitions. + * + *

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

+ * + * @param pdf + * The PDF. + * @param begin + * The start of the content stream. + * @param end + * The end of the content stream. + * @param field_definitions + * The field definitions that are counceled to find out which and + * where varaible strings are. + * @return Returns the list of ReplaceInfo objects specifying the variable + * areas. + * @throws CaptionNotFoundException + */ + protected static List determineReplacesInContentStream(final byte[] pdf, int begin, int end, List field_definitions) throws CaptionNotFoundException + { + List replaces = new ArrayList(); + try + { + + List strings = Placeholder.parseStrings(pdf, begin, end); + + for (int index = 0; index < field_definitions.size(); index++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) field_definitions.get(index); + + if (sfd.placeholder_length > 0) + { + ReplaceInfo ri = new ReplaceInfo(); + ri.sfd = sfd; + ri.replaces = new ArrayList(); + + byte[] caption = sfd.caption.getBytes("ISO-8859-1"); + + int caption_index = findIndex(strings, caption); + if (caption_index < 0) + { + throw new CaptionNotFoundException(sfd.caption); + } + int start_index = skipStrings(strings, caption_index, caption); + int next_index = findFirstNotPlaceholder(strings, start_index); + + for (int i = start_index; i < next_index; i++) + { + StringInfo si = (StringInfo) strings.get(i); + ri.replaces.add(si); + } + + replaces.add(ri); + } + } + } + catch (UnsupportedEncodingException e) + { + logger.error(e.getMessage(), e); + } + + // sort replaces + Collections.sort(replaces, new Comparator() { + public int compare(Object arg0, Object arg1) + { + ReplaceInfo ri0 = (ReplaceInfo) arg0; + ReplaceInfo ri1 = (ReplaceInfo) arg1; + int start0 = ((StringInfo) ri0.replaces.get(0)).string_start; + int start1 = ((StringInfo) ri1.replaces.get(0)).string_start; + return start0 - start1; + } + }); + + return replaces; + } + + /** + * Determines the Kennzeichnug in the content stream. + * + * @param pdf + * The PDF. + * @param begin + * The start of the content stream. + * @param end + * The end of the content stream. + * @param field_definitions + * The field definitions. + * @return Returns the List of StringInfo objects representing the KZ field. + * @throws SettingNotFoundException + * F.e. + */ + protected static List determineKZ(final byte[] pdf, int begin, int end, List field_definitions) throws SettingNotFoundException + { + try + { + List strings = Placeholder.parseStrings(pdf, begin, end); + + for (int index = 0; index < field_definitions.size(); index++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) field_definitions.get(index); + + if (sfd.field_name.equals(SignatureTypes.SIG_KZ)) + { + List kz_list = new ArrayList(); + + byte[] caption = sfd.caption.getBytes("ISO-8859-1"); + + int caption_index = findIndex(strings, caption); + int start_index = skipStrings(strings, caption_index, caption); + + int end_index = -1; + for (end_index = start_index; end_index < strings.size(); end_index++) + { + StringInfo si = (StringInfo) strings.get(end_index); + + if (startsWithCaption(si, field_definitions)) + { + break; + } + + kz_list.add(si); + } + + return kz_list; + } + } + } + catch (UnsupportedEncodingException e) + { + logger.error(e.getMessage(), e); + } + throw new KZSettingNotFoundException("Field " + SignatureTypes.SIG_KZ + " not found."); + } + + /** + * Finds the index of the StringInfo within the StringInfo list that has the + * given content (caption). + * + * @param strings + * The list of StringInfos. + * @param caption + * The text to be matched to the strings. + * @return Returns the index of the found string, or -1 if no string matched. + */ + protected static int findIndex(List strings, byte[] caption) + { + for (int i = 0; i < strings.size(); i++) + { + if (isCaption(strings, i, caption)) + { + return i; + } + } + return -1; + } + + protected static boolean isCaption(List strings, int index, byte[] caption) + { + try + { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = index; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + baos.write(si.copyStringBytes()); + } + byte[] str_data = baos.toByteArray(); + byte[] unescaped = Placeholder.unescapePDFString(str_data); + if (ByteArrayUtils.compareByteArrays(unescaped, 0, caption)) + { + return true; + } + else + { + return false; + } + } + catch (IOException e) + { + logger.error(e.getMessage(), e); + return false; + } + + } + + protected static int skipStrings(List strings, int index, byte[] caption) + { + int length = 0; + for (int i = index; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + length += si.string_length; + + if (length >= caption.length) + { + return i + 1; + } + } + return -1; + } + + /** + * Tells, if the given StringInfo contains only placeholder characters. + * + * @param si + * The StringInfo. + * @param placeholder + * The placeholder character. + * @return Returns true, if the string contains only the given placeholder + * characters, false otherwise. + */ + protected static boolean isPlaceholder(StringInfo si, byte placeholder) + { + byte[] string_bytes = si.copyStringBytes(); + for (int i = 0; i < string_bytes.length; i++) + { + if (string_bytes[i] != placeholder) + { + return false; + } + } + return true; + } + + protected static boolean startsWithCaption(StringInfo si, List field_definitions) + { + try + { + for (int i = 0; i < field_definitions.size(); i++) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) field_definitions.get(i); + + String caption = sfd.caption; + String str = si.getString("ISO-8859-1"); + + if (caption.startsWith(str)) + { + return true; + } + } + return false; + } + catch (UnsupportedEncodingException e) + { + logger.error(e.getMessage(), e); + return false; + } + } + + /** + * Finds the first string after and at the given index not being a placeholder + * string. + * + * @param strings + * The list of StringInfos. + * @param start + * The index where to start the search. + * @return Returns the index of the first not placeholder string, or + * strings.size() if no more non placeholder strings could be found. + */ + protected static int findFirstNotPlaceholder(List strings, int start) + { + for (int i = start; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + if (!isPlaceholder(si, LAYOUT_PLACEHOLDER)) + { + return i; + } + } + return strings.size(); + } + + /** + * Restores the given String to its placeholder. + * + * @param pdf + * The PDF. + * @param si + * The string. + * @param placeholder + * The placeholder the string should be filled with. + */ + public static void restorePlaceholder(final byte[] pdf, StringInfo si, final byte placeholder) + { + byte[] ph = new byte[si.string_length]; + for (int i = 0; i < ph.length; i++) + { + ph[i] = placeholder; + } + System.arraycopy(ph, 0, pdf, si.string_start, ph.length); + } + + /** + * Reconstructs the replaces from the PDF and forms suitable value strings. + * + * @param pdf + * The PDF. + * @param brevs + * The brevs. + * @param sis + * The StringInfo objects of the strings. + * @return Returns the List of ReplaceInfo objects containing the restored + * values. + * @throws PDFDocumentException + */ + public static List reconstructReplaces(final byte[] pdf, byte[][] brevs, StringInfo[] sis, byte[][] encodings) throws PDFDocumentException + { + try + { + List replaces = new ArrayList(); + + ReplaceInfo cur_ri = null; + + for (int cur = 0; cur < brevs.length; cur++) + { + if (ByteArrayUtils.compareByteArrays(brevs[cur], 0, BREV_NIL)) + { + continue; + } + + if (cur_ri == null || !ByteArrayUtils.compareByteArrays(cur_ri.brev, 0, brevs[cur])) + { + if (cur >= encodings.length) { + throw new PDFDocumentException(ErrorCode.INVALID_SIGNATURE_DICTIONARY, "Invalid EGIZ signature dictionary."); + } + cur_ri = new ReplaceInfo(); + + cur_ri.replaces = new ArrayList(); + + cur_ri.brev = brevs[cur]; + cur_ri.enc = encodings[cur]; + + replaces.add(cur_ri); + } + + cur_ri.replaces.add(sis[cur]); + } + + // restore value Strings + Iterator rit = replaces.iterator(); + while (rit.hasNext()) + { + ReplaceInfo ri = (ReplaceInfo) rit.next(); + ri.value = Placeholder.reconstructStringFromPartition(pdf, ri.replaces, ri.enc); + + // System.out.println(new String(ri.brev, "US-ASCII") + ": " + + // ri.value); + } + + return replaces; + } + catch (IOException e) + { + throw new PDFDocumentException(310, e); + } + + } + + /** + * Reads an unsigned integer number. + * + * @param pdf + * The PDF. + * @param start_index + * The start index of the number. + * @param num_digits + * The number of digits. + * @return Returns the read number. + */ + public static int readNumber(final byte[] pdf, final int start_index, final int num_digits) + { + try + { + byte[] n_bytes = new byte[num_digits]; + System.arraycopy(pdf, start_index, n_bytes, 0, num_digits); + String n_string = new String(n_bytes, "US-ASCII"); + + int n = Integer.parseInt(n_string); + return n; + } + catch (UnsupportedEncodingException e) + { + logger.error(e.getMessage(), e); + return -1; + } + } + + /** + * Replaces a number by the new value. + * + * @param pdf + * The PDF. + * @param start_index + * The start index of the number. + * @param number + * The new number. + * @param num_digits + * The number of digits. + */ + public static void replaceNumber(final byte[] pdf, final int start_index, final int number, final int num_digits) + { + try + { + if (number < 0) + { + throw new IllegalArgumentException("The given number " + number + " must not be negative."); + } + String number_string = Integer.toString(number); + if (number_string.length() > num_digits) + { + throw new IllegalArgumentException("The given number " + number + " has more than " + num_digits + " digits."); + } + + int leading_zeros = num_digits - number_string.length(); + String zeros_string = ""; + for (int i = 0; i < leading_zeros; i++) + { + zeros_string += "0"; + } + + String total_string = zeros_string + number_string; + byte[] total_bytes = total_string.getBytes("US-ASCII"); + System.arraycopy(total_bytes, 0, pdf, start_index, num_digits); + } + catch (UnsupportedEncodingException e) + { + logger.error(e.getMessage(), e); + } + } + + + // TODO old code - remove + // /** + // * For debugging purposes. + // * + // * @param args + // * @throws IOException + // */ + // public static void main(String[] args) throws IOException + // { + // File signed_doc = new File("C:/wprinz/temp.pdf"); + // + // PdfReader reader = new PdfReader(new FileInputStream(signed_doc)); + // PdfDictionary egiz_dict = getEgizDictFromReader(reader); + // if (egiz_dict == null) + // { + // System.out.println("NO Egiz Dict"); + // return; + // } + // + // String sig_text = extractSignatureTextOnly(egiz_dict); + // System.out.println("Sig Text:"); + // System.out.println(sig_text); + // + // int ods = getOriginalDocumentSizeFromEgizDict(egiz_dict); + // System.out.println("Original Document Size = " + ods); + // } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java new file mode 100644 index 0000000..7dc49ef --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignatureHolder.java @@ -0,0 +1,185 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BinarySignatureHolder.java,v 1.1 2006/10/11 07:58:28 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Data structure that holds the information of one binary signature block, + * which is the signed/signable pdf and the corresponding SignatureObject. + * + *

+ * The actual signed text is computed by Base64 encoding the binary data when + * first requested. + *

+ *

+ * The corresponding getters can be used to retrieve the signed document (e.g. + * for displaying a preview). + *

+ * + * @author wprinz + */ +public class BinarySignatureHolder implements Serializable, SignatureHolder +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7208103904479272760L; + +// /** +// * The whole pdf this holder was extracted from. +// */ +// private byte[] signed_pdf = null; + + private PdfDataSource pdfDataSource = null; + +// /** +// * The number of bytes that give the signed document. +// */ +// private int signed_pdf_length = -1; + +// /** +// * The signed text of this object. +// * +// *

+// * This is the value that will be signed by the Connector. +// *

+// */ +// private String signed_text = null; + + /** + * The signature object. + */ + private SignatureObject signature_object = null; + +// /** +// * Constructor that takes the pdf and the SignatureObject as parameters. +// * +// * @param pdf +// * The pdf data. +// * @param length +// * The length (number of bytes) of the pdf data to be used for being +// * converted into "signed text". +// * @param so +// * The signed signature object. +// */ +// public BinarySignatureHolder(final byte[] pdf, final int length, SignatureObject so) +// { +//// this.signed_pdf = pdf; +// this.pdfDataSource = new ByteArrayPdfDataSourceImpl(pdf); +// // streaming byte array +// this.signed_pdf_length = length; +// this.signature_object = so; +// +//// this.signed_text = null; +// } + + public BinarySignatureHolder(PdfDataSource pdf, SignatureObject so) + { + this.pdfDataSource = pdf; + this.signature_object = so; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignedText() + */ + public String getSignedText() + { + throw new RuntimeException("BinarySignatureHolder must not return text."); +// if (this.signed_text == null) +// { +// computeSignedText(); +// } +// return this.signed_text; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignatureObject() + */ + public SignatureObject getSignatureObject() + { + return this.signature_object; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getDataSource() + */ + public DataSource getDataSource() + { + return getSignedPdf(); + } + + + + // TODO obsolete funtction - remove; +// /** +// * Computes or recomputes the signed text from the underlying binary data. +// * +// *

+// * This usually encodes the binary data of given length in Base64. +// *

+// * +// *

+// * This is usually called automatically when the signed text is first +// * requested. +// *

+// */ +// protected void computeSignedText() +// { +// this.signed_text = BinarySignature.retrieveSignableTextFromData(this.signed_pdf, this.signed_pdf_length); +// } + +// /** +// * Returns the signed_pdf. +// * @return Returns the signed_pdf. +// */ +// public byte[] getSignedPdf() +// { +// return this.signed_pdf; +// } + + public PdfDataSource getSignedPdf () + { + return this.pdfDataSource; + } + +// /** +// * Returns the signed_pdf_length. +// * @return Returns the signed_pdf_length. +// */ +// public int getSignedPdfLength() +// { +// return this.signed_pdf_length; +// } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java new file mode 100644 index 0000000..d2b29b6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/EGIZDate.java @@ -0,0 +1,284 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: EGIZDate.java,v 1.1 2006/10/31 08:08:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.apache.commons.lang.time.DateUtils; +import org.apache.log4j.Logger; + +/** + * Represents a signature date and the signing time as can be found in the + * SIG_DATE field. + * + *

+ * This is used to compare date values of signatures. + *

+ * + * @author wprinz + */ +public class EGIZDate { + + private static final Logger LOG = Logger.getLogger(EGIZDate.class); + + protected Date date = null; + + // TODO remove deprecated old code +// /** +// * The year. +// */ +// protected int year; +// +// /** +// * The month. +// */ +// protected int month; +// +// /** +// * The day. +// */ +// protected int day; +// +// /** +// * The hour. +// */ +// protected int hour; +// +// /** +// * The minute. +// */ +// protected int minute; +// +// /** +// * The second. +// */ +// protected int second; +// +// /** +// * Constructor that fills the date with values. +// * +// * @param year +// * The year. +// * @param month +// * The month. +// * @param day +// * The day. +// * @param hour +// * The hour. +// * @param minute +// * The minute. +// * @param second +// * The second. +// */ +// public EGIZDate(int year, int month, int day, int hour, int minute, +// int second) { +// this.year = year; +// this.month = month; +// this.day = day; +// this.hour = hour; +// this.minute = minute; +// this.second = second; +// } + + + /** + * @param date + */ + protected EGIZDate(Date date) + { + this.date = date; + } + + /** + * Parses the date information from a given date value. + * + *

+ * Usually the date value is one extracted from the value of the SIG_DATE + * field. + *

+ * + * @param date_value + * The date value String. + * @return Returns the parsed EGIZDate. An IllegalArgumentException is + * thrown if the date String has an illegal format. + */ + public static EGIZDate parseFromString(String date_value) { + Date date = parseDateFromString(date_value); +// Calendar calendar = new GregorianCalendar(); +// calendar.setTime(date); + + LOG.debug("Parsing date string \"" + date_value + "\" returns: " + date); + +// return new EGIZDate(calendar.get(Calendar.YEAR), calendar +// .get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), +// calendar.get(Calendar.HOUR), calendar.get(Calendar.MINUTE), +// calendar.get(Calendar.SECOND)); + return new EGIZDate(date); + + } + + public static Date parseDateFromString (String date_value) + { + // find the according RFC standard and cite it + + /* + * Pattern date_pattern = + * Pattern.compile("^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(Z|((\\+|\\-)\\d\\d:\\d\\d))?$"); + * Matcher date_matcher = date_pattern.matcher(date_value); if + * (!date_matcher.matches()) { throw new IllegalArgumentException("The + * date_value (" + date_value + ") has an illegal format."); } // for + * some strange reasons capture groups don't work + * + * int year = Integer.parseInt(date_value.substring(0, 4)); int month = + * Integer.parseInt(date_value.substring(5, 7)); int day = + * Integer.parseInt(date_value.substring(8, 10)); int hour = + * Integer.parseInt(date_value.substring(11, 13)); int minute = + * Integer.parseInt(date_value.substring(14, 16)); int second = + * Integer.parseInt(date_value.substring(17, 19)); return new + * EGIZDate(year, month, day, hour, minute, second); + */ + + String[] parsePatterns = { "yyyy-MM-dd'T'HH:mm:ss", + "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ssZZ" }; + if (date_value.length() > 19) { + int li = date_value.lastIndexOf(":"); + if (li >= 19) { + date_value = new StringBuffer(date_value).deleteCharAt(li).toString(); + } + // FIXME: @iaik: wenn man bei UTC+"Z" die letzten -2 Zeichen durch "UTC" ersetzt verliert die Zeit ihre Sekunden-Einerstelle!!!!!!! + // alter code: +// if (date_value.endsWith("Z")) { +// date_value = date_value.substring(0, date_value.length()-2) + "UTC"; +// } + // neuer code: + if (date_value.endsWith("ZZ")) { + date_value = date_value.substring(0, date_value.length()-2) + "UTC"; + } + if (date_value.endsWith("Z")) { + date_value = date_value.substring(0, date_value.length()-1) + "UTC"; + } + + } else { + date_value += "UTC"; + } + + Date date; + try { + date = DateUtils.parseDate(date_value, parsePatterns); + } catch (ParseException e) { + throw new IllegalArgumentException("The date_value (" + date_value + + ") has an illegal format."); + } + + +// return new EGIZDate(calendar.get(Calendar.YEAR), calendar +// .get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), +// calendar.get(Calendar.HOUR), calendar.get(Calendar.MINUTE), +// calendar.get(Calendar.SECOND)); + + // fixed by tknall: really bad bug: Calendar.HOUR means hour in 12-hour-mode instead f 24-hour. !!!! + // this leads to false comparison of two dates where one date is prior noon and one after noon. +// return new EGIZDate(calendar.get(Calendar.YEAR), calendar +// .get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), +// calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), +// calendar.get(Calendar.SECOND)); + return date; + + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (!(obj instanceof EGIZDate)) { + return false; + } + + EGIZDate other = (EGIZDate)obj; + return this.date.equals(other.date); + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return this.date.hashCode(); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return this.date.toString(); + } + + +// /** +// * Converts the date to a long integer. +// * +// *

+// * An earlier date is lower than a later date. +// *

+// *

+// * E.g. a date in 1999 will get a smaller number than a date in 2006. +// *

+// * +// * @return Returns the compareable long. +// */ +// protected long toCompareableLong() { +// return +this.year * 12 * 31 * 24 * 60 * 60 + this.month * 31 * 24 * 60 +// * 60 + this.day * 24 * 60 * 60 + this.hour * 60 * 60 +// + this.minute * 60 + this.second; +// } + + /** + * Compares this EGIZDate to another EXIZDate. + * + * @param other + * The other EGIZDate. + * @return Returns negative if this date is earlier (lower) than the other + * date. Returns 0 if both dates are equal. Returns positive if this + * date is later (higher) than the other date. + */ + public int compareTo(EGIZDate other) { + return this.date.compareTo(other.date); +// long diff = toCompareableLong() - other.toCompareableLong(); +// return (int) diff; + } + + /** + * @return the date + */ + public Date getDate() + { + return this.date; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java new file mode 100644 index 0000000..3714684 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/IncrementalUpdateInformation.java @@ -0,0 +1,252 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: IncrementalUpdateInformation.java,v 1.2 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.IOException; +import java.io.Serializable; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.utils.PdfAUtil; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +import com.lowagie.text.pdf.PdfReader; + +/** + * This parameter object contains all useful inforamtion the binary incremental + * update methods need to create and replace a binary singature block. + * + *

+ * This class is basically used to transport information about the document from + * the prepareSign to the finishSign of the Signator. In future, this could be + * extended and encapsulated to task proprietary IUI instances. E.g. a + * BinarySignatorIUI, a TextualSignatorIUI, both implementing the core IUI + * interface, but encapsulating Binary or Textual specialities. + *

+ * + * @author wprinz + */ +public class IncrementalUpdateInformation implements Serializable +{ + public static final Logger log = Logger.getLogger(IncrementalUpdateInformation.class); + + /** + * SVUID. + */ + private static final long serialVersionUID = -5904526956127108035L; + + /** + * The original PDF document. + */ + //public byte[] original_document = null; + public PdfDataSource original_document = null; + + /** + * The Singature type to be created. + */ + public String signature_type = null; + + /** + * The signed pdf document. + * + *

+ * This is the original document plus the incremental update block. + *

+ */ + public byte[] signed_pdf = null; + // this is only valid during prepare + + // holds the variable iui data for bin sigs. + public byte [] sign_iui_block = null; + + /** + * The start index of this incremental update block. + */ + int start_index = -1; + + /** + * The indirect reference of the egiz dict. + */ + // PdfIndirectReference egiz_dict_ir = null; + public int egiz_dict_ir_number; + + public int egiz_dict_ir_generation; + + /** + * The List of ReplaceInfo objects specifying the byte ranges where the + * variable data has to be fille in. + */ + public List replaces = null; + + /** + * The List of StringInfo objects specifying the byte ranges that should + * be/were signed. + */ + public List byte_ranges = null; + + /** + * The indirect reference of the signature x-object. + */ + // public PdfIndirectReference temp_ir; + public int temp_ir_number; + + public int temp_ir_generation; + + /** + * The start index of the content stream of the signature x-object. + */ + public int content_stream_start = -1; + + /** + * The length of the content stream of the signature x-object. + */ + public int content_stream_length = -1; + +// /** +// * The document text for signing. +// */ +// public String document_text; + /** + * The data to be signed or verified. + * + *

+ * For text signature this is the document text. + * For binary signature this is the PDF document. + *

+ */ + public SignatureData signature_data = null; + + /** + * The SignatureObject containing the variable values after the document text + * has been signed. + *

+ * These values have to be filled in. + *

+ */ + public SignSignatureObject signed_signature_object; + + /** + * The start of the /encodings array. + */ + public int enc_start = -1; + + /** + * The length of the /encodings array. + */ + public int enc_length = -1; + + /** + * The start of the first /Cert + */ + public int cert_start = -1; + + /** + * The length of the /cert placeholder. + */ + public int cert_length = -1; + + /** + * The length of the /TimeStamp placeholder. + */ + public int timestamp_length = -1; + + /** + * The start of the first /Timestamp + */ + public int timestamp_start = -1; + + /** + * The list of strings of the KZ. + */ + public List kz_list; + + /** + * The table position. + */ + public TablePos pos; + + /** + * For signing: the profile. + */ + public String signProfile; + + /** + * The actual position where the table was written. + */ + public ActualTablePos actualTablePos; + + /** + * The field definitions of invisible fields, which data should be stored in /Data. + */ + public List invisible_field_definitions; + + /** + * The invisible KZ String, if KZ is invisible. + */ + public String invisibleKZString = null; + + /** + * List {@link NonTextObjectInfo} of non text objects if available (text signature only). + * + */ + public List nonTextObjectInfos; + + + /** + * The timestamper if any + */ + public TimeStamper timeStamper; + + // dferbas + + public String getPdfVersion() { + byte[] pdf_data = this.original_document.getAsByteArray(); + PdfReader reader; + String pdfVersion = null; + try { + reader = new PdfReader(pdf_data); + // is.close(); + + byte[] metaData = reader.getMetadata(); + if (metaData != null) { + pdfVersion = PdfAUtil.findPdfAVersion(new String(metaData)); + } + if (pdfVersion == null) { + pdfVersion = "PDF 1." + reader.getPdfVersion(); + } + + reader.close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + return pdfVersion; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/NoSignatureHolder.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/NoSignatureHolder.java new file mode 100644 index 0000000..97a6111 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/NoSignatureHolder.java @@ -0,0 +1,84 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +public class NoSignatureHolder implements Serializable, SignatureHolder { + + private static final long serialVersionUID = 1L; + + // # sigs before modification + private int position; + + public NoSignatureHolder(int pos) { + this.position = pos; + } + + public DataSource getDataSource() { + return null; + } + + public SignatureObject getSignatureObject() { + return null; + } + + public int getPosition() { + return this.position; + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + this.position; + return result; + } + + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + final NoSignatureHolder other = (NoSignatureHolder) obj; + + if (this.position != other.position) { + return false; + } + + return true; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ObjectExtractor.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ObjectExtractor.java new file mode 100644 index 0000000..eb7377a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ObjectExtractor.java @@ -0,0 +1,233 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; + +import at.gv.egiz.pdfas.api.analyze.NonTextObjectInfo; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; + +/** + * Method for object extraction from pdf documents. + * This uses pdf-box 0.8.0, not 0.7.2. Packages org.apache.pdfbox instead org.pdfbox! + * @author dferbas + * + */ +public class ObjectExtractor { + private static Logger log = Logger.getLogger(ObjectExtractor.class); + + /* + * If set true signature annotations are not extracted otherwise + * all signatures except PDF-AS signatures are extracted. + */ + private final static boolean SKIP_NON_PDFAS_SIGNATURES = false; + + /** + * Find annotation objects in pdf documents + * @param objectInfos + * @param pageNr + * @param page + */ + private static void doExtractAnnotations(List objectInfos, int pageNr, PDPage page) { + List annotations; + try { + annotations = page.getAnnotations(); + } catch (IOException e) { + log.error("Error extracting annotations from pdf. No NonTextObjectInfo-annotations available.", e); + return; + } + for (Iterator it = annotations.iterator(); it.hasNext();) { + try { + PDAnnotation anno = (PDAnnotation) it.next(); + log.debug("found annotation: " +anno); + if (log.isTraceEnabled()) { + log.trace("annotation def: " + dictToString(anno.getDictionary())); + } + String ft = anno.getDictionary().getNameAsString("FT"); + if (ft != null && ft.equals("Sig")) { // skip signature widgets + if (SKIP_NON_PDFAS_SIGNATURES) { + log.debug("found signature widged, skip extraction"); + continue; + } else { + COSDictionary sigDict = (COSDictionary) anno.getDictionary().getDictionaryObject("V"); + if (sigDict != null && AdobeSignatureHelper.ADOBE_SIG_FILTER.equals(sigDict.getNameAsString("Filter"))) { + log.debug("found PDF-AS signature widged, skip extraction"); + continue; + } + } + } + + NonTextObjectInfo objInfo = new NonTextObjectInfo(); + objInfo.setName(anno.getDictionary().getString( "NM" )); + objInfo.setObjectType(NonTextObjectInfo.TYPE_ANNOTATION); + + String subtype = anno.getDictionary().getNameAsString("Subtype"); + String subj = anno.getDictionary().getString("Subj"); + if (subj != null) { + subtype+= "/" + subj; + } + objInfo.setSubType(subtype); + + objInfo.setPageNr(pageNr); + objInfo.setHeight(anno.getRectangle().getHeight()); + objInfo.setWidth(anno.getRectangle().getWidth()); + objectInfos.add(objInfo); + } catch (Exception ex) { + log.info("error reading non text object info key " + ex); + } + } + } + + /** + * Create string representation from COSDictionary + * @param dict + * @return + */ + public static String dictToString(COSDictionary dict) + { + try { + String retVal = "COSDictionary{"; + for (int i = 0; i 0.8.0 needed + } + if (log.isDebugEnabled()) { + log.debug("extracted non textual objects count: " + objectInfos.size()); + } + return objectInfos; + + } + + /** + * Extract non textual data from pdf. + * @param pdfDataSource + * + * @see org.pdfbox.ExtractImages + * + * @return List of {@link NonTextObjectInfo} + */ + public static List extractNonTextInfo(PdfDataSource pdfDataSource) { + + PDDocument doc = null; + try { + doc = PDDocument.load(pdfDataSource.createInputStream()); + List res = extractNonTextInfo(doc); + doc.close(); + return res; + } catch (IOException e) { + log.error("Error extracting images from pdf. No NonTextObjectInfo available.", e); + return new ArrayList(); + } finally { + if (doc != null) { + try { + doc.close(); + } catch (IOException e) { + log.error("error closing pddocument", e); + } + } + } + + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java new file mode 100644 index 0000000..a0311da --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java @@ -0,0 +1,377 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFPage.java,v 1.5 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.pdfbox.cos.COSName; +import org.pdfbox.cos.COSStream; +import org.pdfbox.pdmodel.PDPage; +import org.pdfbox.pdmodel.PDResources; +import org.pdfbox.pdmodel.common.PDStream; +import org.pdfbox.pdmodel.graphics.xobject.PDXObject; +import org.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; +import org.pdfbox.util.Matrix; +import org.pdfbox.util.PDFOperator; +import org.pdfbox.util.PDFTextStripper; +import org.pdfbox.util.TextPosition; +import org.pdfbox.util.operator.OperatorProcessor; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * PDFPage is an inner class that is used to calculate the page length of a PDF + * Document page. It extends the PDFTextStripper class and implement one + * interested method: {@link PDFPage#showCharacter(TextPosition)}
+ * This method is called when processing the FileStream. By calling the method + * {@link org.pdfbox.util.PDFStreamEngine#processStream(org.pdfbox.pdmodel.PDPage, org.pdfbox.pdmodel.PDResources, org.pdfbox.cos.COSStream)} + * the implemented method showCharacter is called. + * + * @author wlackner + * @see PDFTextStripper + */ +public class PDFPage extends PDFTextStripper +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PDFPage.class); + + /** + * The maximum (lowest) y position of a character. + */ + protected float max_character_ypos = Float.NEGATIVE_INFINITY; + + /** + * The maximum (lowest y position of an image. + */ + protected float max_image_ypos = Float.NEGATIVE_INFINITY; + + /** + * The y coordinate of the footer line. PDF elements below this footer line will not be regarded. + */ + protected float footer_line = 0.0f; + + /** + * Constructor. + * + * @param footer_line The y coordinate of the footer line. PDF elements below this footer line will not be regarded. + * + * @throws IOException + */ + public PDFPage(float footer_line) throws IOException + { + super(); + + this.footer_line = footer_line; + + OperatorProcessor newInvoke = new MyInvoke(); + newInvoke.setContext(this); + operators.put("Do", newInvoke); + } + + + protected void processOperator(PDFOperator operator, List arguments) throws IOException + { + //logger_.debug("operator = " + operator); + + super.processOperator(operator, arguments); + } + + // exthex + /** + * A method provided as an event interface to allow a subclass to perform some + * specific functionality when a character needs to be displayed. This method + * is used to calculate the latest position of a text in the page. Sorry for + * this missinterpretation of the method, but it is the only way to do this + * (provided by PDFBox)!!! + * + * @param text + * the character to be displayed -> calculate there y position. + */ + protected void showCharacter(TextPosition text) + { + float current_y = text.getY(); + final String character = text.getCharacter(); + + int pageRotation = page.findRotation(); + //logger_.debug("PageRotation = " + pageRotation); + if (pageRotation == 0) + { + current_y = text.getY(); + } + if (pageRotation == 90) + { + current_y = text.getX(); + } + if (pageRotation == 180) + { + float page_height = page.findMediaBox().getHeight(); + current_y = page_height - text.getY(); + } + if (pageRotation == 270) + { + float page_height = page.findMediaBox().getHeight(); + current_y = page_height - text.getX(); + } + + + if (current_y > this.footer_line) + { + //logger_.debug("character is below footer_line. footer_line = " + this.footer_line + ", text.character=" + character + ", y=" + current_y); + return; + } + + // store ypos of the char if it is not empty + if (!character.equals(" ") && current_y > this.max_character_ypos) + { + this.max_character_ypos = current_y; + //logger_.debug("text.character=" + character + ", y=" + current_y); + // System.err.println(character + "|" + current_y); + } + + //logger_.error("text.character=" + character + ", y=" + current_y + " max_c=" + this.max_character_ypos); + // System.err.println(character + "|" + current_y); + } + + // use this funtion getting an unsorted text output + // public void showString(byte[] string) { + // logger_.debug(new String(string)); + // } + + /** + * Returns the calculated page length. + * + * @return the max page length value + */ + public float getMaxPageLength() + { + float max_ypos = Float.NEGATIVE_INFINITY; + + if (this.max_character_ypos > this.max_image_ypos) + { + max_ypos = this.max_character_ypos; + } + else + { + max_ypos = this.max_image_ypos; + } + //logger_.error("max len=" + max_ypos); + return max_ypos; + } + + public class MyInvoke extends OperatorProcessor + { + + public void process(PDFOperator operator, List arguments) throws IOException + { + COSName name = (COSName) arguments.get(0); + //logger_.error(""); + + // PDResources res = context.getResources(); + + Map xobjects = context.getXObjects(); + PDXObject xobject = (PDXObject) xobjects.get(name.getName()); + + PDStream stream = xobject.getPDStream(); + COSStream cos_stream = stream.getStream(); + + COSName subtype = (COSName) cos_stream.getDictionaryObject(COSName.SUBTYPE); + //logger_.error(""); + if (subtype.equals(COSName.IMAGE)) + { + //logger_.error("XObject Image"); + + Matrix ctm = context.getGraphicsState().getCurrentTransformationMatrix(); + //logger_.debug("ctm = " + ctm); + + Pos [] coordinates = new Pos [] { + new Pos(0, 0, 1), + new Pos(1, 0, 1), + new Pos(0, 1, 1), + new Pos(1, 1, 1) }; + + Pos [] transformed_coordinates = transtormCoordinates(coordinates, ctm); + + /********************************************************** + * pdf-as fix: + * calculating min and max point of an image to look where + * the signature should be placed + * fix solves problems with footer and images and + * placement of the signature in an image only pdf document + **********************************************************/ + + float actual_lowest_point = Float.NaN; + float actual_starting_point = Float.NaN; + + int pageRotation = page.findRotation(); + logger_.debug("PageRotation = " + pageRotation); + if (pageRotation == 0) + { + float min_y = findMinY(transformed_coordinates); + logger_.debug("min_y = " + min_y); + float page_height = page.findMediaBox().getHeight(); + logger_.debug("page_height = " + page_height); + + actual_lowest_point = page_height - min_y; + actual_starting_point = page_height - findMaxY(transformed_coordinates); + } + if (pageRotation == 90) + { + float max_x = findMaxX(transformed_coordinates); + logger_.debug("max_x = " + max_x); + float page_width = page.findMediaBox().getWidth(); + logger_.debug("page_width = " + page_width); + + actual_lowest_point = max_x; + actual_starting_point = findMinX(transformed_coordinates); + } + if (pageRotation == 180) + { + float min_y = findMinY(transformed_coordinates); + logger_.debug("min_y = " + min_y); + float page_height = page.findMediaBox().getHeight(); + actual_lowest_point = page_height - findMaxY(transformed_coordinates); + actual_starting_point = page_height - min_y; + } + if (pageRotation == 270) + { + float min_x = findMinX(transformed_coordinates); + logger_.debug("min_x = " + min_x); + + float page_width = page.findMediaBox().getWidth(); + logger_.debug("page_width = " + page_width); + + actual_lowest_point = page_width - min_x; + actual_starting_point = page_width - findMaxX(transformed_coordinates); + } + + + logger_.debug("actual_lowest_point = " + actual_lowest_point); + + if (actual_lowest_point > PDFPage.this.footer_line && actual_starting_point > PDFPage.this.footer_line) + { + logger_.debug("image is below footer_line. footer_line = " + PDFPage.this.footer_line); + return; + } + + if (actual_lowest_point > PDFPage.this.max_image_ypos) + { + PDFPage.this.max_image_ypos = actual_lowest_point; + } + + return; + } + + if (xobject instanceof PDXObjectForm) + { + PDXObjectForm form = (PDXObjectForm) xobject; + COSStream invoke = (COSStream) form.getCOSObject(); + PDResources pdResources = form.getResources(); + PDPage page = context.getCurrentPage(); + if (pdResources == null) + { + pdResources = page.findResources(); + } + + getContext().processSubStream(page, pdResources, invoke); + } + } + } + + public static Pos [] transtormCoordinates (Pos [] coordinates, Matrix m) + { + Pos [] transformed = new Pos [coordinates.length]; + for (int i = 0; i < coordinates.length; i++) + { + transformed[i] = transtormCoordinate(coordinates[i], m); + } + return transformed; + } + + public static Pos transtormCoordinate (Pos pos, Matrix m) + { + Pos transformed = new Pos(); + transformed.x = pos.x * m.getValue(0, 0) + pos.y * m.getValue(1, 0) + pos.z * m.getValue(2, 0); + transformed.y = pos.x * m.getValue(0, 1) + pos.y * m.getValue(1, 1) + pos.z * m.getValue(2, 1); + transformed.z = pos.x * m.getValue(0, 2) + pos.y * m.getValue(1, 2) + pos.z * m.getValue(2, 2); + + logger_.debug(" transformed " + pos + " --> " + transformed); + return transformed; + } + + public static float findMinY (Pos [] coordinates) + { + float min = Float.POSITIVE_INFINITY; + for (int i = 0; i < coordinates.length; i++) + { + if (coordinates[i].y < min) + { + min = coordinates[i].y; + } + } + return min; + } + + public static float findMaxY(Pos[] coordinates) { + float max = 0; + for (int i = 0; i < coordinates.length; i++) { + if (coordinates[i].y > max) { + max = coordinates[i].y; + } + } + return max; + } + + public static float findMaxX (Pos [] coordinates) + { + float max = Float.NEGATIVE_INFINITY; + for (int i = 0; i < coordinates.length; i++) + { + if (coordinates[i].x > max) + { + max = coordinates[i].x; + } + } + return max; + } + public static float findMinX (Pos [] coordinates) + { + float min = Float.POSITIVE_INFINITY; + for (int i = 0; i < coordinates.length; i++) + { + if (coordinates[i].x < min) + { + min = coordinates[i].x; + } + } + return min; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java new file mode 100644 index 0000000..d6e6966 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureCreation.java @@ -0,0 +1,176 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFSignatureCreation.java,v 1.6 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * This class provides wrapper methods to get an access to abstract PDF documents (PDFSignator). + * There exists many open source libraries and commercial libraries that can implement the abstract + * interface.
+ * This class is to load the corresponding implementation of an abstract PDFSignator class. Therefor + * it seams to be a factory. The factory settings are read from the configuration file calling the + * SettingsReader. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class PDFSignatureCreation { + /** + * The abstract signature object + */ + private SignatureObject sigObject_ = null; + /** + * The abstract pdf siganture object + */ + private PDFSignatureObject pdfSigObject_ = null; + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + /** + * The factory class prefix + */ + private final static String CLASS_PREFIX = ".PDFSignatureObject"; + /** + * The factory class prefix of the default library + */ + protected final static String DEFAULT_LIBRARY = "IText"; + /** + * The settings key defined in the settings file + * + * @see SettingsReader + */ + protected final static String SETTINGS_KEY = "pdf.signature.library"; + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PDFSignatureCreation.class); + + /** + * Load the configuration settings. Load the corresponding class implementation for the abstract + * PDFSignature class. Init with a signature object. + * + * @param sigObject the native signature object + * @throws PDFDocumentException ErrorCode:101 + */ + public PDFSignatureCreation(SignatureObject sigObject) throws PDFDocumentException { +// try { + loadSettings(); +// } catch (PDFDocumentException e) { +// e.setErrorCode(101); +// throw e; +// } + sigObject_ = sigObject; + } + + /** + * Load the factory implementation. This method trys to load the configured PDF library. + * + * @throws PDFDocumentException + */ + private PDFSignatureObject createPDFSignatureObject() throws PDFDocumentException { + PDFSignatureObject pdf_sig_object = null; + String class_name = this.getClass().getPackage().getName() + getClassName(); + Class pdf_sig_obj_class = null; + try { + pdf_sig_obj_class = Class.forName(class_name); + } catch (ClassNotFoundException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Class not found:" + class_name); + } + throw new PDFDocumentException(203, "Can not load pdf signator library", e); + } + try { + pdf_sig_object = (PDFSignatureObject) pdf_sig_obj_class.newInstance(); + } catch (InstantiationException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not instantiate:" + class_name); + } + throw new PDFDocumentException(203, "Can not load pdf signator library", e); + } catch (IllegalAccessException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not access:" + class_name); + } + throw new PDFDocumentException(203, "Can not load pdf signator library", e); + } + return pdf_sig_object; + } + + /** + * load the class settings + * + * @throws PDFDocumentException + * @see SettingsReader + */ + private void loadSettings() throws PDFDocumentException { + if (settings_ == null) { + try { + settings_ = SettingsReader.getInstance(); + } catch (SettingsException e) { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new PDFDocumentException(101, log_message, e); + } + } + } + + /** + * Read the class postfix from the configuration file + * + * @return the full qualified class name + */ + private String getClassName() { + String extract_class = settings_.getSetting(SETTINGS_KEY, DEFAULT_LIBRARY); + return CLASS_PREFIX + extract_class; + } + + /** + * Creates a new pdf signature object using the configured pdf library. + * + * @return a new pdf signature object + * @throws PDFDocumentException ErrorCode:203 + */ + public PDFSignatureObject getPDFSignatureObject() throws PDFDocumentException { + if (pdfSigObject_ == null) { +// try { + pdfSigObject_ = createPDFSignatureObject(); +// } catch (PDFDocumentException e) { +// e.setErrorCode(203); +// throw e; +// } + pdfSigObject_.setSignatorObject(sigObject_); + } + return pdfSigObject_; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java new file mode 100644 index 0000000..bd5b6a3 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObject.java @@ -0,0 +1,56 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFSignatureObject.java,v 1.3 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Defines an interface to get access to PDF documents. There exists many open source libraries and + * commercial libraries. + * + * @author wlackner + */ +public interface PDFSignatureObject { + public void setSignatorObject(SignatureObject signatorObject); + + /** + * Converts the current abstract signature object in a pdf signature object implementation + * + * @return the converted pdf signature object + * @throws PDFDocumentException + */ + public Object getSignatureObject() throws PDFDocumentException; + + /** + * Converts a abstract signature object in a pdf signature object implementation + * + * @param signatorObject the abstract signatorObject to convert + * @return the converted pdf signature object + * @throws PDFDocumentException + */ + public Object getSignatureObject(SignatureObject signatorObject) throws PDFDocumentException; +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java new file mode 100644 index 0000000..1145619 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java @@ -0,0 +1,618 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFSignatureObjectIText.java,v 1.5 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.table.Entry; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.egov.egiz.table.Table; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Element; +import com.lowagie.text.Font; +import com.lowagie.text.Image; +import com.lowagie.text.Phrase; +import com.lowagie.text.pdf.BaseFont; +import com.lowagie.text.pdf.PdfPCell; +import com.lowagie.text.pdf.PdfPTable; +import com.lowagie.text.pdf.SubsetLocal; + +/** + * This class is the IText implementation of the PDFSignatureObject interface. + * The class takes an abstract definition of a signature object and convert them + * into a pdf table that is used to sign a pdf document. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject + * @see at.knowcenter.wag.egov.egiz.table.Table + * @see at.knowcenter.wag.egov.egiz.table.Entry + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see com.lowagie.text.pdf.PdfPTable + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class PDFSignatureObjectIText implements PDFSignatureObject +{ + +// 03.11.2010 changed by exthex to allow setting separate hAlign and vAlign for value and non-value cells. +// If no value for valuevalign or valuehalign is set the values from valign and halign are taken. +// Also fixed a minor bug which prevented proper style inheritment (Bug Nr. #534). +// 04.11.2010 changed by exthex - allow setting separate hAlign and vAlign for image cells analog to value cells. + + private static final String SIG_PDFA1_B_VALID = "SIG_PDFA1B_VALID"; + +/** + * The default font definition + */ + private static Font DEFAULT_FONT = new Font(Font.HELVETICA, 8, Font.NORMAL); + + /** + * The abstract signature object + */ + private SignatureObject sigObject_ = null; + + /** + * The IText pdf table object + */ + private PdfPTable pdfSigObject_ = null; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(PDFSignatureObjectIText.class); + + /** + * Map the style align definitions to IText's align statements + */ + private static HashMap alignMap_ = new HashMap(); + + /** + * Map the font definitions to IText's font statements + */ + private static HashMap fontMap_ = new HashMap(); + + /** + * The empty constructor. It loads the ui definitions from signature tables + * and init the align map. + * + * @throws PDFDocumentException + */ + public PDFSignatureObjectIText() throws PDFDocumentException + { + loadSettings(); + initStyleMaps(); + } + + /** + * load the class settings + * + * @throws PDFDocumentException + * @see SettingsReader + */ + private void loadSettings() throws PDFDocumentException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new PDFDocumentException(101, log_message, e); + } + } + } + + /** + * This method initialize the style maps. It maps the style style definitions + * to IText styles. + */ + private void initStyleMaps() + { + alignMap_.put(Style.TOP, new Integer(Element.ALIGN_TOP)); + alignMap_.put(Style.MIDDLE, new Integer(Element.ALIGN_MIDDLE)); + alignMap_.put(Style.BOTTOM, new Integer(Element.ALIGN_BOTTOM)); + alignMap_.put(Style.LEFT, new Integer(Element.ALIGN_LEFT)); + alignMap_.put(Style.CENTER, new Integer(Element.ALIGN_CENTER)); + alignMap_.put(Style.RIGHT, new Integer(Element.ALIGN_RIGHT)); + + fontMap_.put(Style.HELVETICA, new Integer(Font.HELVETICA)); + fontMap_.put(Style.TIMES_ROMAN, new Integer(Font.TIMES_ROMAN)); + fontMap_.put(Style.COURIER, new Integer(Font.COURIER)); + fontMap_.put(Style.NORMAL, new Integer(Font.NORMAL)); + fontMap_.put(Style.BOLD, new Integer(Font.BOLD)); + fontMap_.put(Style.ITALIC, new Integer(Font.ITALIC)); + fontMap_.put(Style.BOLDITALIC, new Integer(Font.BOLDITALIC)); + fontMap_.put(Style.UNDERLINE, new Integer(Font.UNDERLINE)); + fontMap_.put(Style.STRIKETHRU, new Integer(Font.STRIKETHRU)); + } + + /** + * Set the abstract signature definition. + * + * @param signatorObject + * the abstract signator object + * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#setSignatorObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) + */ + public void setSignatorObject(SignatureObject signatorObject) + { + sigObject_ = signatorObject; + } + + /** + * This method maps the table cell definitions to the pdfCell element. + * + * @param pdfCell + * the pdf cell to be styled + * @param cellStyle + * the abstract style definition + * @param type + * type of the cell to render - the appropriate style will be set + * @see com.lowagie.text.pdf.PdfPCell + * @see at.knowcenter.wag.egov.egiz.table.Style + */ + private void setCellStyle(PdfPCell pdfCell, Style cellStyle, int type) + { + if (cellStyle != null) + { + if (cellStyle.getBgColor() != null) + { + pdfCell.setBackgroundColor(cellStyle.getBgColor()); + } + pdfCell.setPadding(cellStyle.getPadding()); + //exthex - fix for not exactly vertically centered text + pdfCell.setUseAscender(true); + + if (cellStyle.getBorder() > 0) + { + pdfCell.setBorderWidth(cellStyle.getBorder()); + } + else + { + pdfCell.setBorder(0); + } + int align = -1; + if (type == Entry.TYPE_VALUE && cellStyle.getValueVAlign() != null) + align = ((Integer) alignMap_.get(cellStyle.getValueVAlign())).intValue(); + //Note: to change the default valign of images to those of values, change the if construct below + else if (type == Entry.TYPE_IMAGE && cellStyle.getImageVAlign() != null) + align = ((Integer) alignMap_.get(cellStyle.getImageVAlign())).intValue(); + else if (cellStyle.getVAlign() != null) + align = ((Integer) alignMap_.get(cellStyle.getVAlign())).intValue(); + if (align != -1) + pdfCell.setVerticalAlignment(align); + + align = -1; + if (type == Entry.TYPE_VALUE && cellStyle.getValueHAlign() != null) + align = ((Integer) alignMap_.get(cellStyle.getValueHAlign())).intValue(); + //Note: to change the default halign of images to those of values, change the if construct below + else if (type == Entry.TYPE_IMAGE && cellStyle.getImageHAlign() != null) + align = ((Integer) alignMap_.get(cellStyle.getImageHAlign())).intValue(); + else if (cellStyle.getHAlign() != null) + align = ((Integer) alignMap_.get(cellStyle.getHAlign())).intValue(); + if (align != -1) + pdfCell.setHorizontalAlignment(align); + } + } + + /** + * This method maps the cell font definition to the iText Font Object + * + * @param fontString + * @return the corresponding iText Font Object + * @see com.lowagie.text.Font + */ + private Font getCellFont(String fontString) + { + Font font = DEFAULT_FONT; + if (fontString == null) + { + return font; + } + Object cache_font = fontMap_.get(fontString); + if (cache_font != null) + { + return (Font) cache_font; + } + String[] font_arr = fontString.split(","); + if (font_arr.length != 3) + { + return font; + } + Object font_face = fontMap_.get(font_arr[0]); + if (font_face == null) + { + return font; + } + Object font_weight = fontMap_.get(font_arr[2]); + if (font_weight == null) + { + return font; + } + int face = ((Integer) font_face).intValue(); + float height = Float.parseFloat(font_arr[1]); + int weight = ((Integer) font_weight).intValue(); + + font = new Font(face, height, weight); + fontMap_.put(fontString, font); + return font; + } + + /** + * Creates a custom + * @param fontString + * @return + * @throws PDFDocumentException + */ + private Font getCellTrueTypeFont(String fontString) throws PDFDocumentException { + float fontSize=8; + String fontName = fontString.replaceFirst("TTF:", ""); + String[] split = fontName.split(","); + if(split.length>1) + { + fontName = split[0].trim(); + try + { + fontSize = Float.parseFloat(split[1].trim()); + }catch (NumberFormatException e) + { + logger_.error("Unable to parse fontsize:"+fontString); + } + } + logger_.debug("TrueType Font detected:"+fontName +" ("+fontSize+")"); + + try { + Font font = (Font) fontMap_.get(fontString); + + if (font == null) { + logger_.debug("Font \"" + fontString + "\" not in cache. Instantiating font."); + String fontPath = SettingsReader.RESOURCES_PATH + "fonts" + File.separator + fontName; + logger_.debug("Instantiating \"" + fontPath + "\"."); + + font = new Font(BaseFont.createFont(fontPath, BaseFont.WINANSI, true), fontSize); + fontMap_.put(fontString, font); + } + return font; + } catch (DocumentException e) { + throw new PDFDocumentException(ErrorCode.FONT_NOT_FOUND, e.getMessage()); + } catch (IOException e) { + throw new PDFDocumentException(ErrorCode.FONT_NOT_FOUND, e.getMessage()); + } + } + + /** + * This method visualize an abstract table cell into a corresponding pdf table + * cell. The new pdf table cell is redered and get the style information from + * the abstract cell. Following types can be rendered: + *
    + *
  • text statements
  • + *
  • images
  • + *
  • tables
  • + *
+ * + * @param abstractCell + * the abstract cell definition + * @return the new redererd pdf table cell + * @throws PDFDocumentException + * ErrorCode:220, 221, 222 + * @see com.lowagie.text.pdf.PdfPCell + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ + private PdfPCell renderCell(Entry abstractCell) throws PDFDocumentException + { + boolean pdfaValid =false; + try + { + String profileid = sigObject_.getSignatureTypeDefinition().getType(); + String pdfa = SettingsReader.getInstance().getSetting("sig_obj." +profileid+".key."+SIG_PDFA1_B_VALID, "default."+SIG_PDFA1_B_VALID, "false"); + pdfaValid= "true".equalsIgnoreCase(pdfa); + +// exthex test + //SubsetLocal.set(!pdfaValid); + +// boolean forceSubset = true; // get this from config, default to false + //String + + //SubsetLocal.set(true); // exthex + + logger_.trace("Sign PDF/A compliant:"+pdfa); + } catch (SettingsException e1) + { + logger_.error(e1); + } + + PdfPCell pdf_cell = null; + Style cell_style = abstractCell.getStyle(); + boolean isValue = true; + switch (abstractCell.getType()) + { + case Entry.TYPE_CAPTION: + isValue = false; + case Entry.TYPE_VALUE: + String text = (String) abstractCell.getValue(); + if (text == null) + { + text = ""; + } + String font_string = cell_style.getFont(); + if (abstractCell.getType() == Entry.TYPE_VALUE && cell_style.getValueFont() != null) + { + font_string = cell_style.getValueFont(); + } + + logger_.trace("using cell font: "+font_string); + + Font cell_font; + if(font_string.startsWith("TTF:")) + { + cell_font = getCellTrueTypeFont(font_string); + } + else + { + if (pdfaValid) { + throw new PDFDocumentException(ErrorCode.NO_EMBEDABLE_TTF_CONFIGURED_FOR_PDFA, "PDF/A modus requires an embedable true type font"); + } + cell_font = getCellFont(font_string); + + } + // exthex + if (pdfaValid && abstractCell.getType() == Entry.TYPE_VALUE) { + SubsetLocal.addNonSubsetFont(cell_font.getBaseFont()); + } + Phrase text_phrase = new Phrase(text, cell_font); + pdf_cell = new PdfPCell(text_phrase); + setCellStyle(pdf_cell, cell_style, (isValue?Entry.TYPE_VALUE:Entry.TYPE_CAPTION)); + break; + case Entry.TYPE_IMAGE: + try + { + String img_ref = (String) abstractCell.getValue(); + // fixed by tknall start + File img_file = new File(img_ref); + if (!img_file.isAbsolute()) { + logger_.debug("Image file declaration is relative. Prepending path of resources directory."); + img_file = new File(SettingsReader.relocateFile(img_ref)); + } else { + logger_.debug("Image file declaration is absolute. Skipping file relocation."); + } +// String img_location = SettingsReader.relocateFile(img_ref); +// File img_file = new File (img_location); + if (!img_file.exists()) + { + logger_.debug("Image file \"" + img_file.getCanonicalPath() + "\" doesn't exist."); + throw new PDFDocumentException(220, "Image file \"" + img_file.getCanonicalPath() + "\" doesn't exist."); + } + Image image = Image.getInstance(img_file.getCanonicalPath()); + logger_.debug("Using image file \"" + img_file.getCanonicalPath() + "\"."); + + image.scaleToFit(80.0f, 80.0f); + boolean fit = true; + Style.ImageScaleToFit istf = cell_style.getImageScaleToFit(); + if (istf != null) + { + image.scaleToFit(istf.getWidth(), istf.getHeight()); + fit = false; + } + pdf_cell = new PdfPCell(image, fit); + setCellStyle(pdf_cell, cell_style, Entry.TYPE_IMAGE); + } + catch (BadElementException e) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("BadElementException:" + e.getMessage()); + } + PDFDocumentException pde = new PDFDocumentException(220, "PDF table can not created"); + throw pde; + } + catch (MalformedURLException e) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("MalformedURLException:" + e.getMessage()); + } + PDFDocumentException pde = new PDFDocumentException(221, "PDF table can not created"); + throw pde; + } + catch (IOException e) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("Error Code: 222, IOException:" + e.getMessage()); + } + PDFDocumentException pde = new PDFDocumentException(222, "PDF table can not created: Image can not loaded"); + throw pde; + } + break; + case Entry.TYPE_TABLE: + Table table = (Table) abstractCell.getValue(); + // inherit the style from the parent table + Style inherit_style = Style.doInherit(table.getStyle(), cell_style); + table.setStyle(inherit_style); + PdfPTable pdf_table = renderTable(table); + pdf_cell = new PdfPCell(pdf_table); + // The default new PdfPCell has a default border of 15. + // For blocks without border and subtables this results + // in a border to be drawn around the cell. + // ==> no border on default + pdf_cell.setBorder(0); + break; + } + return pdf_cell; + } + + /** + * This method visualize an abstract table into a corresponding pdf table. The + * new pdf table is redered and get the style information from the abstract + * cell. + * + * @param abstractTable + * the abstract table definition + * @return the new redererd pdf table cell + * @throws PDFDocumentException + * ErrorCode:220, 221, 222, 223 + * @see com.lowagie.text.pdf.PdfPTable + * @see at.knowcenter.wag.egov.egiz.table.Table + */ + private PdfPTable renderTable(Table abstractTable) throws PDFDocumentException + { + if (abstractTable == null) + { + PDFDocumentException pde = new PDFDocumentException(223, "Table is not defined."); + throw pde; + } + PdfPTable pdf_table = null; + float[] cols = abstractTable.getColsRelativeWith(); + int max_cols = abstractTable.getMaxCols(); + if (cols == null) + { + cols = new float[max_cols]; + // set the column ratio for all columns to 1 + for (int cols_idx = 0; cols_idx < cols.length; cols_idx++) + { + cols[cols_idx] = 1; + } + } + pdf_table = new PdfPTable(cols); + pdf_table.setWidthPercentage(abstractTable.getWidth()); + Style table_style = abstractTable.getStyle(); + setCellStyle(pdf_table.getDefaultCell(), table_style, Entry.TYPE_TABLE); + + ArrayList rows = abstractTable.getRows(); + for (int row_idx = 0; row_idx < rows.size(); row_idx++) + { + ArrayList row = (ArrayList) rows.get(row_idx); + // logger_.debug("## Row:" + row_idx + " ## of table:" + + // abstractTable.getName()); + for (int entry_idx = 0; entry_idx < row.size(); entry_idx++) + { + Entry cell = (Entry) row.get(entry_idx); + // 03.11.2010 changed by exthex - swapped the two params, was probably a bug + Style inherit_style = Style.doInherit(table_style, cell.getStyle()); + cell.setStyle(inherit_style); + // logger_.debug(cell.toString()); + PdfPCell pdf_cell = renderCell(cell); + if (cell.getColSpan() > 1) + { + pdf_cell.setColspan(cell.getColSpan()); + } + if (cell.isNoWrap()) + { + pdf_cell.setNoWrap(true); + } + // System.err.println("valign:" + pdf_cell.getVerticalAlignment() + " + // halign:" + + // pdf_cell.getHorizontalAlignment()); + pdf_table.addCell(pdf_cell); + } + } + // logger_.debug("render table:" + abstractTable.getName()); + return pdf_table; + } + + /** + * This method creates the pdf table object. It takes the abstract table + * definition from the signature object and render the abstract table. + * + * @param sigObject + * the signature object, the base for the abstract table definition + * @return R + * @throws PDFDocumentException + * ErrorCode:220, 221, 222, 223 + */ + private PdfPTable createPDFSignatureObject(SignatureObject sigObject) throws PDFDocumentException + { + SubsetLocal.clear(); + Table table = sigObject.getAbstractTable(); + PdfPTable pdf_table = renderTable(table); + return pdf_table; + } + + /* + * This method search for the table definitions in the settings file an init + * @param sigObject + */ + /* + * private void initTableSettings(SignatureObject sigObject) { String sig_type = + * sigObject.getSignationType(); String table_key = SignatureObject.SIG_OBJ + + * sig_type + ".table."; ArrayList main_rows = settings_.getKeys(table_key + + * "main"); } + */ + + /** + * Converts the current abstract signature object in a pdf signature object + * implementation + * + * @return the converted pdf signature object + * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject() + */ + public Object getSignatureObject() throws PDFDocumentException + { + if (pdfSigObject_ == null) + { + pdfSigObject_ = (PdfPTable) getSignatureObject(sigObject_); + } + return pdfSigObject_; + } + + /** + * Converts a abstract signature object in a pdf signature object + * implementation + * + * @param sigObject + * the abstract signatorObject to convert + * @return the converted pdf signature object + * @throws PDFDocumentException + * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) + */ + public Object getSignatureObject(SignatureObject sigObject) throws PDFDocumentException + { + // initTableSettings(sigObject); + return createPDFSignatureObject(sigObject); + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java new file mode 100644 index 0000000..e2a3d06 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java @@ -0,0 +1,148 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFUtilities.java,v 1.3 2006/10/31 08:09:33 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; + +import org.pdfbox.pdfparser.PDFParser; +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.pdmodel.PDPage; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +import com.lowagie.text.DocumentException; + +/** + * Contains useful helpers for accessing PDF documents. + * + * @author wprinz + * @author mruhmer + */ +public abstract class PDFUtilities +{ + public static float calculatePageLength(final PdfDataSource pdfDataSource,int page ,float footer_line, int pagerotation) throws PDFDocumentException + { + try + { + //ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); + //byte [] normalized_pdf = TextualSignature.normalizePDF(original_bais); + byte [] normalized_pdf = TextualSignature.normalizePDF(pdfDataSource); + + // PERF: The whole PDF normalization process is costy + ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); + + PDFParser parser = new PDFParser(bais); + File temporary_dir = SettingsReader.getTemporaryDirectory(); + parser.setTempDirectory(temporary_dir); + parser.parse(); + + PDDocument pdfDocument_ = parser.getPDDocument(); + float page_length = calculatePageLength(pdfDocument_,page , footer_line, pagerotation); + pdfDocument_.close(); + return page_length; + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + catch (DocumentException e) + { + throw new PDFDocumentException(201, e); + } + } + public static float calculatePageLength(PDDocument document,int page ,float footer_line, int pagerotation) throws IOException + { + //int last_page_id = document.getNumberOfPages(); + List allPages = document.getDocumentCatalog().getAllPages(); + PDPage pdpage = (PDPage) allPages.get(page); + pdpage.setRotation(pagerotation); + return calculatePageLength(pdpage, footer_line); + } + + /** + * @deprecated + * @param pdf + * @param footer_line + * @return + * @throws PDFDocumentException + */ + public static float calculateLastPageLength(final byte[] pdf, float footer_line) throws PDFDocumentException + { + try + { + //ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); + PdfDataSource dataSource = new ByteArrayPdfDataSourceImpl(pdf); + byte [] normalized_pdf = TextualSignature.normalizePDF(dataSource); + + ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); + + PDFParser parser = new PDFParser(bais); + File temporary_dir = SettingsReader.getTemporaryDirectory(); + parser.setTempDirectory(temporary_dir); + parser.parse(); + + PDDocument pdfDocument_ = parser.getPDDocument(); + float last_page_length = calculateLastPageLength(pdfDocument_, footer_line); + pdfDocument_.close(); + + return last_page_length; + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + catch (DocumentException e) + { + throw new PDFDocumentException(201, e); + } + } + + public static float calculateLastPageLength(PDDocument document, float footer_line) throws IOException + { + int last_page_id = document.getNumberOfPages(); + List allPages = document.getDocumentCatalog().getAllPages(); + PDPage last_page = (PDPage) allPages.get(last_page_id - 1); + + return calculatePageLength(last_page, footer_line); + } + + public static float calculatePageLength(PDPage page, float footer_line) throws IOException + { + // logger_.debug("Last Page id:" + last_page_id); + // PDPage last_page = (PDPage) allPages.get(0); + PDFPage my_page = new PDFPage(footer_line); + my_page.processStream(page, page.findResources(), page.getContents().getStream()); + return my_page.getMaxPageLength(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java new file mode 100644 index 0000000..9249985 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Placeholder.java @@ -0,0 +1,572 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Placeholder.java,v 1.5 2006/10/31 08:17:50 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.sound.midi.SysexMessage; + +import org.apache.commons.codec.net.URLCodec; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; +import at.knowcenter.wag.egov.egiz.exceptions.PlaceholderException; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +/** + * Helper class that provides functionality for dealing with placeholders and + * replacements in pdf. + * + * @author wprinz + */ +public abstract class Placeholder +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Placeholder.class); + + /** + * Escapes the String to be a suitable Literal String.. + * + * @param data + * The String to be escaped. + * @return Returns the escaped PDF String. + */ + public static byte[] escapePDFString(byte[] data) + { + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < data.length; i++) + { + byte[] escaped_bytes = escapeByte(data[i]); + baos.write(escaped_bytes); + } + return baos.toByteArray(); + } + catch (IOException e) + { + logger_.error(e.getMessage(), e); + return null; + } + } + + /** + * Unescapes the PDF String. + * + * @param data + * The escaped String. + * @return Returns the unescaped String. + */ + public static byte[] unescapePDFString(byte[] data) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < data.length; i++) + { + if (data[i] == '\\' && data[i + 1] == '\\') + { + baos.write('\\'); + i++; + continue; + } + if (data[i] == '\\' && data[i + 1] == '(') + + { + baos.write('('); + i++; + continue; + } + if (data[i] == '\\' && data[i + 1] == ')') + { + baos.write(')'); + i++; + continue; + } + baos.write(data[i]); + } + return baos.toByteArray(); + } + + /** + * Reconstructs the string from a partition of placeholders. + * + * @param pdf + * The PDF to read the string from. + * @param sis + * The list of StringInfo objects that specify the bytes of the + * string in the pdf. + * @return Returns the extracted and reconverted string. + * @throws IOException + * Forwarded exception. + */ + public static String reconstructStringFromPartition(byte[] pdf, List sis, + byte[] enc) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + Iterator it = sis.iterator(); + while (it.hasNext()) + { + StringInfo si = (StringInfo) it.next(); + + for (int i = si.string_start; i < si.string_start + si.string_length; i++) + { + if (pdf[i] != 0) + { + baos.write(pdf[i]); + } + } + } + + baos.close(); + byte[] bytes = baos.toByteArray(); + + byte[] unescaped_bytes = unescapePDFString(bytes); + + if (!ByteArrayUtils.compareByteArrays(enc, 0, BinarySignature.ENCODING_WIN) && !ByteArrayUtils.compareByteArrays(enc, 0, BinarySignature.ENCODING_URL)) + { + String enc_str = new String(enc, "US-ASCII"); + logger_.warn("The encoding " + enc_str + " is not known by this application - trying to proceed anyways."); + } + + String text = new String(unescaped_bytes, "windows-1252"); + + String str = text; + if (ByteArrayUtils.compareByteArrays(enc, 0, BinarySignature.ENCODING_URL)) + { + str = unapplyURLEncoding(str); + } + + return str; + } + + /** + * Prepares the given String to a byte array that can be substituted into the + * placeholder. + * + * @param text + * The text to be prepared for substitution. + * @return Returns the prepared byte array. + */ + public static byte[] applyWinAnsiEncoding(String text) + { + // text = text.replace("\\", "\\\\"); + // text = text.replace("(", "\\("); + // text = text.replace(")", "\\)"); + + byte[] replace_bytes; + try + { + replace_bytes = text.getBytes("windows-1252");// CP1252 = WinAnsiEncoding + + // test the opposite way: + // String restored_string = new String (replace_bytes, "windows-1252"); + // if (!restored_string.equals(text)) + // { + // String url_encoded = URLEncoder.encode(text); + // replace_bytes = url_encoded.getBytes("windows-1252"); + // } + } + catch (UnsupportedEncodingException e) + { + logger_.error(e.getMessage(), e); + return null; + } + return replace_bytes; + } + + /** + * Unapplies the WinAnsi encoding. + * + * @param replace_bytes + * The bytes. + * @return Returns the decoded String. + */ + public static String unapplyWinAnsiEncoding(byte[] replace_bytes) + { + try + { + String text = new String(replace_bytes, "windows-1252"); + + return text; + } + catch (UnsupportedEncodingException e) + { + logger_.error(e.getMessage(), e); + return null; + } + + } + + /** + * Applies the URL encoding to the text. + * + * @param text + * The text + * @return Returns the URL and WinAnsi encoded text. + */ + public static byte[] applyURLEncoding(String text) + { + URLCodec utf8_url_codec = new URLCodec("UTF-8"); + String url_encoded = null; + try + { + url_encoded = utf8_url_codec.encode(text, "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Couldn't url encode : " + text, e); + } + // String url_encoded = URLEncoder.encode(text); + return applyWinAnsiEncoding(url_encoded); + } + + /** + * Unapplies the WinAnsi and URL encoding. + * + * @param winansi_str + * The Winansi and URL text. + * @return Returns the decoded text. + */ + public static String unapplyURLEncoding(String winansi_str) + { + URLCodec utf8_url_codec = new URLCodec("UTF-8"); + String url_decoded = null; + try + { + url_decoded = utf8_url_codec.decode(winansi_str, "UTF-8"); + } + catch (Exception e) + { + throw new RuntimeException("Couldn't url decode : " + winansi_str, e); + } + // String url_decoded = URLDecoder.decode(winansi_str); + return url_decoded; + } + + /** + * Restores the String from a previously prepared byte array. + * + * @param pdf_string + * The byte array. + * @return Returns the unprepared String. + */ + public static String unprepareAndUnescapeString(byte[] pdf_string) + { + try + { + String text = new String(pdf_string, "windows-1252"); + + // This makes problems when "+" appears. + // if (isURLEncoded(text)) + // { + // text = URLDecoder.decode(text); + // } + +// text = text.replace("\\)", ")"); +// text = text.replace("\\(", "("); +// text = text.replace("\\\\", "\\"); + + // TODO: replace jdk1.5-code with jdf1.4-code (should be tested) + /* */ + text = text.replaceAll("\\\\\\)", ")"); + text = text.replaceAll("\\\\\\(", "("); + text = text.replaceAll("\\\\\\\\", "\\\\"); + + + return text; + } + catch (UnsupportedEncodingException e) + { + logger_.error(e.getMessage(), e); + return null; + } + } + + /** + * Checks the presence of typical URL encoded characters to tell if the string + * is URL encoded. + * + *

+ * This heuristic checks if there are any non URL encoded characters in the + * String, like ASCII control characters, which aren't allowed in the + * URLEncoding characterset. + *

+ * + * @param text + * The text under suspicion. + * @return Returns true if the String is URL encoded, false otherwise. + */ + protected static boolean isURLEncoded(String text) + { + if (text.indexOf(' ') >= 0) + { + return false; + } + for (int i = 0; i < text.length(); i++) + { + char c = text.charAt(i); + if (0x00 <= c && c <= 0x1f) + { + return false; + } + if (c == 0x7F) + { + return false; + } + if (0x80 <= c) + { + return false; + } + } + return true; + } + + /** + * Tells, if a break can occur behind the given character. + * + * @param character + * The character. + * @return Returns true, if a break may occur behind the character, false + * otherwise. + */ + protected static boolean canBreakAfter(byte character) + { + return (character == ' ' || character == '.' || character == ',' || character == ';' || character == '-' || character == '\n') ; + } + + /** + * Scans the given PDF content stream for literal PDF strings. + * + * @param pdf + * The PDF. + * @param stream_start + * The start of the content stream to be scanned. + * @param stream_next + * The end of the content stream. + * @return Returns a list of StringInfo objects specifying the strings that + * could be found. + */ + public static List parseStrings(byte[] pdf, int stream_start, int stream_next) + { + List strings = new ArrayList(); + StringInfo cur_string = null; + for (int i = stream_start; i < stream_next; i++) + { + byte cur_byte = pdf[i]; + + if (cur_byte == '(' && pdf[i - 1] != '\\') + { + cur_string = new StringInfo(); + cur_string.pdf = pdf; + cur_string.string_start = i + 1; + cur_string.string_length = -1; + // logger_.debug("String start = " + cur_string.string_start); + continue; + } + if (cur_byte == ')' && pdf[i - 1] != '\\') + { + cur_string.string_length = i - cur_string.string_start; + // logger_.debug("String length = " + cur_string.string_length); + strings.add(cur_string); + + cur_string = null; + continue; + } + } + + return strings; + } + + /** + * Escapes the data byte if necessary. + * + *

+ * Before bytes can be written into the pdf Strings, they have to be escaped. + * Special care has to be taken that escaped sequences are not split due to + * line breaks. This could have fatal consequences and usually renders the + * whole document invalid. + *

+ * + * @param data + * The data byte to be escaped. + * @return Returns a new byte array escaping the data byte. If the byte needs + * not to be escaped, this new array will contain only the original + * data byte. + */ + public static byte[] escapeByte(byte data) + { + if (data == '\\') + { + return new byte[] { '\\', '\\' }; + } + if (data == '(') + { + return new byte[] { '\\', '(' }; + } + if (data == ')') + { + return new byte[] { '\\', ')' }; + } + return new byte[] { data }; + } + + /** + * Replaces the placeholder with the given String breaking lines with a given + * tolerance. + * + * @param pdf + * The PDF. + * @param sis + * The list of StringInfo objects describing the positions where the + * String should be filled in. + * @param replace_bytes + * The unescaped bytes to be filled in. Escaping is performed by this + * method. + * @param tolerance + * The tolerance for line wrapping. The tolerance counts from the end + * of a StringInfo backwards to its start. If a word that starts + * within the tolerance doesn't fit, it is wrapped into the next + * line. + * @throws PDFDocumentException + * Forwarded exception. + */ + public static void replacePlaceholderWithTolerance(byte[] pdf, List sis, + byte[] replace_bytes, int tolerance) throws PDFDocumentException + { + try + { + // String rep_str = new String(replace_bytes); + + SplitStrings ss = new SplitStrings(pdf, sis); + + int read_index = 0; + while (read_index < replace_bytes.length) + { + if (!ss.isValidLine()) + { + break; + } + + byte[] token = readToken(replace_bytes, read_index); + // String token_str = new String(token); + byte[] escaped_token = escapeToken(token); + + if (ss.fits(escaped_token)) + { + ss.write(escaped_token); + read_index += token.length; + continue; + } + else + { + if (ss.getAvailable() < tolerance) + { + ss.newline(); + continue; + } + else + { + // break the token + for (; read_index < replace_bytes.length; read_index++) + { + byte data = replace_bytes[read_index]; + + byte[] escaped_data = escapeByte(data); + + if (ss.fits(escaped_data)) + { + ss.write(escaped_data); + } + else + { + ss.newline(); + break; + } + } + continue; + + } + } + } + ss.fillRest(); + + if (read_index < replace_bytes.length) + { + logger_.error("The replace string was longer than the reserved placeholder."); + throw new PlaceholderException(null, replace_bytes.length - read_index); + } + + } + catch (IOException e) + { + throw new PDFDocumentException(201, e); + } + + } + + protected static byte[] readToken(byte[] bytes, int index) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (; index < bytes.length; index++) + { + byte data = bytes[index]; + + + // byte [] escaped_data = escapeByte(data); + baos.write(data); + + if (canBreakAfter(data)) + { + break; + } + } + + return baos.toByteArray(); + } + + + +protected static byte[] escapeToken(byte[] token) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + for (int i = 0; i < token.length; i++) + { + byte[] escaped_data = escapeByte(token[i]); + baos.write(escaped_data); + } + + return baos.toByteArray(); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java new file mode 100644 index 0000000..c0b3ecd --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Pos.java @@ -0,0 +1,70 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Pos.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +/** + * Encapsulation of a position on a PDF page. + * + * @author wprinz + */ +public class Pos +{ + + public float x; + + public float y; + + public float z; + + /** + * Default constructor. + */ + public Pos() + { + } + + /** + * Constructor that sets the coordinates. + * @param xx + * @param yy + * @param zz + */ + public Pos(float xx, float yy, float zz) + { + this.x = xx; + this.y = yy; + this.z = zz; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + return "(" + this.x + "," + this.y + "," + this.z + ")"; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java new file mode 100644 index 0000000..7af4ce7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PositioningInstruction.java @@ -0,0 +1,139 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +/** + * The positioning instruction holds information of where to place the signature + * block. + * + *

+ * This instruction is given to the PDF writer in order to place the signature. + *

+ * + * @author wprinz + */ +public class PositioningInstruction +{ + + /** + * Tells, if a new plain page should be appended. + * + *

+ * This command is executed before the signature block is positioned according + * to page, x and y. + *

+ */ + protected boolean make_new_page = false; + + /** + * The number of the page on which the signature block is to be placed. If + * specified to make a new page, the number of this newly created page can be + * used here as well. + */ + protected int page = 0; + + /** + * The x coordinate where the upper left corner of the signature block should + * be placed. + */ + protected float x = 0.0f; + + /** + * The y coordinate where the upper left corner of the signature block should + * be placed. + */ + protected float y = 0.0f; + + /** + * + * @param make_new_page + * Tells, if a new plain page should be appended. This command is + * executed before the signature block is positioned according to + * page, x and y. + * @param page + * The number of the page on which the signature block is to be + * placed. If specified to make a new page, the number of this newly + * created page can be used here as well. + * @param x + * The x coordinate where the upper left corner of the signature + * block should be placed. + * @param y + * The y coordinate where the upper left corner of the signature + * block should be placed. + */ + public PositioningInstruction(boolean make_new_page, int page, float x, float y) + { + this.make_new_page = make_new_page; + this.page = page; + this.x = x; + this.y = y; + } + + /** + * Tells, if a new plain page should be appended to the document. + * + * @return Returns true, if a new plain page should be appended. + */ + public boolean isMakeNewPage() + { + return this.make_new_page; + } + + /** + * Returns the page on which the signature is to be printed. + * + * @return Returns the page on which the signature is to be printed. + */ + public int getPage() + { + return this.page; + } + + /** + * Returns the x coordinate where the upper left corner of the signature block + * should be placed. + * + * @return Returns the x coordinate where the upper left corner of the + * signature block should be placed. + */ + public float getX() + { + return this.x; + } + + /** + * Returns the y coordinate where the upper left corner of the signature block + * should be placed. + * + * @return Returns the y coordinate where the upper left corner of the + * signature block should be placed. + */ + public float getY() + { + return this.y; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java new file mode 100644 index 0000000..520d987 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/ReplaceInfo.java @@ -0,0 +1,93 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ReplaceInfo.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; +import java.util.List; + +import at.knowcenter.wag.egov.egiz.sig.SignatureFieldDefinition; + +/** + * Holds the information requeired to replace a certain value in the document + * completely. + * + * @author wprinz + */ +public class ReplaceInfo implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 7307210282876750431L; + + /** + * The field definition of this value. + */ + public SignatureFieldDefinition sfd = null; + + /** + * The value itself. + */ + public String value = null; + + /** + * The list of Strings this value must be splitted to. + */ + public List replaces = null; + + /** + * The brev of this value. + */ + public byte[] brev = null; + + /** + * The encoding of this value. + */ + public byte[] enc = null; + + public String toString() { + return "ReplaceInfo [brev=" + (brev != null ? arrayToString(brev, brev.length) : null) + + ", enc=" + (enc != null ? arrayToString(enc, enc.length) : null) + ", sfd=" + sfd + + ", value=" + value + "]"; + } + + private String arrayToString(Object array, int len) { + StringBuffer buffer = new StringBuffer(); + buffer.append("["); + for (int i = 0; i < len; i++) { + if (i > 0) + buffer.append(", "); + if (array instanceof byte[]) + buffer.append(((byte[]) array)[i]); + } + buffer.append("]"); + return buffer.toString(); + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java new file mode 100644 index 0000000..54cac64 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SignatureHolder.java @@ -0,0 +1,76 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureHolder.java,v 1.3 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Data structure that holds the information of one signature block, which is + * the signed/signable text and the corresponding SignatureObject. + * + *

+ * Signators and Verifiactors should implement own classes for this interface + * that generate the text to be signed from the underlying data. For example a + * binary signature holder could generate the text to be signed by Base64 + * encoding the binary data. Furthermore this allows to cache the text to be + * signed. + *

+ * + * @author wprinz + */ +public interface SignatureHolder +{ + +// /** +// * Returns the signed text (verification) or the to-be-signed signable text +// * (signation). +// * +// *

+// * Note that this text must be the one that was actually signed. This text is +// * directly passed to the connector for signation/verification. No +// * normalization or modification will be / must be done to this text between +// * reading out from the signature holder and passing the text to the +// * connector. +// *

+// * +// * @return Returns the signed text or the to-be-signed signable text. +// */ +// public String getSignedText(); + + /** + * + * @return Returns the SignatureObject containing the issuer, serial number, + * etc. + */ + public SignatureObject getSignatureObject(); + + /** + * Returns the DataSource providing the data. + * @return + */ + public DataSource getDataSource(); +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java new file mode 100644 index 0000000..be2b2b4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/SplitStrings.java @@ -0,0 +1,177 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SplitStrings.java,v 1.1 2006/08/30 14:02:35 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.util.List; + +import org.apache.commons.lang.ArrayUtils; + + +/** + * Class that helps filling out the placeholders. + * + *

+ * This class treats a sequence of placeholder StringInfos like a continuous + * data area that can be filled out regarding the boundaries. + *

+ * + * @author wprinz + */ +public class SplitStrings +{ + /** + * The byte used to fill unused bytes in the placeholders. + */ + + public static final byte FILL_BYTE = ' '; + + /** + * The underlying PDF. + */ + protected byte[] pdf = null; + + /** + * The strings to be filled out. + */ + protected StringInfo[] strings = null; + + /** + * The current string which is written to. + */ + protected int cur_string = 0; + + /** + * The current write position within the current string. + */ + protected int cur_pos = 0; + + /** + * Constructor. + * + * @param pdf + * The underlying PDF. + * @param strings + * The strings to be filled out. + */ + public SplitStrings(byte[] pdf, List strings) + { + this.pdf = pdf; + this.strings = new StringInfo[strings.size()]; + for (int i = 0; i < strings.size(); i++) + { + StringInfo si = (StringInfo) strings.get(i); + this.strings[i] = si; + } + } + + /** + * Returns how many bytes are still available in the current string. + * + * @return Returns the number of bytes that are still available. (positive + * integer, or zero if none are available) + */ + public int getAvailable() + { + return this.strings[this.cur_string].string_length - this.cur_pos; + } + + /** + * Tells, if the whole data would fit into the current string. + * + * @param data + * The data to be matched for fitting + * @return Returns true, if the whole data fits, false otherwise. + */ + public boolean fits(byte[] data) + { + return getAvailable() >= data.length; + } + + /** + * Writes the data into the current string. + * + *

+ * Note that the data must fit in. + *

+ * @param data The data to be written. + */ + public void write(byte[] data) + { + if (!fits(data)) + { + throw new IllegalArgumentException("The data doesn't fit in."); + } + + System.arraycopy(data, 0, this.pdf, this.strings[this.cur_string].string_start + this.cur_pos, data.length); + this.cur_pos += data.length; + + if (data[data.length-1] == '\n') { + this.cur_pos -= 1; // remove \n from output + newline(); + } + } + + /** + * Fills the current string with the fill character and moves on to the next + * string. + * + */ + public void newline() + { + int end = this.strings[this.cur_string].string_start + this.strings[this.cur_string].string_length; + for (int i = this.strings[this.cur_string].string_start + this.cur_pos; i < end; i++) + { + pdf[i] = FILL_BYTE; + } + + this.cur_string++; + this.cur_pos = 0; + } + + /** + * Fills all rest bytes with the fill character. + * + *

+ * This should be called when everything is finished to fill all strings properly. + *

+ */ + public void fillRest() + { + while (this.cur_string < this.strings.length) + { + newline(); + } + } + + /** + * Tells, if the current line is valid. + * @return Returns true, if this is a line that can be written to. + */ + public boolean isValidLine () + { + return this.cur_string < this.strings.length; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java new file mode 100644 index 0000000..1982077 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StringInfo.java @@ -0,0 +1,106 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: StringInfo.java,v 1.2 2006/10/11 07:57:58 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Specifies a certain data area within the pdf. + * + *

+ * Actually this is a byte range, which is used to hold the placeholder ranges + * for later replacement. + *

+ * + * @author wprinz + */ +public class StringInfo implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 5834801907046737048L; + + protected static Log logger = LogFactory.getLog(StringInfo.class); + + /** + * The PDF document this range belongs to. + */ + public byte[] pdf = null; + + /** + * The start offset of the range. + */ + public int string_start = -1; + + /** + * The length of the range. + */ + public int string_length = -1; + + /** + * Copies the bytes of this range to a new byte array. + * + * @return Returns the new byte array. + */ + public byte[] copyStringBytes() + { + byte[] bytes = new byte[this.string_length]; + System.arraycopy(this.pdf, this.string_start, bytes, 0, this.string_length); + return bytes; + } + + /** + * Converts the range into a String. + * + * @return Returns the String. + * @throws UnsupportedEncodingException + * Forwarded exception. + */ + public String getString(String encoding) throws UnsupportedEncodingException + { + byte[] bytes = copyStringBytes(); + return new String(bytes, encoding); + } + + public String toString() + { + try + { + return "(" + this.string_start + "," + this.string_length + ")" + getString("ISO-8859-1"); + } + catch (UnsupportedEncodingException e) + { + logger.error(e.getMessage(), e); + return "(" + this.string_start + "," + this.string_length + ")"; + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java new file mode 100644 index 0000000..7ca5a0a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java @@ -0,0 +1,716 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PresentableException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfArray; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfDictionary; +import com.lowagie.text.pdf.PdfFormField; +import com.lowagie.text.pdf.PdfIndirectReference; +import com.lowagie.text.pdf.PdfName; +import com.lowagie.text.pdf.PdfNumber; +import com.lowagie.text.pdf.PdfObject; +import com.lowagie.text.pdf.PdfStamper; +import com.lowagie.text.pdf.PdfStamperImp; +import com.lowagie.text.pdf.PdfString; +import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdfas.StructContentWriter; +import com.lowagie.text.pdfas.StructContentWriterHolder; +import com.lowagie.text.pdfas.UrlInTextFinder; + +/** + * Helper class for writing the structure hierarchy of the signature elements. + * Everything is written with the PdfObject low level API because there is no better support. + * The structured content is only written for structured (==tagged) input documents. The methods have to be called in the + * defined order. The object cannot be reused for several signatures.
+ * See pdf spec "Logical Structure" for details.
+ * The struct writing could be a little more abstracted, but this would include quite some itext extension work. And like this it + * fits better to PDF-AS / wprinz coding style :-( + * @author exthex + * + */ +public class StructContentHelper implements StructContentWriter { + private static final Logger logger = Logger.getLogger(StructContentHelper.class); + + private static final String SIGBLOCK_STRUCT_TYPE = "P"; + private static final PdfName PARENTTREENEXTKEY = new PdfName("ParentTreeNextKey"); + private static final String ALT_TEXT_DEFAULT = "Signaturbildmarke"; + private final static String ALT_TEXT_CONF_KEY = "sigLogoAltText"; + + + private int nextMcid = 0; + /** + * MCID value used for the sigblock marked contend identifier + */ + private int sigBlockMcid =-1; + /** + * MCID value for "Bildmarke" marked content sequence + */ + private int figureMcid = -1; + /** + * MCID value for verify link marked content sequence + */ + private int linkMcid = -1; + private String linkUrlString = null; + private boolean isTagged = false; + private Map linkPosMap = new HashMap(); + private Map tmpMap = new HashMap(); + + private PdfStamper stamper; + private PdfStamperImp stamperImp; + private PdfContentByte content; + private PdfDictionary page; + private PdfNumber parentTreeNextKey = null; + private PdfNumber annotationParentTreeKey = null; + + /** + * Temporary save a pos + */ + private Rectangle tempMarkedPos = null; + /** + * Cell position of the signature verify link overlay + */ + private Rectangle verifyLinkCellPos = null; + + /** + * Kids array (K) of the StructTreeRoot + */ + private PdfArray structTreeRootKids = null; + + /** + * Entry in the ParentTree.Nums array used for sigtable structs + */ + private PdfArray mainParentTreeNumEntry; + + /** + * Create new helper for one signature, and bind it to {@link StructContentWriterHolder} + * for thread local access from itext. + * + * @param stamper + * @param content + * @param pageNr + */ + StructContentHelper(PdfStamper stamper, PdfContentByte content, int pageNr) { + this.stamper = stamper; + this.content = content; + stamperImp = ((PdfStamperImp) stamper.getWriter()); + page = stamper.getReader().getPageN(pageNr); + StructContentWriterHolder.setThreadLocalWriter(this); + } + + /** + * Remove thread local helper + */ + public void removeCurrent() { + StructContentWriterHolder.removeThreadLocalWriter(); + } + + /** + * Prepare structured content for signature block. This method initializes the whole StructTreeRoot stuff. + * @param sigBlockObj + * @throws PresentableException + */ + void prepareStructData(PdfTemplate sigBlockObj) throws PresentableException { + + try { + checkTagging(); + if (!isTagged) { + return; + } + + doAnnoTabOrder(); + + PdfDictionary structTreeRoot = getStructTreeRoot(); + stamperImp.markUsed(structTreeRoot); + + PdfArray parentTreeNums = getParentTreeNums(); + + PdfNumber structParentsNr = page.getAsNumber(PdfName.STRUCTPARENTS); // read StructParents entry from current page + + mainParentTreeNumEntry = obtainParentTreeEntry(structTreeRoot, parentTreeNums, structParentsNr, sigBlockObj); + + nextMcid = mainParentTreeNumEntry.size(); + sigBlockMcid = nextMcid; + nextMcid++; + + this.structTreeRootKids = obtainStructTreeRootKids(structTreeRoot); + + if(this.structTreeRootKids == null) + { + this.structTreeRootKids = this.createStructTreeRootKids(structTreeRoot); + } + + } catch (Exception ex) { + logger.error("error", ex); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "error writing structured signature content", ex); + } + } + + PdfArray createStructTreeRootKids(PdfDictionary structTreeRoot) { + PdfArray tmp = new PdfArray(); + structTreeRoot.put(PdfName.K, tmp); + return tmp; + } + + /** + * Create struct data for main signature block + * @throws PresentableException + */ + void buildSigBlockStructData() throws PresentableException { + if (!isTagged) return; + try { + PdfIndirectReference newStructRef = createStructElem(SIGBLOCK_STRUCT_TYPE, new PdfNumber( + sigBlockMcid), getStructTreeRoot().getIndRef()); + + // ADD everything at the end because nothing can be written afterwards + structTreeRootKids.add(newStructRef); + mainParentTreeNumEntry.add(newStructRef); + + stamperImp.markUsed(mainParentTreeNumEntry); + + } catch (Exception ex) { + logger.error("error", ex); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "error writing structured signature content", ex); + } + } + + + /** + * Finish struct data for signblock and it's elements (NOT for the external link and annot!) + * @throws PresentableException + */ + void finishMainStructData() throws PresentableException { + try { + if (isTagged && mainParentTreeNumEntry.getIndRef() == null) { + getParentTreeNums().add( + stamper.getWriter().addToBody(mainParentTreeNumEntry).getIndirectReference()); + stamperImp.markUsed(getParentTreeNums()); + stamperImp.markUsed(getStructTreeRoot().getAsDict(PdfName.PARENTTREE)); + } + } catch (Exception ex) { + logger.error("error", ex); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "error writing structured signature content", ex); + } + } + + /** + * Build the structured content for the signature logo (bildmarke). {@link #beginFigureContent(PdfContentByte)} and + * {@link #endFigureContent(PdfContentByte)} have to be called before this method to mark the logo in the stream. This + * is done implicitly in the modified itext source (see {@link StructContentWriterHolder}). + * @param so + * @param sigBlockObj + * @throws PresentableException + */ + void buildFigureStructData(SignatureObject so, PdfTemplate sigBlockObj) throws PresentableException { + try { + if (isTagged && isFigureMarked()) { + + PdfDictionary structTreeRoot = getStructTreeRoot(); + PdfIndirectReference mcrRef = createMcrStructElem(this.figureMcid, sigBlockObj.getIndirectReference()); + PdfIndirectReference figureRef = createStructElem("Figure", mcrRef, + getAltText(so.getSignatureTypeDefinition().getType()), structTreeRoot.getIndRef()); + + structTreeRootKids.add(figureRef); + mainParentTreeNumEntry.add(figureRef); + + stamperImp.markUsed(structTreeRootKids); + stamperImp.markUsed(structTreeRoot); + stamperImp.markUsed(mainParentTreeNumEntry); + + } + + } catch (Exception ex) { + logger.error("error", ex); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "error writing structured signature content", ex); + } + + } + + /** + * Build the link annotation for the signature verification link and the structured content accordingly.
+ * The tagging does NOT work if the link is placed in a binary signature replace cell (phlengh for this cell)!! + * @param sigBlockObj + * @param atp + * @throws PresentableException + */ + void buildVerifyLinkStructData(PdfTemplate sigBlockObj, ActualTablePos atp) throws PresentableException { + if (!this.isTagged || !this.isLinkMarked() || !isLinkFound()) return; + + try { + PdfNumber parentTreeKey = getNewParentTreeKey(); + + PdfArray annots = obrainAnnotsFromPage(); + + PdfIndirectReference linkAnnotRef = createLinkAnnot(parentTreeKey, atp); + annots.add(linkAnnotRef); + + PdfIndirectReference objr = createObjrStructElem(linkAnnotRef); + PdfIndirectReference mcr = createMcrStructElem(this.linkMcid, sigBlockObj.getIndirectReference()); + + PdfDictionary structTreeRoot = getStructTreeRoot(); + + PdfArray linkKids = new PdfArray(); + PdfIndirectReference linkKidsRef = stamper.getWriter().getPdfIndirectReference(); + + PdfIndirectReference linkRef = createStructElem("Link", linkKidsRef, structTreeRoot.getIndRef()); + linkKids.add(objr); + + PdfIndirectReference span = createStructElem("Span", mcr, linkRef); + linkKids.add(span); + + stamper.getWriter().addToBody(linkKids, linkKidsRef); + structTreeRootKids.add(linkRef); + + // create new entry in ParentTree + PdfArray parentTreeNums = getParentTreeNums(); + parentTreeNums.add(parentTreeKey); + parentTreeNums.add(linkRef); + + stamperImp.markUsed(parentTreeNums); + stamperImp.markUsed(structTreeRoot.getAsDict(PdfName.PARENTTREE)); + stamperImp.markUsed(structTreeRootKids); + stamperImp.markUsed(linkKids); + + stamperImp.markUsed(structTreeRoot); + + } catch (IOException e) { + logger.error("error", e); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "error writing structured signature content", e); + } + } + + private boolean isLinkFound() { + return this.linkUrlString != null && this.verifyLinkCellPos != null && this.linkPosMap.size() > 0 && this.linkMcid >= 0; + } + + /** + * Build new StructParent entry for signature annotation. + * @return + */ + PdfNumber buildAdobeSigStructParent() { + if (this.isTagged) { + this.annotationParentTreeKey = getNewParentTreeKey(); + return annotationParentTreeKey; + } else { + return null; + } + } + + /** + * Build and write structured content for adobe signature annotation + * + * @param sigFormField + * @param title + * @throws PresentableException + */ + void buildAdobeSigStruct(PdfFormField sigFormField, String title) throws PresentableException { + if (!isTagged) + return; + try { + + PdfDictionary root = getStructTreeRoot(); + + PdfIndirectReference objrRef = createObjrStructElem(sigFormField.getIndirectReference()); + + PdfIndirectReference adobeSigStructRef = createStructElem("Link", objrRef, root.getIndRef()); + + PdfArray parentTreeNums = getParentTreeNums(); + // create new entry in ParentTree + parentTreeNums.add(annotationParentTreeKey); + parentTreeNums.add(adobeSigStructRef); + + structTreeRootKids.add(adobeSigStructRef); + stamperImp.markUsed(structTreeRootKids); + + stamperImp.markUsed(parentTreeNums); + stamperImp.markUsed(root.getAsDict(PdfName.PARENTTREE)); + + } catch (Exception ex) { + logger.error("error", ex); + throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, + "error writing structured signature content", ex); + } + + } + + /** + * Start tag for signature block content stream. Place this before the signature block is written to a content stream. + * Call {@link #endSigBlockContent()} afterwards + */ + void beginSigBlockContent() { + if (isTagged) { + content.getInternalBuffer().append(new PdfName(SIGBLOCK_STRUCT_TYPE).getBytes()).append(" <> BDC").append('\n'); + } + } + + /** + * End tag for signature block content stream. Place this after the signature block is written to a content stream + */ + void endSigBlockContent() { + if (isTagged) { + content.endMarkedContentSequence(); + } + } + + /** + * Writes start tag for signature logo marked content sequence. + */ + public void beginFigureContent(PdfContentByte localContent) { + if (isTagged) { + if (!isFigureMarked()) { + this.figureMcid = this.nextMcid++; + localContent.getInternalBuffer().append("/Figure <> BDC\n"); + } else { + logger.warn("cannot tag multiple figures (bildmarken)"); + } + } + } + + /** + * Writes end tag for signature logo marked content sequence. + */ + public void endFigureContent(PdfContentByte localContent) { + if (isTagged && isFigureMarked()) { + localContent.endMarkedContentSequence(); + } + } + + /** + * Writes start tag for verify link marked content sequence. + */ + public void beginLinkContent(PdfContentByte localContent, String urlString) { + // it's called from here com.lowagie.text.pdf.PdfContentByte.showText(String) + + if (isTagged) { + if (!isLinkMarked()) { + this.linkUrlString = urlString; + this.linkMcid = this.nextMcid++; + localContent.getInternalBuffer().append("/Span <> BDC\n"); + } else { + logger.warn("cannot tag multiple verify links"); + } + } + } + + /** + * Writes end tag for verify link marked content sequence. + */ + public void endLinkContent(PdfContentByte localContent) { + if (isTagged && isLinkMarked()) { + localContent.endMarkedContentSequence(); + } + } + + /** + * Implements {@link StructContentWriter#markPos(Rectangle)} + */ + public void markPos(Rectangle pos) { + this.tempMarkedPos = pos; + } + + /** + * Implements {@link StructContentWriter#storeCurrentPosAsLink()} + */ + public void storeCurrentPosAsLink() { + this.verifyLinkCellPos = new Rectangle(this.tempMarkedPos); + } + + public void putVal(String key, Object val) { + tmpMap.put(key, val); + } + + public void storeVals() { + linkPosMap = new HashMap(tmpMap); + } + + /** + * set explicit annotation tab order if missing + */ + private void doAnnoTabOrder() { + if (page.getAsName(new PdfName("Tabs")) == null) { + page.put(new PdfName("Tabs"), PdfName.S); // set explicit annotation TAB order + stamperImp.markUsed(page); + } + } + + private void checkTagging() { + PdfDictionary markDict = stamper.getReader().getCatalog().getAsDict(PdfName.MARKINFO); + if (markDict != null) { + isTagged = markDict.getAsBoolean(PdfName.MARKED).booleanValue(); + } + if (!isTagged) { + logger.debug("input document is not tagged. no structure/wai information is written"); + } + logger.debug("Input is tagged. Writing structure/WAI data."); + } + + + + private PdfIndirectReference createLinkAnnot(PdfNumber structParentNr, ActualTablePos atp) throws IOException { + PdfDictionary linkAnnot = new PdfDictionary(); + + PdfDictionary a = new PdfDictionary(); + a.put(PdfName.S, new PdfName("URI")); + a.put(PdfName.TYPE, PdfName.ACTION); + a.put(PdfName.URI, new PdfString(this.linkUrlString)); + linkAnnot.put(PdfName.A, a); + + PdfDictionary bs = new PdfDictionary(); + bs.put(PdfName.W, new PdfNumber(0)); + linkAnnot.put(PdfName.BS, bs); + linkAnnot.put(PdfName.F, new PdfNumber(4)); + + // iText "converts" 0.0f to an integer, therefore we cannot use 0, not nice... + //linkAnnot.put(PdfName.RECT, new PdfArray(new float[] {0.01f, 0.01f, 0.01f, 0.01f})); + // take cell pos as link pos + linkAnnot.put(PdfName.RECT, new PdfArray(calcLinkPos(atp))); + + linkAnnot.put(PdfName.STRUCTPARENT, structParentNr); + linkAnnot.put(PdfName.SUBTYPE, PdfName.LINK); + + return stamper.getWriter().addToBody(linkAnnot).getIndirectReference(); + } + + + private PdfArray calcLinkPos(ActualTablePos atp) { + PdfArray res = new PdfArray(); + + float downY = atp.y - atp.height; + + float startX = atp.x + this.verifyLinkCellPos.getLeft(); + float yLine = getPosMapVal("yLine"); + float lineHigh = getPosMapVal("maxSize"); + float lineWidth = getPosMapVal("lineWidth"); + UrlInTextFinder finder = (UrlInTextFinder) this.linkPosMap.get("urlFinder"); + + // maybe one could calc the link pos even more exactly with char width counting + // but this should be close enough (see BidiLine.processLine and chunk.getcharwith) + float lineCorr = -2; + float xCorr = 5; + res.add(new PdfNumber(1 + startX + finder.calcLinkPosXStart(lineWidth))); + res.add(new PdfNumber(downY + yLine + lineHigh + lineCorr)); + res.add(new PdfNumber(xCorr + startX + finder.calcLinkPosXEnd(lineWidth))); + res.add(new PdfNumber(downY + yLine + lineCorr)); + + return res; + } + + private float getPosMapVal(String key) { + return ((Float) this.linkPosMap.get(key)).floatValue(); + } + + protected static PdfArray createPdfArrayFromTablePos(ActualTablePos pos) { + return new PdfArray( new float[] {pos.x, pos.y, pos.x + pos.width, pos.y - pos.height}); + } + + private PdfArray obrainAnnotsFromPage() throws IOException { + PdfArray annots = this.page.getAsArray(PdfName.ANNOTS); + if (annots == null) { + annots = new PdfArray(); + page.put(PdfName.ANNOTS, annots); + stamperImp.markUsed(this.page); + stamper.getWriter().addToBody(annots); + } + return annots; + } + + private PdfArray obtainStructTreeRootKids(PdfDictionary structTreeRoot) { + PdfArray rk = null; + PdfObject root_k = structTreeRoot.getDirectObject(PdfName.K); + stamperImp.markUsed(root_k); + if (root_k instanceof PdfDictionary) { + rk = new PdfArray(); + stamperImp.markUsed(structTreeRootKids); + rk.add(root_k.getIndRef()); + structTreeRoot.put(PdfName.K, structTreeRootKids); + + } else if(root_k != null) { // has to be array + rk = (PdfArray) root_k; + } + return rk; + } + + private PdfArray obtainParentTreeEntry(PdfDictionary structTreeRoot, PdfArray parentTreeNums, + PdfNumber structParentsNr, PdfTemplate sigBlockObj) { + int numsIdx = -1; + PdfArray parentTreeEntry = null; + + if (structParentsNr == null) { // no StructParents entry yet, make new one and add new parenttree entry + PdfNumber parentTreeKey = null; + parentTreeNextKey = structTreeRoot.getAsNumber(PARENTTREENEXTKEY); // read next proposed key + if (parentTreeNextKey == null) { // this can be null if a non-perfect pdf creator was at work + // find the next key by counting + int nextI = ((int) parentTreeNums.size() / 2); // know the "Number Trees" data structure from pdf-ref + this.parentTreeNextKey = new PdfNumber(nextI); + structTreeRoot.put(PARENTTREENEXTKEY, this.parentTreeNextKey); // write ParentTreeNextKey entry + } + + parentTreeKey = new PdfNumber(parentTreeNextKey.intValue()); + parentTreeNextKey.increment(); + page.put(PdfName.STRUCTPARENTS, parentTreeKey); // write /StructParents entry to page + structParentsNr = parentTreeKey; + + stamperImp.markUsed(page); + // create new entry in ParentTree + parentTreeNums.add(parentTreeKey); + parentTreeEntry = new PdfArray(); + numsIdx = parentTreeNums.size() - 1; + + } else { // structparents entry already available, find parenttree entry + //parentTreeKey = structParentsNr; + parentTreeNextKey = structTreeRoot.getAsNumber(PARENTTREENEXTKEY); // read next proposed key + if (parentTreeNextKey == null) { // this can be null if a non-perfact pdf creator was at work + // find the next key by counting + int nextI = 0; + if (parentTreeNums != null) { + nextI = ((int) parentTreeNums.size() / 2); + } + this.parentTreeNextKey = new PdfNumber(nextI); + structTreeRoot.put(PARENTTREENEXTKEY, this.parentTreeNextKey); + } + } + + // add Structparents entry to xobject content stream + sigBlockObj.addAttribute(PdfName.STRUCTPARENTS, structParentsNr); + + // find my structParentEntry + if (numsIdx < 0) { + // it's a weird data structure: "number tree", see pdf reference if you really want to understand + + // if the array has no gaps it is easy: + numsIdx = structParentsNr.intValue() * 2; + if (parentTreeNums.getAsNumber(numsIdx).intValue() != structParentsNr.intValue()) { // there seem to be gaps + for (numsIdx = 0; numsIdx < parentTreeNums.size(); numsIdx += 2) { // search manually + if (parentTreeNums.getAsNumber(numsIdx).intValue() == structParentsNr.intValue()) { + break; + } + } + } + numsIdx += 1; + } + if (parentTreeEntry == null) { + parentTreeEntry = parentTreeNums.getAsArray(numsIdx); + } + return parentTreeEntry; + } + +// private PdfIndirectReference createStructElem(String structType, PdfObject kid) throws IOException { +// return createStructElem(structType, kid, null); +// } + + private PdfIndirectReference createStructElem(String structType, PdfObject kid, PdfIndirectReference parentRef) throws IOException { + return createStructElem(structType, kid, null, parentRef); + } + + private PdfIndirectReference createStructElem(String structType, PdfObject kid, String altText, + PdfIndirectReference parentRef) throws IOException { + + PdfDictionary newStruct = new PdfDictionary(); + newStruct.put(PdfName.S, new PdfName(structType)); + //newStruct.put(PdfName.T, new PdfString("PDF-AS Signaturblock"));// eher nicht + if (parentRef != null) { + newStruct.put(PdfName.P, parentRef); + } + newStruct.put(PdfName.TYPE, new PdfName("StructElem")); + + newStruct.put(PdfName.PG, page.getIndRef()); + if (altText != null) { + newStruct.put(PdfName.ALT, new PdfString(altText)); + } + // newStruct.put(PdfName.ALT, new PdfString(getAltText(so.getSignatureTypeDefinition().getType()))); + //newStruct.put(PdfName.K, new PdfNumber(nextMcid)); + newStruct.put(PdfName.K, kid); + + return stamper.getWriter().addToBody(newStruct).getIndirectReference(); + } + + private boolean isFigureMarked() { + return this.figureMcid > -1; + } + + private boolean isLinkMarked() { + return this.linkMcid > -1; + } + + + private PdfNumber getNewParentTreeKey() { + // new parent tree entry + if (parentTreeNextKey == null) { + parentTreeNextKey = getStructTreeRoot().getAsNumber(PARENTTREENEXTKEY); // read next proposed key + } + PdfNumber res = new PdfNumber(parentTreeNextKey.intValue()); + parentTreeNextKey.increment(); + return res; + } + + + private PdfIndirectReference createObjrStructElem(PdfIndirectReference objRef) throws IOException { + PdfDictionary objr = new PdfDictionary(); + objr.put(PdfName.TYPE, new PdfName("OBJR")); + objr.put(PdfName.PG, page.getIndRef()); + objr.put(new PdfName("Obj"), objRef); + + return stamper.getWriter().addToBody(objr).getIndirectReference(); + } + + private PdfIndirectReference createMcrStructElem(int mcid, PdfIndirectReference streamRef) throws IOException { + PdfDictionary objr = new PdfDictionary(); + objr.put(PdfName.TYPE, new PdfName("MCR")); + objr.put(PdfName.PG, page.getIndRef()); + objr.put(PdfName.MCID, new PdfNumber(mcid)); + objr.put(new PdfName("Stm"), streamRef); + + return stamper.getWriter().addToBody(objr).getIndirectReference(); + } + + private PdfArray getParentTreeNums() { + return getStructTreeRoot().getAsDict(PdfName.PARENTTREE).getAsArray(PdfName.NUMS); + } + + private PdfDictionary getStructTreeRoot() { + return stamper.getReader().getCatalog().getAsDict(PdfName.STRUCTTREEROOT); + } + + private static String getAltText(String sigProfile) { + return AdobeSignatureHelper.getDefaultableConfigProperty(sigProfile, ALT_TEXT_CONF_KEY, ALT_TEXT_DEFAULT); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java new file mode 100644 index 0000000..53d6609 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TablePos.java @@ -0,0 +1,262 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TablePos.java,v 1.1 2006/08/25 17:10:08 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +/** + * Class that holds the exact position where the table should be written to the + * document. + * + * @author wprinz + * @author mruhmer + */ +public class TablePos implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -5299027706623518059L; + + /** + * The page on which the block should be displayed. + * + */ + private int page = 0; + + /** + * The x position. + */ + private float pos_x = 0.0f; + + /** + * The y position. + */ + private float pos_y = 0.0f; + + /** + * The width of the block. + */ + private float width = 0.0f; + /** + * The top y position of the footer line. + */ + public float footer_line = 0.0f; + + /** + * The y position. + */ + public String myposstring = ""; + + private boolean newpage = false; + private boolean autoX = true; + private boolean autoY = true; + private boolean autoW = true; + private boolean autoP = true; + + public boolean isXauto() + { + return this.autoX; + } + public boolean isYauto() + { + return this.autoY; + } + public boolean isWauto() + { + return this.autoW; + } + public boolean isPauto() + { + return this.autoP; + } + public boolean isNewPage() + { + return this.newpage; + } + public int getPage() + { + return this.page; + } + public float getFooterLine() + { + //ignore if newpage and y is not auto + if (!this.autoY || this.newpage) + { + return 0.0f; + } + return this.footer_line; + } + public float getPosX() + { + return this.pos_x; + } + public float getPosY() + { + return this.pos_y; + } + public float getWidth() + { + return this.width; + } + public TablePos() + { + //nothing to do --> default + } + + /** + * Constructor. + * + * @param pos_string The pos instruction. + * format : [x:x_algo];[y:y_algo];[w:w_algo][p:p_algo];[f:f_algo] + * x_algo:='auto' ... automatic positioning x + * floatvalue ... absolute x + * y_algo:='auto' ... automatic positioning y + * floatvalue ... absolute y + * w_algo:='auto' ... automatic width + * floatvalue ... absolute width + * p_algo:='auto' ... automatic last page + * 'new' ... new page + * intvalue ... pagenumber + * f_algo floatvalue ... consider footerline (only if y_algo is auto and p_algo is not 'new') + * @throws PDFDocumentException + */ + public TablePos(String pos_string) throws PDFDocumentException + { + //parse posstring and throw exception + //[x:x_algo];[y:y_algo];[w:w_algo][p:p_algo];[f:f_algo] + + String[] strs = pos_string.split(";"); + try + { + for (int cmds = 0;cmds Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignature.java,v 1.4 2006/10/31 08:12:45 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; + +import org.apache.log4j.Logger; +import org.pdfbox.pdfparser.PDFParser; +import org.pdfbox.pdmodel.PDDocument; +import org.pdfbox.util.PDFTextStripper; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.input.PdfDataSource; +import at.gv.egiz.pdfas.performance.PerformanceCounters; +import at.gv.egiz.pdfas.utils.PDFASUtils; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; + +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfImportedPage; +import com.lowagie.text.pdf.PdfReader; +import com.lowagie.text.pdf.PdfWriter; + +/** + * Contains helper function for textual signatures. + * + * @author wprinz + */ +public class TextualSignature +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(TextualSignature.class); + + /** + * Extracts the document text from a given pdf. + * + * @param pdf_stream + * The pdf_input stream. + * @return Returns the extracted document text. + * @throws PDFDocumentException + * @throws TextExtractionException + * Forwarded exception. + */ + public static String extractTextTextual(PdfDataSource pdfDataSource, String encoding) throws PDFDocumentException + { + PerformanceCounters.textExtractions.increment(); + + try + { + int first_page_rotation = 0; + // logger_.debug("===================================================="); + // logger_.debug("extractText:"); + + // For text extraction, create a temporary object with iText just as the + // one + // created + // when being signed, but of course without adding content. + + + // byte[] bytes = normalizePDF(pdf_stream); + //iText + + byte [] pdf_data = pdfDataSource.getAsByteArray(); + PdfReader reader = new PdfReader(pdf_data); + PDFASUtils.checkReaderPermissions(reader); + //pdf_stream.close(); + + // PERF: PDF normalization needs byte array - this is costy + ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); + + // For some reason the Reader -> ImportPage -> Writer mechanism produces + // problems en mass. + // The text extractor may not be able to extract proper text from + // documents + // created with + // this method (although it works when a Table is appended)... very + // fragile. + + Document document = new Document(); + + PdfWriter writer = PdfWriter.getInstance(document, baos); + document.open(); + + PdfContentByte cb = writer.getDirectContent(); + for (int page_num = 1; page_num <= reader.getNumberOfPages(); page_num++) + { + //Rectangle new_size = reader.getPageSize(page_num); + //logger_.info("PageSize with no rotaion: Pagenr:"+page_num+" Size: "+new_size); + //document.setPageSize(new_size); + Rectangle new_size_withrot =reader.getPageSizeWithRotation(page_num); + if (page_num == 1) + { + //setFirstPageRotation(new_size_withrot.getRotation()); + first_page_rotation = new_size_withrot.getRotation(); + //logger_.info("iText first_page_rotation="+new_size_withrot.getRotation()); + } + //logger_.info("iText set PageSize of page:"+page_num+" to: "+new_size_withrot); + //document.setPageSize(new_size); + document.setPageSize(new_size_withrot); + document.newPage(); + + PdfImportedPage page = writer.getImportedPage(reader, page_num); + // note that this will add an xobject form to the doc. + // the xobject form contains the content of the page. + cb.addTemplate(page, 0, 0); + + // wprinz: debugging + // cb.beginText(); + // cb.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, + // BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 14); + // cb.showText("page " + page_num); + // cb.endText(); + // wprinz: end debugging + } + + document.close(); + + // for (int i = 1; i <= reader.getNumberOfPages(); i++) + // { + // Rectangle rect = reader.getBoxSize(i, "bleed"); + // logger_.debug("rect[" + i + "] = " + rect); + // } + + baos.close(); + byte[] normalizedPDF = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(normalizedPDF); + //PDFBox-parser + PDFParser parser = new PDFParser(bais); + File temporary_dir = SettingsReader.getTemporaryDirectory(); + //logger_.info("temporary_dir="+temporary_dir.getAbsolutePath()); + parser.setTempDirectory(temporary_dir); + parser.parse(); + + PDDocument doc = parser.getPDDocument(); + //System.out.println("pdfBox.getNumberOfPages()"+doc.getNumberOfPages()); + + PDFTextStripper stripper = new PDFTextStripper(); + stripper.setSortByPosition(false); + stripper.setGetFirstPageRotationFromThis(true); + stripper.setFirstPageRotation(first_page_rotation); + + // stripper.setStartPage(4); + // stripper.setEndPage(4); + logger_.debug("TextualSignator extractTextTextual: Begin stripping text"); + String text; + try { + text = stripper.getText(doc, encoding); + } catch (Exception e) { + throw new PDFDocumentException(ErrorCode.TEXT_EXTRACTION_EXCEPTION, "Unable to extract textual content.", e); + } + logger_.debug("TextualSignator extractTextTextual: Stripping text ended"); + + doc.close(); + //logger_.debug("TextualSignator extractTextTextual="+text); + return text; + + } + catch (IllegalArgumentException e) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + catch (IOException e) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + catch (DocumentException e) + { + throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } + } + + /** + * Normalizes a given binary PDF to a version PDFbox can handle correctly. + * + *

+ * PDFbox has serious problems with documents that use incremental updates or + * XObject forms. Therefor use this to remove incremental updates and create a + * streamlined document. + *

+ * + *

+ * Note that this has nothing to do with text normalization. It just unifies + * the PDF documents that are fed into PDFbox for text extraction and page + * length determination. + *

+ * + * @param input_pdf + * The input pdf to be normalized. + * @return Returns the normalized pdf. + * @throws IOException + * @throws DocumentException + * @throws PDFDocumentException + */ + public static byte[] normalizePDF(PdfDataSource pdfDataSource) throws IOException, DocumentException, PDFDocumentException + { + //iText + byte [] pdf_data = pdfDataSource.getAsByteArray(); + PdfReader reader = new PdfReader(pdf_data); + PDFASUtils.checkReaderPermissions(reader); + //input_pdf.close(); + + // PERF: PDF Normalization needs byte array + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // For some reason the Reader -> ImportPage -> Writer mechanism produces + // problems en mass. + // The text extractor may not be able to extract proper text from + // documents + // created with + // this method (although it works when a Table is appended)... very + // fragile. + + Document document = new Document(); + + PdfWriter writer = PdfWriter.getInstance(document, baos); + document.open(); + + PdfContentByte cb = writer.getDirectContent(); + for (int page_num = 1; page_num <= reader.getNumberOfPages(); page_num++) + { + Rectangle new_size_withrot =reader.getPageSizeWithRotation(page_num); + document.setPageSize(new_size_withrot); + document.newPage(); + PdfImportedPage page = writer.getImportedPage(reader, page_num); + // note that this will add an xobject form to the doc. + // the xobject form contains the content of the page. + cb.addTemplate(page, 0, 0); + + // wprinz: debugging + // cb.beginText(); + // cb.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, + // BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 14); + // cb.showText("page " + page_num); + // cb.endText(); + // wprinz: end debugging + } + + document.close(); + + // for (int i = 1; i <= reader.getNumberOfPages(); i++) + // { + // Rectangle rect = reader.getBoxSize(i, "bleed"); + // logger_.debug("rect[" + i + "] = " + rect); + // } + + baos.close(); + byte[] normalizedPDF = baos.toByteArray(); + return normalizedPDF; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java new file mode 100644 index 0000000..165de05 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignatureHolder.java @@ -0,0 +1,153 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TextualSignatureHolder.java,v 1.1 2006/10/11 07:58:17 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.framework.input.TextDataSource; +import at.gv.egiz.pdfas.impl.input.TextDataSourceImpl; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; + +/** + * Data structure that holds the information of one signature block, which is + * the signed/signable text and the corresponding SignatureObject. + * + * @author wprinz + */ +public class TextualSignatureHolder implements Serializable, SignatureHolder +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7208103904479272760L; + +// /** +// * The signed text of this object. +// * +// *

+// * This is the value that will be signed by the Connector. +// *

+// */ +// private String signed_text = null; + + /** + * The signature object. + */ + private SignatureObject signature_object = null; + + private TextDataSource textDataSource = null; + + private int uiBlockEndPos = 0; + + public TextualSignatureHolder(String text, SignatureObject so) + { + //this.signed_text = text; + this.signature_object = so; + this.textDataSource = new TextDataSourceImpl(text); + } + + public TextualSignatureHolder(TextDataSource text, SignatureObject so) + { + //this.signed_text = text; + this.signature_object = so; + this.textDataSource = text; + } + +// /** +// * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignedText() +// */ +// public String getSignedText() +// { +// return this.signed_text; +// } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getSignatureObject() + */ + public SignatureObject getSignatureObject() + { + return this.signature_object; + } + + /** + * @see at.knowcenter.wag.egov.egiz.pdf.SignatureHolder#getDataSource() + */ + public DataSource getDataSource() + { + return this.textDataSource; + } + + /** + * This is used to replace the DataSource. + * + *

+ * After processing the text, data sources containing large texts are usually replaced by a FileBased ones to save memory. + *

+ * + * @param tds + */ + public void exchangeDataSource(TextDataSource tds) + { + this.textDataSource = tds; + } + + /** + * This is just a shortcut to getDataSource().getText() + * @return Returns the text of this data source. + */ + public String getSignedText() + { + return this.textDataSource.getText(); + } + + public int getUiBlockEndPos() { + return this.uiBlockEndPos; + } + + public void setUiBlockEndPos(int uiBlockEndPos) { + this.uiBlockEndPos = uiBlockEndPos; + } + + public static void mulitSetUiBlockEndPos(List signatureHolders, int uiBlockEndPos) { + for (Iterator it = signatureHolders.iterator(); it.hasNext();) { + SignatureHolder sh = (SignatureHolder) it.next(); + trySetUiBlockEndPos(sh, uiBlockEndPos); + } + } + + public static void trySetUiBlockEndPos(SignatureHolder sh, int uiBlockEndPos ) { + if (sh != null && sh instanceof TextualSignatureHolder) { + ((TextualSignatureHolder)sh).setUiBlockEndPos(uiBlockEndPos); + } + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java new file mode 100644 index 0000000..519d0b5 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/Utils.java @@ -0,0 +1,124 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Utils.java,v 1.3 2006/10/31 08:13:02 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.pdf; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Abstract class that contains helpful utility functions used by the digital + * signatures. + * + * @author wprinz + */ +public abstract class Utils +{ + + /** + * Extracts the pure content text from a given content stream. + * + *

+ * The pure content text is just an assembly of all strings that occur within the content stream in + * stream order. + * Each of these strings will be set on a new line. + *

+ * + * @param stream_bytes The content stream. + * @return Returns the extracted string. + * @throws IOException Forwarded exception. + */ + public static String extractPureTextFromContentStream( + final byte[] stream_bytes) throws IOException + { + + // logger_.debug("stream_bytes:"); + // logger_.debug(new String(stream_bytes, "US-ASCII")); + // logger_.debug(":end of stream_bytes"); + + final byte OPEN = '('; + final byte CLOSE = ')'; + + StringWriter strwrtr = new StringWriter(); + PrintWriter printer = new PrintWriter(strwrtr); + int open_index = -1; + int close_index = -1; + for (int i = 0; i < stream_bytes.length; i++) + { + if (stream_bytes[i] == OPEN) + { + open_index = i; + continue; + } + if (stream_bytes[i] == CLOSE) + { + close_index = i; + + // logger_.debug("open = " + open_index + ", close = " + + // close_index); + + int len = close_index - open_index - 1; + // logger_.debug("len = " + len); + + byte[] bytes = new byte[len]; + System.arraycopy(stream_bytes, open_index + 1, bytes, 0, len); + + String str = new String(bytes, "ISO-8859-1"); + // logger_.debug("string = " + str); + + printer.println(str); + + continue; + } + } + strwrtr.close(); + String signature_text = new String(strwrtr.getBuffer()); + // logger_.debug(signature_text); + + return signature_text; + } + + public static int max(int[] ints) { + int max = Integer.MIN_VALUE; + for (int i = 0; i < ints.length; i++) { + if (ints[i] > max) { + max = ints[i]; + } + } + return max; + } + + public static String resolveCanonical(String path) { + File file = new File(path); + try { + return file.getCanonicalPath(); + } catch (IOException e) { + return file.getPath(); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java new file mode 100644 index 0000000..f70f19c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java @@ -0,0 +1,67 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Connector.java,v 1.3 2006/10/11 07:54:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * The basic interface for all connectors. + * + * @author wprinz + */ +public interface Connector +{ + + /** + * Performs a sign. + * + * @param sig_type + * The signature type/profile. + * @param user_name + * The user name for user logging. + * @param text_to_sign + * The text to be signed. + * @return Returns the signed SignatureObject. + * @throws SignatureException + * F.e. + */ + public SignatureObject doSign(String sig_type, String user_name, + String text_to_sign) throws SignatureException; + + /** + * Performs a verify. + * + * @param signed_text + * The signed text to be verified. + * @param sig_obj + * The Signature object. + * @return Returns the SignatureResponse. + * @throws SignatureException + * F.e. + */ + public SignatureResponse doVerify(String signed_text, SignatureObject sig_obj) throws SignatureException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java new file mode 100644 index 0000000..fa019b9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java @@ -0,0 +1,372 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ConnectorFactory.java,v 1.4 2006/10/31 08:18:12 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.lang.reflect.Field; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.connectors.A1Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorConfigurationKeys; +import at.knowcenter.wag.egov.egiz.sig.connectors.MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; + +/** + * This is a factory for creating the appropriate connector according to the + * connector identifier. + * + * @deprecated this code is far too complicated + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorInformation + * @author wprinz + */ +public abstract class ConnectorFactory +{ + /** + * The name of the field that holds the Connector implementation's unique + * identifier. + * + *

+ * This must be a public static final String on the Connector implementation + * class. + *

+ */ + protected static final String CONNECTOR_INFORMATION_FIELD_NAME = "CONNECTOR_INFORMATION"; + + /** + * The list of available Connector implementations. + * + *

+ * Note that this could also be generated dynamically from a config file, + * preferably enveloped by a Singleton. + *

+ */ + protected static Class[] AVAILABLE_CONNECTORS = { MOAConnector.class, + BKUConnector.class, A1Connector.class }; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(ConnectorFactory.class); + + + + /** + * Retrieves the ConnectorInformation from the connector Class. + * + * @param connector_class + * The connector Class. + * @return Returns the ConnectorInformation. + * @throws IllegalArgumentException + * F.e. + * @throws IllegalAccessException + * F.e. + * @throws SecurityException + * F.e. + * @throws NoSuchFieldException + * F.e. + */ + protected static ConnectorInformation getConnectorInformationFromClass( + Class connector_class) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException + { + Field type_field = connector_class.getField(CONNECTOR_INFORMATION_FIELD_NAME); + ConnectorInformation connector_information = (ConnectorInformation) type_field.get(null); + return connector_information; + } + + /** + * Gathers the ConnectorInformation objects of all registered connectors. + * + *

+ * This is used by the user interface to provide a list of all available + * connectors. + *

+ * + * @return Returns the ConnectorInformation objects. + * @throws ConnectorFactoryException + * F.e. + */ + public static ConnectorInformation[] getConnectorInformationArray() throws ConnectorFactoryException + { + ConnectorInformation[] coninf = new ConnectorInformation[AVAILABLE_CONNECTORS.length]; + + for (int i = 0; i < coninf.length; i++) + { + try + { + coninf[i] = getConnectorInformationFromClass(AVAILABLE_CONNECTORS[i]); + } + catch (Exception e) + { + throw new ConnectorFactoryException(e); + } + } + + return coninf; + } + + /** + * Retrieves the connector Class belonging to the connector id. + * + * @param connector_identifier + * The connector id. + * @return Returns the corresponding connector class. + * @throws ConnectorFactoryException + * Thrown, if the id is invalid. + */ + protected static Class getConnectorClass(String connector_identifier) throws ConnectorFactoryException + { + ConnectorInformation[] conids = getConnectorInformationArray(); + for (int i = 0; i < conids.length; i++) + { + String connector_id = conids[i].getIdentifier(); + + if (connector_id.equals(connector_identifier)) + { + Class conn_class = AVAILABLE_CONNECTORS[i]; + + return conn_class; + } + } + + throw new ConnectorFactoryException("The connector '" + connector_identifier + "' couldn't be found in the list of available connectors."); + } + + /** + * Creates a new connector given by the connector_identifier. + * + * @param connector_identifier + * The connector identifier of the new connector. + * @return Returns the new connector. + * @throws ConnectorFactoryException + * F.e. + */ + public static Connector createConnector(String connector_identifier) throws ConnectorFactoryException + { + + Class conn_class = getConnectorClass(connector_identifier); + + try + { + Connector connector_obj = (Connector) conn_class.newInstance(); + return connector_obj; + } + catch (Exception e) + { + throw new ConnectorFactoryException(e); + } + } + + /** + * Tells, if the given connector identifier is valid. + * + * @param connector_identifier + * The connector identifier. + * @return Returns true, if the identifier is valid, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isValidConnectorIdentifier(String connector_identifier) throws ConnectorFactoryException + { + ConnectorInformation[] conids = getConnectorInformationArray(); + for (int i = 0; i < conids.length; i++) + { + if (conids[i].getIdentifier().equals(connector_identifier)) + { + return true; + } + } + return false; + } + + /** + * Retrieves the availability of the connector from the flags specified in the + * config file. + * + * @param connector_identifier + * The connector. + * @param availability_key + * The key of the availability flag to be retrieved. + * @param default_value + * The default value to be used if the flag is not set in the config + * file. + * @return Returns true, if the flag was set to true, false, if the flag was + * set otherwise, or the default_value if the flag wasn't set at all. + * @throws ConnectorFactoryException + * Thrown, if the connector is invalid. + */ + protected static boolean getAvailabilityUsingDefault(String connector_identifier, + String availability_key, boolean default_value) throws ConnectorFactoryException + { + if (!isValidConnectorIdentifier(connector_identifier)) + { + throw new ConnectorFactoryException("The connector '" + connector_identifier + "' couldn't be found in the list of available connectors."); + } + + SettingsReader settings_ = null; + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new RuntimeException(e); + } + + String value = settings_.getValueFromKey(connector_identifier + "." + availability_key); + if (value == null) + { + return default_value; + } + return value.equals("true"); + } + + /** + * Tells, if the connector is available for being used in the Commandline + * (synchron) environment. + * + *

+ * A connector is available for commandline processing if it requires no + * active user interaction for being executed or if it handles the user + * interaction itself. + *

+ *

+ * A commandline connector is executed synchronously. The client waits until + * the Connector has finished. + *

+ *

+ * Usually a synchron connector can also be used in a web environment. + *

+ *

+ * Examples for commandline connectors are: MOA, BKU. A1 is not suitible for + * commandline because it requires HTTP/HTML interaction, log in, etc. + *

+ * + * @return Returns true, if the Connector is available for Commandline + * processing. + */ + public static boolean isAvailableForCommandline(String connector_identifier) throws ConnectorFactoryException + { + return getAvailabilityUsingDefault(connector_identifier, ConnectorConfigurationKeys.AVAILABLE_FOR_COMMANDLINE, false); + } + + /** + * Tells, if the Connector is available for being used in a Web (asynchron, + * local) environment. + * + *

+ * A connector is available for Web if it can be used in a web environment. + * Often a web connector is also a local connector. + *

+ *

+ * Typical examples are the local BKU and A1. The later requires HTML log in + * and session handling. + *

+ * + * @return Returns true, if the Connector is available for the Web + * application. + */ + public static boolean isAvailableForWeb(String connector_identifier) throws ConnectorFactoryException + { + return getAvailabilityUsingDefault(connector_identifier, ConnectorConfigurationKeys.AVAILABLE_FOR_WEB, false); + } + + /** + * Tells, if the given connector is local. + * + * @param connector_identifier + * The connector. + * @return Returns true, if the given connector is local, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isConnectorLocal(String connector_identifier) throws ConnectorFactoryException + { + return connector_identifier.equals(Constants.SIGNATURE_DEVICE_BKU) || connector_identifier.equals(Constants.SIGNATURE_DEVICE_A1) || connector_identifier.equals(Constants.SIGNATURE_DEVICE_MOC); + } + + /** + * Key value in property file + */ + // dferbas: not used anymore with dynamic algorithm support. + // field has to be showed/embedded except for default algorithm suites + // use signature block layout to show/hide + //public static final String MOA_ID_VISIBLE_PROPERTY_KEY = "moa.id.field.visible"; + + // dferbas: not used anymore +// /** +// * Tells, if the given connector needs or produces SIG_IDs. +// * +// *

+// * This method is used when pre formatted signature blocks have to be created +// * that have to know if there will be a SIG_ID field or not. +// *

+// *

+// * Connectors like BKU produce SIG_IDs when signing that are needed when +// * verifying. +// *

+// * +// * @param connector +// * The connector. +// * @return Returns true, if the given connector uses SIG_IDs, false otherwise. +// */ +// public static boolean needsSIG_ID(String connector) +// { +// // all modernn detached signatures have the SIG_ID field. +// if(connector.equals("moa")) +// { +// String is_id_field_visible = null; +// +// try +// { +// is_id_field_visible = SettingsReader.getInstance().getValueFromKey(MOA_ID_VISIBLE_PROPERTY_KEY); +// } catch (SettingsException e) +// { +// logger_.error(e.getMessage(), e); +// } +// +// // if not setted in config, show it +// if(is_id_field_visible == null) +// return true; +// if(is_id_field_visible.equals("true")) +// return true; +// else +// return false; +// } +// +// return true; +// //return !connector.equals("moa"); +// } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java new file mode 100644 index 0000000..efd6c53 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java @@ -0,0 +1,97 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ConnectorInformation.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * Holds the information of one connectior. + * + *

+ * An implementation of the Connector interface must provide a public static + * final ConnectorInformation field named + * ConnectorFactory#CONNECTOR_INFORMATION_FIELD_NAME that provides the + * information about this connector to the system. + *

+ * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * + * @author wprinz + */ +public class ConnectorInformation implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 5692836392376853268L; + + /** + * The short identifier of the connector (e.g. "bku"). + */ + protected String connector_identifiert = null; + + /** + * The user suitable description of the connector (e.g. + * "Bürgerkartenumgebung"). + */ + protected String connector_description = null; + + /** + * Constructor that initializes this object. + * + * @param identifier + * The short identifier of the connector (e.g. "bku"). + * @param description + * The user suitable description of the connector (e.g. + * "Bürgerkartenumgebung"). + */ + public ConnectorInformation(String identifier, String description) + { + this.connector_identifiert = identifier; + this.connector_description = description; + } + + /** + * Returns the identifier of this connector. + * + * @return Returns the identifier of this connector. + */ + public String getIdentifier() + { + return this.connector_identifiert; + } + + /** + * Returns the description if this connector. + * + * @return Returns the description if this connector. + */ + public String getDescription() + { + return this.connector_description; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java new file mode 100644 index 0000000..d15f1a9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java @@ -0,0 +1,100 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: DummyLDAPAPI.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; + +/** + * This is just a dummy implementation until the real Egiz LDAP API is + * implemented. + * + * @author wprinz + * @author modified by Thomas Knall + * @deprecated Use {@link at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIFactory#createLDAPAPI()} instead. + */ +public class DummyLDAPAPI implements LDAPAPI +{ + String url_ = null; + + /** + * The Logger. + */ + protected static Log logger = LogFactory.getLog(DummyLDAPAPI.class); + + public DummyLDAPAPI(String url) + { + this.url_ = url; + } + + /* (non-Javadoc) + * @see at.knowcenter.wag.egov.egiz.sig.LDAPAPI#getURL(String) + */ + public String getURL(String issuer) + { + return this.url_; + } + + /* (non-Javadoc) + * @see at.knowcenter.wag.egov.egiz.sig.LDAPAPI#loadCertificateFromLDAP(java.lang.String, java.lang.String) + */ +public byte[] loadBase64CertificateFromLDAP(String serial_number, String issuer) + { + //System.out.println("LDAP: serial_number = " + serial_number); + //System.out.println("LDAP: issuer = " + issuer); + + byte[] data = null; + if (serial_number.equals("153868") && issuer.equals("CN=a-sign-TEST-Premium-Sig-01,OU=a-sign-TEST-Premium-Sig-01,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT")) + { + try + { + File test_file = new File(SettingsReader.CERT_PATH + File.separator + "ldap_test_cert.der"); + data = new byte[(int) test_file.length()]; + FileInputStream fis = new FileInputStream(test_file); + fis.read(data); + fis.close(); + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + data = null; + } + } + + return data; + } + + public void setIssuerNameFilter(LDAPIssuerNameFilter filter) throws LDAPAPIException { + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java new file mode 100644 index 0000000..4269e28 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java @@ -0,0 +1,50 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig; + +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; + +/** + * @author Thomas Knall + */ +public interface LDAPAPI { + + public static final String SYS_PROP_IMPLEMENTATION = "pdfas.ldapapi.impl"; + + /** + * Retrieves an certificate from the ldap server identified by serial number and issuer name. + * @param serialNumber The serial number. + * @param issuer The issuer name. + * @return BASE64 encoded certificate + */ + public byte[] loadBase64CertificateFromLDAP(String serialNumber, String issuer); + + /** + * Sets the filter that has to be applied before trying to match the issuer name. + * @param filter The filter. + */ + public void setIssuerNameFilter(LDAPIssuerNameFilter filter) throws LDAPAPIException; + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java new file mode 100644 index 0000000..1c254e2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java @@ -0,0 +1,127 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: LocalConnector.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.Properties; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * A local connector is a refinement of a "normal" Connector that allows to + * explicitely do the request on a local client. + * + *

+ * Basically the sign and verify procedures of this connector are split into + * three groups: + *

+ *
    + *
  1. Prepare the request to the local service.
  2. + *
  3. Carry out the request on the local client.
  4. + *
  5. Analyze the response from the local client.
  6. + *
+ *

+ * Usually the preparation and the analyzation are carried out on the server, + * whereas the connection to the local service is made from the local client. + *

+ * + * @deprecated use the new connectory instead + * + * @author wprinz + */ +public interface LocalConnector extends Connector +{ + /** + * Prepares the sign request string. + * + * @param user_name + * The user name. + * @param sign_text + * The text to be signed. + * @param signature_type + * The type of the signature. + * @return Returns the request string to be sent to the local service. + * @throws SignatureException + * F.e. + */ + public String prepareSignRequest(String user_name, String sign_text, + String signature_type) throws SignatureException; + + /** + * Prepares the verify request string. + * + * @param signed_text + * The signed text to be verified. + * @param signature_object + * The SignatureObject. + * @return Returns the request string. + * @throws SignatureException + * F.e. + */ + public String prepareVerifyRequest(String signed_text, + SignatureObject signature_object) throws SignatureException; + + /** + * Analyzes the sign response string. + * + * @param signature_type + * The type of the signature. + * @return Returns the SignatureObject of the sign request. + * @throws SignatureException + * F.e. + */ + // TODO hotfix - already deprecated + public SignatureObject analyzeSignResponse(Properties response_properties, + String signature_type) throws SignatureException; + + /** + * Analyzes the verify response string. + * + * @return Returns the SignatureResponse of the verify request. + * @throws SignatureException + * F.e. + */ + // TODO hotfix - already deprecated + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException; + + /** + * Returns the sign URL of the local service. + * + * @param profile + * The signature type the URL should be retrieved from. + * @return Returns the sign URL of the local service. + */ + public String getSignURL(String profile); + + /** + * Returns the verify URL of the local service. + * + * @param profile + * The signature type the URL should be retrieved from. + * @return Returns the verify URL of the local service. + */ + public String getVerifyURL(String profile); + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java new file mode 100644 index 0000000..c9e3b98 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java @@ -0,0 +1,316 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureBlock.java,v 1.4 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * This method is to analyse a signature block string. It searches for + * configured signature types while compairing defined key words with the text. + * + * @deprecated Use AbsoluteTextSignature instead. + * + * @author wlackner + */ +public class SignatureBlock +{ + + /** + * Start index of the signature block text. + */ + private int startIndex_ = -1; + + /** + * End index of the signature block text. + */ + private int endIndex_ = -1; + + /** + * The type of the signature block. + */ + private String type_ = null; + + /** + * The signature type definition object. + */ + private SignatureTypeDefinition sigTypeDef_ = null; + + /** + * The signature block string. + */ + private String signatureString_ = null; + + /** + * The signature object build by the signature string using the signture + * definition. + */ + private SignatureObject signatureObject_ = null; + + /** + * A list of configured signature types. + */ + List signatureTypes_ = null; + + /** + * A list of found keys in the signature block string. + */ + Map foundKeys_ = new HashMap(); + + int maxSize_ = -1; + + /** + * The default constructor to analyse a signature block string. It uses a + * predefined signature type list to assign the text block to signature type. + * The analyse method have to be call separately --> + * separateBlockFromRawText() + * + * @param signatureTypes + */ + public SignatureBlock(List signatureTypes) + { + signatureTypes_ = signatureTypes; + } + + /** + * This method checks if all required keys are found in the signature block + * string. + * + * @param foundKeys + * the keys that are found in the singnature block string + * @return true if all required keys are found, false otherwise + */ + private boolean checkRequiredFields(Map foundKeys) + { + String[] req_keys = SignatureTypes.REQUIRED_SIG_KEYS; + for (int req_idx = 0; req_idx < req_keys.length; req_idx++) + { + String key = req_keys[req_idx]; + // SIG_ID could be optional --> only set in BKU signed documents + if (key.equals(SignatureTypes.SIG_ID)) + { + continue; + } + // logger.debug("check:" + key + "=" + foundKeys.get(key)); + if (foundKeys.get(key) == null) + { + return false; + } + } + return true; + } + + /** + * This method is the base method to analyse a raw text separating a signature + * block string from the raw text. It searches for corresponding signature + * types from back to front in the raw text. Therefore a revert list of + * multiple signations can be extracted calling this method more than one + * times. The method extracts the start and end postition of a found signature + * block and extracts all keys used in that block. If all required fields are + * found a successful separation is done and can be access calling the method + * getStartIndex, getEndIndex, getType, getSignatureObject. + * + * @param rawText + * the raw text to separate a signature block from + * @return true if a separation has done successful false if no signature + * block can be found + */ + public boolean separateBlockFromRawText(String rawText, boolean old_style) + { + endIndex_ = rawText.length(); + boolean found_type = false; + for (int sig_type_idx = 0; sig_type_idx < signatureTypes_.size(); sig_type_idx++) + { + int last_index = endIndex_; + SignatureTypeDefinition sig_type_def = (SignatureTypeDefinition) signatureTypes_.get(sig_type_idx); + //logger.debug("Try sep type:" + sig_type_def.getType()); + + Vector keys = sig_type_def.getRevertSortedKeys(); + Vector captions = sig_type_def.getRevertSortedCaptions(); + Map found_keys = new HashMap(); + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String key = (String) keys.get(key_idx); + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + // If separating the old style way - skip The "Kennzeichnung" + // key, because it wasn't present in old profiles. + continue; + } + String caption = (String) captions.get(key_idx); + int found_idx = rawText.lastIndexOf(caption); + //logger.debug("Try find:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + if (found_idx >= 0 && found_idx < last_index) + { + if (key.equals(SignatureTypes.SIG_ID)) + { + //logger.debug("store SIG_ID, but don't decrease last index:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + found_keys.put(key, new Integer(found_idx)); + // don't decrease last index as SIG_ID is not necessarily persistent + } + else + { + //logger.debug("store:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + found_keys.put(key, new Integer(found_idx)); + last_index = found_idx; + } + } + } + if (checkRequiredFields(found_keys) && found_keys.size() > maxSize_) + { + foundKeys_ = found_keys; + sigTypeDef_ = sig_type_def; + type_ = sig_type_def.getType(); + startIndex_ = last_index; + signatureString_ = rawText.substring(startIndex_, endIndex_); + maxSize_ = found_keys.size(); + found_type = true; + } + } + return found_type; + } + + /** + * @return Returns the endIndex. + */ + public int getEndIndex() + { + return endIndex_; + } + + /** + * @return Returns the signatureObject of the separated signature block. + * @throws SignatureException + */ + public SignatureObject getSignatureObject() throws SignatureException + { + if (signatureObject_ == null && foundKeys_ != null) + { + signatureObject_ = new SignatureObject(); + try + { + signatureObject_.setSigType(type_); + signatureObject_.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(101, "Can ot set signation type:" + type_, e); + throw se; + } + String sig_text = signatureString_; + Vector revert_keys = sigTypeDef_.getRevertSortedKeys(); + Vector revert_captions = sigTypeDef_.getRevertSortedCaptions(); + for (int key_idx = 0; key_idx < revert_keys.size(); key_idx++) + { + String key = (String) revert_keys.get(key_idx); + String caption = (String) revert_captions.get(key_idx); + int start_idx = sig_text.lastIndexOf(caption); + if (start_idx >= 0) + { + int sep_idx = start_idx + caption.length(); + // logger.debug(sig_text); + // logger.debug("caption:" + caption + " start_idx:" + start_idx + // + " length:" + + // sig_text.length()); + String value = sig_text.substring(sep_idx); + // logger.debug("key:" + key + " value:" + value); + signatureObject_.setSigValueCaption(key, value, caption); + sig_text = sig_text.substring(0, start_idx); + } + } + } + return signatureObject_; + } + + /** + * @return Returns the startIndex. + */ + public int getStartIndex() + { + return startIndex_; + } + + /** + * @return Returns the type. + */ + public String getType() + { + return type_; + } + +// /** +// * @param endIndex +// * The endIndex to set. +// */ +// private void setEndIndex(int endIndex) +// { +// endIndex_ = endIndex; +// } +// +// /** +// * @param startIndex +// * The startIndex to set. +// */ +// private void setStartIndex(int startIndex) +// { +// startIndex_ = startIndex; +// } +// +// /** +// * @param type +// * The type to set. +// */ +// private void setType(String type) +// { +// type_ = type; +// } + + /** + * The standard toString method. Used for interal tests only. + */ + public String toString() + { + String strg = ""; + strg += "Type:" + type_ + "\n"; + strg += "Start index:" + startIndex_ + "\n"; + strg += "End index:" + endIndex_ + "\n"; + strg += signatureString_ + "\n"; + strg += sigTypeDef_ + "\n"; + try + { + strg += getSignatureObject().toString(); + } + catch (SignatureException e) + { + } + return strg; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java new file mode 100644 index 0000000..18f4fe8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig; + +import at.gv.egiz.pdfas.framework.input.DataSource; + +/** + * This encapsuilates the content data to be signed or verified. + * + *

+ * For a text signature this would be the text to be signed or verified. For a + * binary signature this would be the PDF to be signed or verified. + *

+ * + *

+ * This is an abstract reprsenation of data: the binary data, its mime type and + * (if appropriate according to the mime type) the charset the data is encoded. + *

+ * + * @author wprinz + */ +public interface SignatureData +{ + /** + * Returns the DataSource that provides the data for this SignatureData. + * + * @return Returns the DataSource. + */ + public DataSource getDataSource(); + + /** + * Returns the mime type of the data. + * + *

+ * E.g. "text/plain" for text data or "application/pdf" for a PDF. + *

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

+ * This is only appropriate if the mime type suggests that the data contained + * in here is textually encoded. Usually text/plain or similar data types will + * have a character encoding present. + *

+ *

+ * If no character encoding is present, null is returned here. + *

+ *

+ * E.g. "UTF-8" is the most common encoding for textual data. + *

+ * + * @return Returns the character encoding (charset) of the data if + * appropriate. + */ + public String getCharacterEncoding(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java new file mode 100644 index 0000000..cbd2408 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java @@ -0,0 +1,130 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.framework.input.DataSource; + +/** + * Generic implementation of the SignatureData interface for being used by + * signators and verificators. + * + * @author wprinz + */ +public class SignatureDataImpl implements SignatureData, Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -8652845539968684408L; + + /** + * The signature data. + */ + protected DataSource data = null; + + /** + * The mime type of the data. + */ + protected String mimeType = null; + + /** + * The character encoding of the data if appropriate, or null if not. + */ + protected String characterEncoding = null; + + /** + * Constructor that fills the SignatureData. + * + *

+ * The charactor encoding is set to null, so this constructor is primarily for + * signature data that has no character encoding (e.g. binary data). + *

+ * + * @param data + * The signature data. + * @param mime_type + * The mime type of the data. + */ + public SignatureDataImpl(DataSource data, String mime_type) + { + this.data = data; + this.mimeType = mime_type; + this.characterEncoding = null; + } + +// /** +// * Constructor that fills the SignatureData. +// * +// *

+// * Use this constructor for textual data as it allows to provide the character +// * encoding. +// *

+// * +// * @param data +// * The signature data. +// * @param mime_type +// * The mime type of the data. +// * @param character_encoding +// * The character encoding of the data if appropriate, or null if not. +// */ +// public SignatureDataImpl(byte[] data, String mime_type, String character_encoding) +// { +// this.data = data; +// this.mimeType = mime_type; +// this.characterEncoding = character_encoding; +// } + public SignatureDataImpl(DataSource data, String mime_type, String character_encoding) + { + this.data = data; + this.mimeType = mime_type; + this.characterEncoding = character_encoding; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.SignatureData#getDataSource() + */ + public DataSource getDataSource() + { + return this.data; + } + + + /** + * @see at.knowcenter.wag.egov.egiz.sig.SignatureData#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.SignatureData#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java new file mode 100644 index 0000000..078f80f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java @@ -0,0 +1,163 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureEntry.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * This class is to store a signature entry. The signature entry is 3-tupel. A key that is defined + * or declarated in the settings file, an optional caption or a value.
+ * An additional helper value is a marker for the start index of the key, if the key is found in an + * analysing process extracting captions and values from a raw signature text. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject + */ +public class SignatureEntry implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = 4640380069301731879L; + + /** + * The signature key. + */ + private String key_ = null; + /** + * The signature caption for the key found or set in the signature text. + */ + private String caption_ = null; + /** + * The signature value for the key found or set in the signature text. + */ + private String value_ = null; + /** + * The starting index position of the key if it is found in the signature text. + */ + private int startIndex_ = -1; + + public boolean isPlaceholder = false; + + /** + * The empty constructor. + */ + public SignatureEntry() { + } + + /** + * A new SignatureEntry init with the key. + * + * @param key + */ + public SignatureEntry(String key) { + key_ = key; + } + + /** + * Returns the caption off the current key. + * + * @return Returns the caption. + */ + public String getCaption() { + return caption_; + } + + /** + * Set the caption of the current key. + * + * @param caption The caption to set. + */ + public void setCaption(String caption) { + caption_ = caption; + } + + /** + * Return the current key. + * + * @return Returns the key. + */ + public String getKey() { + return key_; + } + + /** + * Set the current key. + * + * @param key The key to set. + */ + public void setKey(String key) { + key_ = key; + } + + /** + * Return the start position of the key that caption is found in the signature text. + * + * @return Returns the startIndex. + */ + public int getStartIndex() { + return startIndex_; + } + + /** + * Set the start position of the current key. + * + * @param startIndex The startIndex to set. + */ + public void setStartIndex(int startIndex) { + startIndex_ = startIndex; + } + + /** + * Return the value of the current key. + * + * @return Returns the value. + */ + public String getValue() { + return value_; + } + + /** + * Set the value of the current key. + * + * @param value The value to set. + */ + public void setValue(String value) { + value_ = value; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + String the_string = ""; + the_string += "\n Key:" + key_; + the_string += "\nCaption:" + caption_; + the_string += "\n Value:" + value_; +// the_string += "\nStart I:" + startIndex_; + return the_string; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java new file mode 100644 index 0000000..3c16599 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java @@ -0,0 +1,88 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureFieldDefinition.java,v 1.1 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * This class contains the information about one field in the signature block. + * + *

+ * E.g. Field "Issuer" could have the caption "Aussteller", the value null and + * the placeholder length of 500. + *

+ * + * @author wprinz + */ +public class SignatureFieldDefinition implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -46020173047777315L; + + /** + * The key identifier of this field. + */ + public String field_name = null; + + /** + * The static caption of the field. + */ + public String caption = null; + + /** + * The static value of the field. + * + *

+ * Null means that this field has no static value and must be filled out. + *

+ */ + public String value = null; + + /** + * If the field is not static and has to be filled out, this gives the + * length of the placeholder that is reserved for filling out. + * + *

+ * This has to be large enough so that it can hold the whole value to be + * filled out. + *

+ */ + public int placeholder_length = -1; + + /** + * Stores the three byte abbreviation code of this field's field name. + */ + //public byte [] brev = null; + + public String toString() + { + return this.field_name + ": caption=" + this.caption + ", value=" + this.value + ", phlen=" + this.placeholder_length; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java new file mode 100644 index 0000000..8855b86 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java @@ -0,0 +1,2108 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureObject.java,v 1.7 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import iaik.asn1.structures.Name; +import iaik.asn1.structures.RDN; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIFactory; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.table.Entry; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.egov.egiz.table.Table; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; + +/** + * This class represents the abstract signature object. It contains all methods + * reading the definitions from the settings file, analyse them and build the + * abstract signature table.
+ * All values that build or used by the signation creation process, call the + * external services, can read or set separately. All other values are defined + * in the settings file. + * + * @author wlackner + * @author modified by Thomas Knall + */ +public class SignatureObject implements Serializable +{ + +// 03.11.2010 changed by exthex - added default for defaultValueStyle_.hAlign since we had to remove the hardcoded default in Style +// 04.11.2010 changed by exthex - setSigValue no longer removes multiple newlines from value + + /** + * SVUID. + */ + private static final long serialVersionUID = -3535189232362254713L; + + /** + * The system file separator char + */ + private static final String FILE_SEP = System.getProperty("file.separator"); + + /** + * The certificate extension + */ + private static final String CERT_FILE_EXTENSION = ".der"; + + /** + * certificate import dir + */ + private static final String CERT_ADD_DIR = "tobeadded"; + + /** + * The default style definition for images. + */ + private Style defaultImageStyle_ = new Style(); + + /** + * The default style definition for captions. + */ + private Style defaultCaptionStyle_ = new Style(); + + /** + * The default style definition for values. + */ + private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * Standard key get/set the certification value + */ + public static final String SIG_CER = "SIG_CER"; + + /** + * Standard key get/set the certification digest value + */ + public static final String SIG_CER_DIG = "SIG_CER_DIG"; + + private X509Cert x509Cert_ = null; + + private String timeStamp = null; + + // public static final String SIG_RES = "SIG_RES"; + // dummy value for debugging only + private String sigResponse_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureObject.class); + + /** + * The normalizer reference + */ + private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + /** + * The current signature type used reading and analysing the property tree + */ + private String sigType_ = null; + + /** + * Reference from signature key to there corresponding value + */ + private Hashtable sigEntries_ = new Hashtable(8); + + /** + * The abstract table representation + */ + private Table sigTable_ = null; + + // private HashMap sigIndexMap_ = new HashMap(); + + /** + * Path value storing and fetching the certificates + */ + private String certPath_ = null; + + /** + * the signature definition object + */ + private SignatureTypeDefinition signatureDefinition_ = null; + + /** + * The raw xml response from the connector that was used to set the values in + * this SignatureObject. + * + *

+ * This is set by the Connector so that signing Applications can use the + * returned XML values. + *

+ */ + protected String raw_signature_response = null; + + /** + * Filters the issuer name in order to find matches. + * @author tknall + * @see #normalizeIssuer + */ + private LDAPIssuerNameFilter issuerNameFilter = new LDAPIssuerNameFilter() { + public Name applyFilter(Name name) { + RFC2253NameParser parser = new RFC2253NameParser(normalizeIssuer(name.getName())); + try { + name = parser.parse(); + } catch (RFC2253NameParserException e) { + logger_.error(e.getMessage(), e); + } + return name; + } + }; + + /** + * The empty constructor. It initilize the normlizer, load the settings and + * set the default styles. + * + * @throws SignatureException + * ErrorCode:101, 400 + */ + public SignatureObject() throws SignatureException + { + initNormalizer(); + loadSettings(); + setDefaultStyles(); + } + + /** + * This method initialize the normalizer + * + * @throws SignatureException + * ErrorCode:400 + */ + private void initNormalizer() throws SignatureException + { + try + { + normalizer_ = new Normalizer(); + } + catch (NormalizeException e) + { + SignatureException se = new SignatureException(400, "Normalizer can not be initialized", e); + throw se; + } + } + + /** + * This method load the signature definitions + * + * @throws SignatureException + * ErrorCode:101 + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + // pTree_ = settings_.getPTree(); + + certPath_ = SettingsReader.CERT_PATH; + } + + /** + * This method set the default styles for images, captions and values. + */ + private void setDefaultStyles() + { + defaultImageStyle_.setPadding(3); + defaultImageStyle_.setHAlign(Style.CENTER); + defaultImageStyle_.setVAlign(Style.MIDDLE); + + defaultCaptionStyle_.setHAlign(Style.CENTER); + defaultCaptionStyle_.setVAlign(Style.MIDDLE); + + defaultValueStyle_.setHAlign(Style.LEFT); + defaultValueStyle_.setVAlign(Style.MIDDLE); + } + + /** + * Dummy getter Method for debugging only + * + * @return response string + */ + public String getSigResponse() + { + return sigResponse_; + } + + /** + * Dummy setter Method for debugging only + * + * @param sigRespone + * store the response string + */ + public void setSigResponse(String sigRespone) + { + sigResponse_ = sigRespone; + } + + /** + * This method set the signature type. + * + * @param sigType + * the signature type to be set + * @throws SignatureTypesException + */ + public void setSigType(String sigType) throws SignatureTypesException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + sigType_ = sigType; + } + + /** + * Returns the default signation type + * + * @return the key for the default signature definition, if the key is not + * found it returns null + */ + private String getDefaultSigType() + { + return settings_.getSetting(SignatureTypes.DEFAULT_TYPE, null); + } + + /** + * This method checks if a given signature key is realy a defined signature + * key. + * + * @param sigKey + * the key to check + * @return true if the key is correct, false if the given key is not defined + */ + public boolean isSigKey(String sigKey) + { + return signatureDefinition_.contains(sigKey); + } + + /** + * This method adds an sig value to the entry cache. If a key is not in + * the cache a new signature entry is created. Therefore the method return + * true.
+ * The value that has to be set would be normalized!
+ * If the key equals to SIG_VALUE all whitespaces are + * removed!
+ * + * @param key + * the key to be set + * @param value + * the value to be set + * @return true if a new signature value is created, + * false otherwise + */ + public boolean setSigValue(String key, String value) { + return setSigValue(key, value, false); + } + + public boolean setSigValue(String key, String value, boolean placeholder) + { + SignatureEntry sig_entry = null; + boolean is_new = false; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + is_new = true; + } + value = normalizer_.normalize(value, true); + if (SignatureTypes.SIG_VALUE.equals(key) || SignatureTypes.SIG_ID.equals(key) || SignatureTypes.SIG_NUMBER.equals(key)) + { + value = removeAllWhiteSpaces(value); + } + sig_entry.setValue(value); + sig_entry.isPlaceholder = placeholder; + return is_new; + } + + public boolean setValueBruteForce(String key, String value) + { + SignatureEntry sig_entry = null; + boolean is_new = false; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + is_new = true; + } + sig_entry.setValue(value); + return is_new; + } + + /** + * Set the value and the caption to given key. + * + * @param key + * the key of the signature object + * @param value + * the value of the given key + * @param caption + * the caption of the given key + */ + public void setSigValueCaption(String key, String value, String caption) + { + setSigValue(key, value); + SignatureEntry sig_entry = (SignatureEntry) sigEntries_.get(key); + sig_entry.setCaption(caption); + } + + /** + * This method returns a value for a given signature key. If the key equals to + * SIG_NORM and the value is null the version + * string of the current normalizer is returned! + * + * @param key + * the key to get the value for + * @return a value for the given key + */ + public String getSigValue(String key) + { + + String value = null; + SignatureEntry sigEntry = null; + if (sigEntries_.containsKey(key)) + { + sigEntry = (SignatureEntry) sigEntries_.get(key); + value = sigEntry.getValue(); + } + if (value == null && SignatureTypes.SIG_NORM.equals(key)) + { + value = normalizer_.getVersion(); + } + + String overrideVal = OverridePropertyHolder.getProperty(key); + if (value != null && sigEntry != null && !sigEntry.isPlaceholder && overrideVal != null) { // TODO this!! SignatureEntry.isPlaceholder + value = overrideVal; + if (logger_.isDebugEnabled()) { + logger_.debug("Using override property for key '" + key + "' = " + value); + } + } + + return value; + } + + /** + * Sets the "Kennzeichnung". + * + * @param kz + * The "Kennzeichnung" to be set. + */ + public void setKZ(PdfASID kz) + { + setSigValue(SignatureTypes.SIG_KZ, kz.toString()); + } + + /** + * Returns the "Kennzeichnung" of this signature. + * + * @return Returns the "Kennzeichnung" of this signature. Returns null if + * there is no "Kennzeichnung" or it is not recognized by this + * application. + */ + public PdfASID getKZ() throws InvalidIDException + { + String kz_string = getSigValue(SignatureTypes.SIG_KZ); + if (kz_string == null) + { + return null; + } + PdfASID kz = null; + try + { + kz = new PdfASID(kz_string); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + return kz; + } + + /** + * This method returns a caption for a given signature key. If the key exists + * and the coresponding value is null the key itself is + * returned as caption! If the key does not exist the method returns + * null. + * + * @param key + * the key to get the caption for + * @return a caption for the given key + */ + private String getSigCaption(String key) + { + + String caption = null; + if (sigEntries_.containsKey(key)) + { + caption = ((SignatureEntry) sigEntries_.get(key)).getCaption(); + if (caption == null) + { + caption = key; + } + } + return caption; + } + + /** + * @return Returns the SignationType. + */ + public String getSignationType() + { + if (sigType_ == null) + { + sigType_ = getDefaultSigType(); + } + return sigType_; + } + + /** + * @return Returns the SignationDate. + */ + public String getSignationDate() + { + return getSigValue(SignatureTypes.SIG_DATE); + } + + /** + * @param sigDate + * The SignationDate to set. + */ + public void setSignationDate(String sigDate) + { + setSigValue(SignatureTypes.SIG_DATE, sigDate); + } + + /** + * @return Returns the SignationName. + */ + public String getSignationName() + { + return getSigValue(SignatureTypes.SIG_NAME); + } + + /** + * @param sigName + * The SignationName to set. + */ + public void setSignationName(String sigName) + { + setSigValue(SignatureTypes.SIG_NAME, sigName); + } + + /** + * @return Returns the SignationNormVersion. + */ + public String getSignationNormVersion() + { + return getSigValue(SignatureTypes.SIG_NORM); + } + + /** + * @param sigNormVersion + * The SignationNormVersion to set. + */ + public void setSignationNormVersion(String sigNormVersion) + { + setSigValue(SignatureTypes.SIG_NORM, sigNormVersion); + } + + /** + * This method removes whitespaces around RDNs. Whitespaces may be assumed by the algorithm that + * re-merges multiple lines from a binary signature when line breaks occur after commas. Without + * correction this will result in broken signatures.
+ * e.g this + * invalid IssuerName (note the space before the second RND CN): + * serialNumber=863532247989, CN=BMUKK - Amtssignatur Schulen,OU=Abt. IT/2,O=Bundesministerium für Unterricht, Kunst und Kultur,C=AT + * will be normalized to: + * serialNumber=863532247989,CN=BMUKK - Amtssignatur Schulen,OU=Abt. IT/2,O=Bundesministerium für Unterricht, Kunst und Kultur,C=AT + * @param The invalid RFC2253 name as string. + * @return The normalized RFC2253 name without spaces prior to RDNs. + */ + public static String prepareRFC2253Name(String name) { + if (name == null) { + return null; + } + StringTokenizer tokenizer = new StringTokenizer(name, ",", false); + StringBuffer result = new StringBuffer(); + // iterate over all alleged RND=value-pairs + while (tokenizer.hasMoreTokens()) { + String rdnExpression = tokenizer.nextToken(); + try { + // try to parse RDN=value + new RFC2253NameParser(rdnExpression.trim()).parse(); + // rdnExpression is a RDN=value pair -> remove whitespaces before and after RDN=value + rdnExpression = rdnExpression.trim(); + } catch (RFC2253NameParserException e) { + // this is not a RDN=value pair + // e.g. " Kunst und Kultur" from the javadoc example + // do not trim, otherwise resulting RFC2253Name will be invalid + } + // re-insert delimiter + if (result.length() > 0) { + result.append(","); + } + // add token (either trimmed RND=value pair, or not trimmed text token) + result.append(rdnExpression); + } + String cleanedName = result.toString(); + if (logger_.isDebugEnabled()) { + logger_.debug("Cleaning RFC2253 name: \"" + name + "\" -> \"" + cleanedName + "\"."); + } + return cleanedName; + } + + /** + * This method depicts a workaround for a bug with RFC2253 names with RDNs that have not been + * resolved from ObjectID at signing time (this results from a BKU that could not resolve + * the respective OID).
+ * e.g. 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
+ * The example above shows a RDN "2.5.4.5" which should have been resolved to "serialNumber" at + * signing time. We also recognize that the name shows spaces prior to RDNs and that the space + * which between "Foreigner" and "CA" is missing due to text extraction/reconstruction. + * The naive approach would be to take the complete RFC2253 name from the certificate, since that + * name has also been used for signature. But this does not work in some cases because while + * the bku was not able to resolve 2.5.4.5 on signing time, the entity invoking pdfas for + * verification might be, so that taking the name from certificate on verification time, may not + * result in the name we had at signing time.
+ * e.g. at signing time: 2.5.4.5=#1306323030383034,CN=Foreigner CA,C=BE
+ * after text extraction: 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
+ * from certificate: serialNumber=863532247989,CN=Foreigner CA,C=BE
+ * This method provides a workaround for that problem, by merging information from text extraction + * with information from the certificate. The method takes all RDNs from the extracted text and + * merges them with the values from the certificate (considering the case where the textual + * version shows BER encoded values (e.g. #1306323030383034). + * @param nameFromText The extracted RFC2253 name from the text (e.g. 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE). + * @param nameFromCertificate The RFC2253 name from the certificate (e.g. serialNumber=863532247989,CN=Foreigner CA,C=BE) + * @return The RFC2253 name that was used for signature (e.g. 2.5.4.5=#1306323030383034,CN=Foreigner CA,C=BE). + */ + public static String prepareRFC2253Name(String nameFromText, String nameFromCertificate) { + + // do not invoke the workaround for performance reasons when both the extracted name and the + // name from certificate are equal + if (StringUtils.equals(nameFromText, nameFromCertificate)) { + return nameFromText; + } + + logger_.debug("Checking RFC2253 name."); + + // if we do not have a name from certificate just return the name from text + if (nameFromCertificate == null) { + logger_.debug("No certificate RFC2253 name provided. Applying less sophisticated workaround (does not cover all cases) without certificate usage."); + return prepareRFC2253Name(nameFromText); + } + + // no name from text extraction available, just return name from certificate + if (nameFromText == null) { + logger_.debug("No extracted/reconstructed name available. Just returning the name from certificate: \"" + nameFromCertificate + "\"."); + return nameFromCertificate; + } + + // helper class + final class RDNValuePair { + + private String rdn; + private String value; + + public RDNValuePair(String rdn, String value) { + this.rdn = rdn; + this.value = value; + } + + public String getRdn() { + return this.rdn; + } + + public String getValue() { + return this.value; + } + + public String toString() { + return rdn + "=" + value; + } + } + + // retrieve RDNs from text based name + List rdnList = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(nameFromText, ",", false); + while (tokenizer.hasMoreTokens()) { + String rdnExpression = tokenizer.nextToken().trim(); + try { + new RFC2253NameParser(rdnExpression).parse(); + // token is RDN=value pair + // split RDN from value + String[] split = rdnExpression.split("=", 2); + rdnList.add(new RDNValuePair(split[0].trim(), split[1].trim())); + } catch (RFC2253NameParserException e) { + // no RDN in token + } + } + + // get values from certificate name + Name nCert; + try { + nCert = new RFC2253NameParser(nameFromCertificate).parse(); + } catch (RFC2253NameParserException e) { + // should never happen + logger_.warn("Unable to parse RFC2253 name \"" + nameFromCertificate + "\". Applying less sophisticated workaround (does not cover all cases) without certificate usage."); + return prepareRFC2253Name(nameFromText); + } + RDN[] values = nCert.getRDNs(); + + // check if results are mergeable + if (values.length != rdnList.size()) { + // unable to merge names; returning nameFromCertificate (since this should be normal + // behavior) + logger_.warn("Number of parsed text based RDNs from \"" + nameFromText + "\" does not fit the number of RDN values from certificate name \"" + nameFromCertificate + "\". Returning name from certificate."); + return nameFromCertificate; + } + + // merge textual based RDNs with values from certificate + StringBuffer result = new StringBuffer(); + for (int i = 0; i < values.length; i++) { + if (i > 0) { + result.append(","); + } + // take rdn from textual representation + RDNValuePair rdnVP = (RDNValuePair) rdnList.get(i); + // Note: Do not take RDN from extraction but from certificate + // (Bug-Fix for EMAIL/EMAILADDRESS problem in ZID documents) + + // take value from certificate but make sure that we do not have a + // BER encoding + if (rdnVP.getValue().startsWith("#")) { + + // take rdn from textual representation + result.append(rdnVP.getRdn()).append("="); + // BER encoding -> take value from text representation + result.append(rdnVP.getValue()); + } else { + // no BER encoding -> take value from certificate + // also take RDN from certificate if possible + String certValue = values[values.length - 1 - i].getAVA() + .getValueAsString(); + String rdn = resolveRDN(nameFromCertificate, certValue, rdnVP.getRdn()); + result.append(rdn + "=").append(certValue); + } + + } + String merged = result.toString(); + if (logger_.isDebugEnabled()) { + if (merged.equals(nameFromText)) { + logger_.debug("Taking name from text: \"" + nameFromText + "\""); + } else if (merged.equals(nameFromCertificate)) { + logger_.debug("Taking name from certificate: \"" + nameFromText + "\""); + } else { + logger_.debug("Name has been fixed."); + logger_.debug("Name from text : \"" + nameFromText + "\""); + logger_.debug("Name from certificate : \"" + nameFromCertificate + "\""); + logger_.debug("Fixed name : \"" + merged + "\""); + } + } + return merged; + } + + /** + * This method tries to resolve the RDN corresponding to a given value from the certificate String. + * As values might occur multiple times for different RDNs, an unambiguous resolving cannot be assured. + * In case of ambiguity, the RDN extracted from text is returned by default. + * + * This method is a bug fix for a problem that caused the verification of ZID documents to fail as the RDN + * from the extracted text ("EMAILADDRESS") was different to the RDN in the certificate ("EMAIL") + * + * @param certString + * The String obtained from the certificate + * @param value + * The RDN's value + * @param extractedRDN + * The RDN extracted from the given text + * @return + * The resolved RDN from the certificate, or the RDN from text extraction + */ + private static String resolveRDN(String certString, String value, String extractedRDN) { + + if(!certString.contains(value)) { + + // given value cannot be found in certificate string + return extractedRDN; + } + + if(certString.indexOf(value) != certString.lastIndexOf(value)) { + + // given value is ambiguous - cannot resolve RDN from certificate string + return extractedRDN; + } + + String[] parts = certString.split(",|;"); + String val = value.trim(); + + for(int i=0; i + * It stores back the SignationIssuer, X509Certificate and + * X509CertificateDigest + */ + private void loadCurrentCert() + { + X509Cert cert = loadCertificate(getSignationSerialNumber(), getSignationIssuer()); + if (cert != null) + { + // merge RDNs from file with values from certificate + if (getSigValue(SignatureTypes.SIG_ISSUER) != null) { + this.setSignationIssuer(prepareRFC2253Name(getSigValue(SignatureTypes.SIG_ISSUER), cert.getIssuerName())); + } else { + this.setSignationIssuer(cert.getIssuerName()); + } + /* + if (getSigValue(SignatureTypes.SIG_ISSUER) == null) { + this.setSignationIssuer(cert.getIssuerName()); + } + */ + setSigValue(SIG_CER, cert.getCertString()); + // setSigValue(SIG_CER_DIG, cert.getCertDigest()); + x509Cert_ = cert; + } + } + + /** + * @return the current X509CertificateDigest value (as SHA1 digest). + */ + public String getX509CertificateDigest() + { + String dig = getSigValue(SIG_CER_DIG); + if (dig == null) + { + loadCurrentCert(); + byte[] cert_b64 = CodingHelper.decodeBase64(x509Cert_.getCertString()); + byte[] cert_hash = CodingHelper.buildDigest(cert_b64, "SHA"); + dig = new String(CodingHelper.encodeBase64(cert_hash)); + setSigValue(SIG_CER_DIG, dig); + } + return dig; + } + + /** + * @return the current X509v3 certificate string + */ + public String getX509CertificateString() + { + String cert = getSigValue(SIG_CER); + if (cert == null) + { + loadCurrentCert(); + cert = getSigValue(SIG_CER); + } + return cert; + } + + /** + * @param x509Certificate + * The X509v3 certificate of the signature to set + */ + public void setX509Certificate(String x509Certificate) + { + setSigValue(SIG_CER, x509Certificate); + storeCertificate(getSignationSerialNumber(), getSignationIssuer(), x509Certificate); + } + + public void setX509Certificate(X509Certificate cert) + { + try + { +// byte [] der = cert.getEncoded(); +// String certStr = CodingHelper.encodeBase64(der); +// setX509Certificate(certStr); + X509Cert knowcenterCert = X509Cert.initByX509Certificate(cert); + setSigValue(SIG_CER, knowcenterCert.getCertString()); + storeCertificate(cert.getSerialNumber().toString(), knowcenterCert.getIssuerName(), knowcenterCert.getCertString()); + } + catch (CertificateEncodingException e) + { + logger_.error(e.getMessage(), e); + } + } + + /** + * return the 509v3 certificate of the given serialNumber and the given issuer + * string + * + * @param serialNumber + * the serialNumber which the certificates should load + * @param issuer + * the issuer which the certificates should load + * @return the X509v3 certificate string + */ + public String getX509CertificateString(String serialNumber, String issuer) + { + X509Cert cert = loadCertificate(serialNumber, issuer); + if (cert != null) + { + return cert.getCertString(); + } + return null; + } + + public X509Cert getX509Cert(String serialNumber, String issuer) + { + return loadCertificate(serialNumber, issuer); + } + + public X509Cert getX509Cert() + { + if (x509Cert_ == null) + { + loadCurrentCert(); + } + return x509Cert_; + } + + /** + * Set the signation id's build by a BKU signated SignatureObject. + * + * @param sigIds + * the string to store. + */ + public void setSignationIDs(String sigIds) + { + if (sigIds != null) + { + setSigValue(SignatureTypes.SIG_ID, sigIds); + } + } + + // /** + // * Set the signation id's build by a BKU signated SignatureObject. + // * + // * @param sigIds + // * The sination id's are defined into five parts, that have the same + // * base as prefix. Therefore the ids's are reduced by the base prefix + // * and stored in the SignatureObject. + // */ + // public void setSignationIDs(String[] sigIds) + // { + // String join = ""; + // String base = null; + // for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++) + // { + // String id = sigIds[arr_idx]; + // if (logger_.isDebugEnabled()) + // { + // logger_.debug("Set BKU id:" + id); + // } + // int id_idx = id.lastIndexOf("-"); + // if (arr_idx == 0) + // { + // base = id.substring(0, id_idx); + // } + // String cur_id = id.substring(id_idx + 1); + // join += "-" + cur_id; + // } + // setSignationIDs(base + "@" + join.substring(1)); + // } + + // TODO hotfix + public static String formatSigIds(Properties response_properties, + String[] sigIds) throws SignatureException + { + // ids algorithm: + String join = ""; + String base = null; + for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++) + { + String id = sigIds[arr_idx]; + if (logger_.isDebugEnabled()) + { + logger_.debug("Set BKU id:" + id); + } + int id_idx = id.lastIndexOf("-"); + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + join += "-" + cur_id; + } + // setSignationIDs(base + "@" + join.substring(1)); + String ids = base + "@" + join.substring(1); + // :ids algorithm + + String productName = response_properties.getProperty("productName"); + logger_.debug("productName = " + productName); +// if (!productName.equals("trustDeskbasic")) + // modified by tknall + if (!productName.startsWith("trustDeskbasic")) + { + final String msg = "The BKU environment " + productName + " is not trustDeskbasic and therefore the productVersion cannot be decided."; + logger_.error(msg); + // uncomment the following line in order to check new bkus + throw new SignatureException(0, msg); + } + + String productVersion = response_properties.getProperty("productVersion"); + logger_.debug("productVersion = " + productVersion); + boolean new_etsi = decideNewEtsiByBKUVersion(productVersion); + logger_.debug("verwende neue etsi properties = " + new_etsi); + + String etsi_prefix = ""; + if (new_etsi) + { + // TODO hotfix + etsi_prefix = "etsi-bka-1.0@"; + } + + String final_ids = etsi_prefix + ids; + logger_.debug("final_ids = " + final_ids); + + return final_ids; + } + + // TODO hotfix + public static boolean decideNewEtsiByBKUVersion(String productVersion) + { + boolean new_etsi = true; + // TODO hotfix + if (productVersion.startsWith("2.5") || productVersion.startsWith("2.4") || productVersion.startsWith("2.3") || productVersion.startsWith("2.2") || productVersion.startsWith("2.1") || productVersion.startsWith("1") || productVersion.startsWith("0")) + { + new_etsi = false; + } + return new_etsi; + } + + /** + * Checks if the current SignatureObject is siganted by MOA. It checks if the + * current SignatureObject has a signation id value. + * + * @return true if no signation id value is found, false otherwise + */ + public boolean isMOASigned() + { + try + { + PdfASID sig_kz = getKZ(); + String sig_id = getSignationIds(); + return SigKZIDHelper.isMOASigned(sig_kz, sig_id); + //return getSignationIds() == null; + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + return false; + } + } + + /** + * Tells if this SignatureObject is textual. + * + * @return Returns true, if it is textual. + */ + public boolean isTextual() + { + PdfASID kz = null; + try + { + kz = getKZ(); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + return SigKZIDHelper.isTextual(kz); + } + + /** + * Tells, if this SignatureObject is binary. + * + * @return Returns true, if it is binary. + */ + public boolean isBinary() + { + PdfASID kz = null; + try + { + kz = getKZ(); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + + return SigKZIDHelper.isBinary(kz); + } + + /** + * Takes the signation id value of the current SignatureObject and split them + * into the corresponding id array added with the id-base. + * + * @return the id array + */ + // TODO hotifx + public String getSignationIds() + { + String sig_ids = getSigValue(SignatureTypes.SIG_ID); + return sig_ids; + + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + // + // // int index = sig_ids.indexOf(PdfAS.IDS); + // // if (index < 0) + // // { + // // return null; + // // } + // // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // // + // // if (sig_ids == null || sig_ids.length() == 0) + // // { + // // return null; + // // } + // + // String[] ids_str = sig_ids.split("@"); + // String base = ids_str[0]; + // String[] ids = ids_str[1].split("-"); + // String[] real_ids = new String[5]; + // real_ids[0] = base + "-" + ids[0]; + // real_ids[1] = "0-" + base + "-" + ids[1]; + // real_ids[2] = "0-" + base + "-" + ids[2]; + // real_ids[3] = "0-" + base + "-" + ids[3]; + // real_ids[4] = "0-" + base + "-" + ids[4]; + // if (logger_.isDebugEnabled()) + // { + // for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + // { + // logger_.debug("Set BKU id:" + real_ids[id_idx]); + // } + // } + // return real_ids; + } + + // TODO hotfix + public static String[] parseSigIds(String sig_ids) + { + if (sig_ids == null || sig_ids.length() == 0) + { + return null; + } + + // int index = sig_ids.indexOf(PdfAS.IDS); + // if (index < 0) + // { + // return null; + // } + // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + + String[] ids_str = sig_ids.split("@"); + + String etsi_string = null; + if (ids_str.length == 3) + { + etsi_string = ids_str[0]; + String[] rest_ids = new String[] { ids_str[1], ids_str[2] }; + ids_str = rest_ids; + } + + String base = ids_str[0]; + String[] ids = ids_str[1].split("-"); + String[] real_ids = new String[6]; // the last one contains the etsi string + real_ids[0] = base + "-" + ids[0]; + real_ids[1] = "0-" + base + "-" + ids[1]; + real_ids[2] = "0-" + base + "-" + ids[2]; + real_ids[3] = "0-" + base + "-" + ids[3]; + real_ids[4] = "0-" + base + "-" + ids[4]; + real_ids[5] = etsi_string; + + if (logger_.isDebugEnabled()) + { + for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + { + logger_.debug("real_ids[" + id_idx + "] = " + real_ids[id_idx]); + } + } + + return real_ids; + } + + /** + * This method normalizes the issuer string to support unique issuer string + * for equition. Used to store and find corresponting certificates. + * Normalzing: normalizing the string using the normalizer, remove all white + * spaces, encode as base64 and replace all "/" chars with "_". + * + * @param issuer + * the issuer string to normalize + * @return the normalized issuer string + * @author modified by tknall + */ + private String getIssuerFileHash(String issuer) + { + try + { + if (issuer != null) + { + // use explicit method for normalization + issuer = normalizeIssuer(issuer); + /* this block may be used to enhance normalization (tknall) + try { + Name issuerName = new RFC2253NameParser(issuer).parse(); + issuer = issuerName.getRFC2253String(); + } catch (RFC2253NameParserException e) { + logger_.error(e); + } + */ + // added the ("UTF-8") + issuer = CodingHelper.encodeBase64(CodingHelper.buildDigest(issuer.getBytes("UTF-8"), "sha1")); + issuer = issuer.replaceAll("/", "_"); + } + return issuer; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * Prepares issuer for further processing (e.g. calculation of certificate store location or + * comparison with registered ldap mappings.) + * @param issuer The issuer. + * @return normalized issuer + * @see #issuerNameFilter + * @author tknall + */ + private String normalizeIssuer(String issuer) { + issuer = normalizer_.normalize(issuer, false); + issuer = removeAllWhiteSpaces(issuer); + return issuer; + } + + /** + * This method imports new certificates into the certstore path. + */ + private void addNewCertificates() + { + String cert_add_path = certPath_ + CERT_ADD_DIR; + File cert_add_dir = new File(cert_add_path); + if (cert_add_dir.isDirectory()) + { + File[] cert_files = cert_add_dir.listFiles(); + for (int cert_file_idx = 0; cert_file_idx < cert_files.length; cert_file_idx++) + { + File cert_file = cert_files[cert_file_idx]; + if (cert_file.isFile() && cert_file.canRead()) + { + X509Cert cert = X509Cert.initByFile(cert_file); + // System.err.println("isCert:" + cert.isX509Cert() + ":" + + // cert_file.getAbsolutePath()); + if (cert.isX509Cert()) + { + String issuer = cert.getIssuerName(); + String serial_number = cert.getSerialNumber(); + String iss_hash = getIssuerFileHash(issuer); + String cert_store_path = certPath_ + iss_hash; + + File cert_store_dir = new File(cert_store_path); + if (!cert_store_dir.exists()) + { + cert_store_dir.mkdir(); + } + if (cert_store_dir.isDirectory()) + { + String cert_file_name = cert_store_path + FILE_SEP + serial_number + CERT_FILE_EXTENSION; + logger_.debug("Adding cert (issuer=\"" + cert.getIssuerName() + "\", sn=\"" + cert.getSerialNumber() + "\") to certstore: \"" + cert_file_name + "\"."); + // boolean store = + FileHelper.writeToFile(cert_file_name, cert.getCertString()); + // System.err.println("store:" + store + ":" + + // cert_file.getAbsolutePath()); + } + } + boolean deleted = cert_file.delete(); + if (deleted == false) + { + logger_.error("couldn't delete:" + cert_file.getAbsolutePath()); + } + } + } + } + } + + private X509Cert loadCertificateFromCertstore(String serialNumber, String issuer) { + String iss_hash = getIssuerFileHash(issuer); + String cert_store_path = certPath_ + iss_hash; + String cert_file_name = cert_store_path + FILE_SEP + serialNumber + CERT_FILE_EXTENSION; + if (logger_.isDebugEnabled()) { + logger_.debug("Trying to load cert (issuer=\"" + (issuer != null ? normalizeIssuer(issuer) : issuer) + "\", sn=\"" + serialNumber + "\") from certstore: \"" + cert_file_name + "\"."); + } + return X509Cert.initByFilePath(cert_file_name); + } + + /** + * This method load a X509v3 certificate from the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the file path value of the certificate + * @return String array: [0]--> issuer string; [1]-->certificate binary; + * [2]--> cert digest value + */ + private X509Cert loadCertificate(String serialNumber, String issuer) + { + addNewCertificates(); + X509Cert cert = null; + if (issuer != null && serialNumber != null) + { + cert = loadCertificateFromCertstore(serialNumber, issuer); + if (cert == null) { + logger_.debug("Certificate not found. Trying alternative normalization method."); + try { + Name issuerName = new RFC2253NameParser(issuer).parse(); + cert = loadCertificateFromCertstore(serialNumber, issuerName.getRFC2253String(false)); + } catch (RFC2253NameParserException e) { + logger_.error(e.getMessage(), e); + } + } + + if (cert == null) + { + logger_.info("The certificate '" + issuer + "', '" + serialNumber + "' wasn't found in the local certificate store - connecting to LDAP."); + + // the certificate wasn't found in the local store + // - load it from the LDAP server. + + byte[] cert_data = loadCertificateFromLDAP(serialNumber, issuer); + if (cert_data == null) + { + logger_.info("The certificate '" + issuer + "', '" + serialNumber + "' wasn't found on the LDAP server either."); + + return null; + } + + storeNewCertificateInLocalStore(cert_data); + + cert = X509Cert.initByByteArray(cert_data); + if (cert == null) + { + logger_.debug("The certificate should be loaded here, but is null - something's wrong."); + } + } + } else { + logger_.warn("loadCertificate(\"" + serialNumber + "\", \"" + issuer + "\")"); + } + return cert; + } + + /** + * This is an internal counter for added certificates. + */ + protected static int new_cert_num = 0; + + /** + * Writes the certificate data to a file and stores the file in the local + * certificate store. + * + * @param cert_data + * The binary certificate data. + */ + public void storeNewCertificateInLocalStore(byte[] cert_data) + { + // write the loaded certificate to the add directory + String cert_add_path = certPath_ + CERT_ADD_DIR; + File cert_add_dir = new File(cert_add_path); + if (!cert_add_dir.exists()) + { + cert_add_dir.mkdirs(); + } + File save_file = new File(cert_add_dir, "newcert_" + new_cert_num + ".der"); + new_cert_num++; + try + { + FileOutputStream fos = new FileOutputStream(save_file); + fos.write(cert_data); + fos.close(); + // fixed by tknall: if serialnumber or issuername is omitted (binary signature) the + // certificate could not be found in the certstore. The fix sets the issuername and + // serialnumber as long the are known. + X509Cert cert = X509Cert.initByByteArray(cert_data); + if (cert.isX509Cert()) { + this.setSignationSerialNumber(cert.getSerialNumber()); + this.setSignationIssuer(cert.getIssuerName()); + } + } catch (IOException e) { + logger_.error(e.getMessage(), e); + return; + } + + // add the new certificate to the local store + addNewCertificates(); + } + + /** + * Connects to the LDAP server to look for the certificate. + * + * @param serialNumber + * The serial number String of the certificate being sought. E.g. + * "123455676744123432". + * @param issuer + * The issuer String of the certificate being sought. + * + * @return Returns the DER certificate file as can be stored in the local + * repository. Returns null, if the document wasn't found on the + * server. + * @throws ClassNotFoundException + */ + protected byte[] loadCertificateFromLDAP(String serialNumber, String issuer) { + // START modification by TK + String implClassURI = System.getProperty(LDAPAPI.SYS_PROP_IMPLEMENTATION); + LDAPAPI ldapAPIImpl; + try { + // note: in case of implClassURI==null the default implementation + // at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIImpl is used + ldapAPIImpl = LDAPAPIFactory.getInstance(issuerNameFilter).createLDAPAPI(implClassURI); + } catch (LDAPAPIException e) { + throw new RuntimeException(e); + } + return ldapAPIImpl.loadBase64CertificateFromLDAP(serialNumber, issuer); + // STOP modification by TK + } + + /** + * This method stores a X509v3 certificate to the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the issuer string for the file path value of the certificate and + * for metainformation + * @param x509Certificate + * the x509v3 binary string + * @param x509Digest + * the digest value of the given x509Certificate + * @return true the certificate is stored completely, false otherwise + * @deprecated Use {@link #storeCertificate(String, String, String)} instead. + */ + private boolean storeCertificate(String serialNumber, String issuer, + String x509Certificate, String x509Digest) + { + return storeCertificate(serialNumber, issuer, x509Certificate); + } + + /** + * This method stores a X509v3 certificate to the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the issuer string for the file path value of the certificate and + * for metainformation + * @param x509Certificate + * the x509v3 binary string + * @return true the certificate is stored completely, false otherwise + */ + private boolean storeCertificate(String serialNumber, String issuer, + String x509Certificate) + { + boolean store_complete = false; + if (issuer != null && serialNumber != null) + { + logger_.debug("Storing certificate."); + // String issuer_b64 = CodingHelper.encodeBase64(issuer.getBytes()); + String iss_hash = getIssuerFileHash(issuer); + File cert_path_dir = new File(certPath_); + if (!cert_path_dir.exists()) + { + logger_.debug("Certstore path \"" + cert_path_dir + "\" does not exist. Creating."); + cert_path_dir.mkdir(); + } + String cert_store_path = certPath_ + iss_hash; + File cert_store_dir = new File(cert_store_path); + if (!cert_store_dir.exists()) + { + logger_.debug("Certstore dir \"" + cert_store_dir + "\" does not exist. Creating."); + cert_store_dir.mkdir(); + } + if (cert_store_dir.isDirectory()) + { + String cert_file_name = cert_store_path + FILE_SEP + serialNumber + CERT_FILE_EXTENSION; + if (logger_.isInfoEnabled()) + { + logger_.info("store certificate:" + cert_file_name); + } + boolean store_cert_file = FileHelper.writeToFile(cert_file_name, x509Certificate); + store_complete = store_cert_file;// && store_cert_meta; + } else { + logger_.warn("Certstore dir \"" + cert_store_dir + "\" is not a directory. Skipping storage."); + } + } + return store_complete; + } + + /** + * @return Returns the AbstractTable. + * @see at.knowcenter.wag.egov.egiz.table.Table + */ + public Table getAbstractTable() + { + if (sigTable_ == null) + { + sigTable_ = createSigTable(SignatureTypes.MAIN_TABLE); + } + return sigTable_; + } + + /** + * This method read the style definitions from the settings file. + * + * @param styleKey + * the key to read the style definitions + * @return the defined style informations + * @see at.knowcenter.wag.egov.egiz.table.Style + */ + private Style readStyle(String styleKey) + { + ArrayList styles = settings_.getKeys(styleKey); + Style style = new Style(); + for (int style_idx = 0; style_idx < styles.size(); style_idx++) + { + String style_id = (String) styles.get(style_idx); + String style_val = settings_.getSetting(styleKey + "." + style_id, null); + style.setStyle(style_id, style_val); + } + return style; + } + + /** + * This method creates an abstract signature table object. It takes all keys + * and values set by the signature object to create the corresponding abstract + * table object. The table definition is read from the settings file. + * + * @param tableKey + * is the name of the table definition in the settings file + * @return a new abstract signature table + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see at.knowcenter.wag.egov.egiz.table.Table + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ + private Table createSigTable(String tableKey) + { + String table_key_prefix = SignatureTypes.SIG_OBJ + getSignationType() + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + // String caption_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".key."; + // String value_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".value."; + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys == null) + { + return null; + } + Table sig_table = new Table(tableKey); + boolean found_style = false; + for (int table_key_idx = table_def_keys.size() - 1; table_key_idx >= 0; table_key_idx--) + { + String table_def = (String) table_def_keys.get(table_key_idx); + int dot_idx = (table_def.indexOf(".") > 0 ? table_def.indexOf(".") : table_def.length()); + table_def = table_def.substring(0, dot_idx); + String table_def_keys_prefix = table_key + "." + table_def; + String table_def_string = settings_.getSetting(table_def_keys_prefix, null); + if (table_def.matches("\\D*")) + { + // if the table key is not a number (row number index) + if (SignatureTypes.COLS_WITH.equals(table_def)) + { + String[] cols_s = table_def_string.split(" "); + float[] cols_f = new float[cols_s.length]; + for (int i = 0; i < cols_s.length; i++) + { + cols_f[i] = Float.parseFloat(cols_s[i]); + } + sig_table.setColsRelativeWith(cols_f); + } + if (SignatureTypes.STYLE.equals(table_def) && !found_style) + { + Style style = readStyle(table_def_keys_prefix); + sig_table.setStyle(style); + found_style = true; + } + continue; + } + if (table_def_string != null) + { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + ArrayList row = new ArrayList(); + for (int elem_idx = 0; elem_idx < elems.length; elem_idx++) + { + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) + { + return null; + } + String key = key_type[0]; + String type = key_type[1]; + if (SignatureTypes.TYPE_TABLE.equals(key)) + { + // add a table entry + Table table = createSigTable(type); + if (table != null) + { + Entry entry = new Entry(Entry.TYPE_TABLE, table, key); + row.add(entry); + } + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) + { + // add an image entry + String value = getSigValue(key); + if (value != null) + { + Entry entry = new Entry(Entry.TYPE_IMAGE, value, key); + entry.setStyle(defaultImageStyle_); + row.add(entry); + } + } + if (SignatureTypes.TYPE_VALUE.equals(type)) + { + // add a single value entry + String value = getSigValue(key); + Entry entry = new Entry(Entry.TYPE_VALUE, value, key); + if (entry != null) + { + entry.setColSpan(2); + entry.setStyle(defaultValueStyle_); + row.add(entry); + } + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION).equals(type) || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE).equals(type)) + { + // add a caption value pair + String caption = getSigCaption(key); + String value = getSigValue(key); + if (value != null) + { + Entry c_entry = new Entry(Entry.TYPE_CAPTION, caption, key); + c_entry.setNoWrap(true); // dferbas fix bug #331 + c_entry.setStyle(defaultCaptionStyle_); + + Entry v_entry = new Entry(Entry.TYPE_VALUE, value, key); + v_entry.setStyle(defaultValueStyle_); + if (c_entry != null && v_entry != null) + { + row.add(c_entry); + row.add(v_entry); + } + } + } + } + sig_table.addRow(table_def, row); + } + } + + return sig_table; + } + + /** + * This method inits the signature object by the given type. It loads the + * configured values and captions from the config.properties file. + */ + public void initByType() throws SignatureTypesException + { + if (sigType_ == null) + { + sigType_ = getDefaultSigType(); + } + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + if (signatureDefinition_ == null) + { + final String msg = "The SignatureObject's sigType '" + sigType_ + "' wasn't found in the configuration file's specified signature profiles. This usually happens if the sig_obj.type.default object has been turned off or is misspelled."; + logger_.error(msg); + throw new SignatureTypesException(msg); + } + Map key_cap_map = signatureDefinition_.getKeyCaptionMap(); + if (key_cap_map != null) + { + Iterator key_cap = key_cap_map.entrySet().iterator(); + while (key_cap.hasNext()) + { + Map.Entry entry = (Map.Entry) key_cap.next(); + String key = (String) entry.getKey(); + String caption = (String) entry.getValue(); + SignatureEntry sig_entry = null; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + } + sig_entry.setCaption(caption); + } + } + + Map key_val_map = signatureDefinition_.getKeyValueMap(); + if (key_val_map != null) + { + Set key_val_set = key_val_map.entrySet(); + Iterator key_val = key_val_set.iterator(); + while (key_val.hasNext()) + { + Map.Entry entry = (Map.Entry) key_val.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (SignatureTypes.SIG_NORM.equals(key)) + { + try + { + normalizer_.setVersion(value); + } + catch (NormalizeException e) + { + throw new SignatureTypesException(e); + } + } + // value = new String(CodingHelper.encodeUTF8(value)); + // if (logger_.isDebugEnabled()) + // { + // logger_.debug("key:" + key + " value:" + value); + // } + setSigValue(key, value); + } + } + } + + /** + * This method returns a signature entry object. + * + * @param key + * the corresponding key + * @return the signature entry object of the given key, null if the key does + * not exist + */ + public SignatureEntry getSigEntry(String key) + { + return (SignatureEntry) sigEntries_.get(key); + } + + /** + * This method is a helper function to remove all white spaces from a text. + * + * @param text + * the white spaces should remove from + * @return a text without white spaces + */ + private static String removeAllWhiteSpaces(String text) + { + return text.replaceAll("\\s", ""); + } + + public SignatureTypeDefinition getSignatureTypeDefinition() + { + return this.signatureDefinition_; + } + + /** + * + * @param placeholder + * @return Returns the list of SignatureFieldDefinitions that's values in the + * SignatureObject have been filled out with placeholders. + */ + public List fillValues(final char placeholder, boolean has_SIG_ID, boolean baikEnabled) + { + List variable_fields = new ArrayList(); + + List field_definitions = this.signatureDefinition_.getFieldDefinitions(); + Iterator it = field_definitions.iterator(); + while (it.hasNext()) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + String value_string = null; + if (sfd.placeholder_length > 0) + { + if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false) + { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + if (sfd.field_name.equals(SignatureTypes.SIG_ALG) && !baikEnabled) { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + char[] placeholder_chars = new char[sfd.placeholder_length]; + for (int i = 0; i < placeholder_chars.length; i++) + { + placeholder_chars[i] = placeholder; + } + value_string = new String(placeholder_chars); + + variable_fields.add(sfd); + + setSigValue(sfd.field_name, value_string, true); + } + } + + return variable_fields; + } + + /** + * Returns the raw signature response XML string as set by the signing + * Connector. + * + * @return Returns the XML response String. + */ + public String getRawSignatureResponse() + { + return this.raw_signature_response; + } + + /** + * Sets the raw signature response XML string. + * + *

+ * This should be used by the Connector to pass the response String to the + * signer. + *

+ * + * @param raw_response_string + * The new raw signature response string. + */ + public void setRawSignatureResponse(String raw_response_string) + { + this.raw_signature_response = raw_response_string; + } + + + + /** + * get timestamp if available + * @return + */ + public String getTimeStamp() { + return this.timeStamp; + } + + /** + * set timestamp + * @param timeStamp + */ + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + +/** + * The toString method, used for tests or debugging. + */ + public String toString() + { + String strg = ""; + Iterator it = sigEntries_.values().iterator(); + while (it.hasNext()) + { + SignatureEntry sig_entry = (SignatureEntry) it.next(); + String key = sig_entry.getKey(); + String caption = sig_entry.getCaption(); + String value = sig_entry.getValue(); + strg += key + "=" + caption + ":" + value + "\n"; + } + strg += "Signation Type:" + getSignationType() + "\n"; + return strg; + } + + public Map getSigEntries() { + return sigEntries_; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java new file mode 100644 index 0000000..0c733f6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java @@ -0,0 +1,559 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureResponse.java,v 1.4 2006/08/03 07:43:04 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.PropertyTree; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * The response of a verification. + * + * @author wlackner + */ +public class SignatureResponse +{ + /** + * The siganture response config key + */ + private static String SIG_RESP_KEY = "signature.response."; + + /** + * Default response message + */ + private static String SIG_RESP_DEFAULT_INFO = "Es ist leider keine nähere Information verfügbar:"; + + /** + * Response value for x509SubjectName_ + */ + private String x509SubjectName_ = null; + + /** + * Response value for x509IssuerName + */ + private String x509IssuerName = null; + + /** + * Response value for x509SerialNumber + */ + private String x509SerialNumber = null; + + /** + * Response value for signatureCheckCode_ + */ + private String signatureCheckCode_ = null; + + /** + * Response value for signatureCheckInfo_ + */ + private String signatureCheckInfo_ = null; + + /** + * Response value for signatureManifestCheckCode_ + */ + private String signatureManifestCheckCode_ = null; + + /** + * Response value for signatureManifestCheckInfo_ + */ + private String signatureManifestCheckInfo_ = null; + + /** + * Response value for certificateCheckCode_ + */ + private String certificateCheckCode_ = null; + + /** + * Response value for certificateCheckInfo_ + */ + private String certificateCheckInfo_ = null; + + /** + * The X.509 certificated parsed from the response string. + */ + protected X509Cert certificate_ = null; + + // [tknall] start qualified certificate + private boolean qualifiedCertificate = false; + // [tknall] stop qualified certificate + + private boolean publicAuthority = false; + private String publicAuthorityCode = null; + + protected String hashInputData = null; + + private PdfAsException verificationImpossibleEx = null; + + // /** + // * Flag the marks that the response is an error response + // */ + // private boolean isError_ = false; + // + // /** + // * The error code of an external application + // */ + // private String errorCode_ = null; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureResponse.class); + + /** + * + * + */ + public SignatureResponse() + { + try + { + loadSettings(); + } + catch (SignatureException e) + { + logger_.warn(e.getMessage(), e); + } + } + + /** + * load the inital signature settings + * + * @throws SignatureException + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * @return Returns the certificateCheckCode. + */ + public String getCertificateCheckCode() + { + return certificateCheckCode_; + } + + /** + * @param certificateCheckCode + * The certificateCheckCode to set. + */ + public void setCertificateCheckCode(String certificateCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setCertificateCheckCode:" + certificateCheckCode); + } + certificateCheckCode_ = certificateCheckCode; + } + + /** + * @return Returns the signatureCheckCode. + */ + public String getSignatureCheckCode() + { + return signatureCheckCode_; + } + + /** + * @param signatureCheckCode + * The signatureCheckCode to set. + */ + public void setSignatureCheckCode(String signatureCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureCheckCode:" + signatureCheckCode); + } + signatureCheckCode_ = signatureCheckCode; + } + + /** + * @return Returns the signatureManifestCheckCode. + */ + public String getSignatureManifestCheckCode() + { + return signatureManifestCheckCode_; + } + + /** + * Returns {@code true} if the underlying certificate indicates public authority. + * @return {@code true} if public authority, {@code false} if not. + */ + public boolean isPublicAuthority() { + return this.publicAuthority; + } + + /** + * Sets the public authority flag. + * @param publicAuthority The public authority flag. + */ + public void setPublicAuthority(boolean publicAuthority) { + this.publicAuthority = publicAuthority; + } + + /** + * Returns the public authority code of {@code null} if no code was provided. + * @return The public authority code. + */ + public String getPublicAuthorityCode() { + return this.publicAuthorityCode; + } + + /** + * Sets the public authority code. + * @param publicAuthorityCode The public authority code. + */ + public void setPublicAuthorityCode(String publicAuthorityCode) { + this.publicAuthorityCode = publicAuthorityCode; + } + +/** + * @param signatureManifestCheckCode + * The signatureManifestCheckCode to set. + */ + public void setSignatureManifestCheckCode(String signatureManifestCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureManifestCheckCode:" + signatureManifestCheckCode); + } + signatureManifestCheckCode_ = signatureManifestCheckCode; + } + + /** + * @return Returns the x509IssuerName. + */ + public String getX509IssuerName() + { + return x509IssuerName; + } + + /** + * @param issuerName + * The x509IssuerName to set. + */ + public void setX509IssuerName(String issuerName) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509IssuerName:" + issuerName); + } + x509IssuerName = issuerName; + } + + /** + * @return Returns the x509SerialNumber. + */ + public String getX509SerialNumber() + { + return x509SerialNumber; + } + + /** + * @param serialNumber + * The x509SerialNumber to set. + */ + public void setX509SerialNumber(String serialNumber) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509SerialNumber:" + serialNumber); + } + x509SerialNumber = serialNumber; + } + + /** + * @return Returns the x509SubjectName. + */ + public String getX509SubjectName() + { + return x509SubjectName_; + } + + /** + * @param subjectName + * The x509SubjectName to set. + */ + public void setX509SubjectName(String subjectName) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509SubjectName:" + subjectName); + } + x509SubjectName_ = subjectName; + } + + /** + * @return Returns the certificateCheckInfo. + */ + public String getCertificateCheckInfo() + { + if (certificateCheckInfo_ == null) + { + if (settings_ != null) + { + certificateCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "certificateCheckInfo." + getCertificateCheckCode()); + } + } + if (certificateCheckInfo_ == null) + { + certificateCheckInfo_ = SIG_RESP_DEFAULT_INFO + getCertificateCheckCode(); + } + return certificateCheckInfo_; + } + + /** + * @param certificateCheckInfo + * The certificateCheckInfo to set. + */ + public void setCertificateCheckInfo(String certificateCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setCertificateCheckInfo:" + certificateCheckInfo); + } + certificateCheckInfo_ = certificateCheckInfo; + } + + // [tknall] start qualified certificate + + /** + * Returns true if certificate is qualified, false if not. + * @return true if certificate is qualified, false if not. + */ + public boolean isQualifiedCertificate() { + return this.qualifiedCertificate; + } + + /** + * Sets the flag for qualified certificate. + * @param qualifiedCertificate The new qualified certificate status. + */ + public void setQualifiedCertificate(boolean qualifiedCertificate) { + this.qualifiedCertificate = qualifiedCertificate; + } + // [tknall] stop qualified certificate + + /** + * @return Returns the signatureCheckInfo. + */ + public String getSignatureCheckInfo() + { + if (signatureCheckInfo_ == null) + { + if (settings_ != null) + { + signatureCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "signatureCheckInfo." + getSignatureCheckCode()); + } + } + if (signatureCheckInfo_ == null) + { + signatureCheckInfo_ = SIG_RESP_DEFAULT_INFO + getSignatureCheckCode(); + } + return signatureCheckInfo_; + } + + /** + * @param signatureCheckInfo + * The signatureCheckInfo to set. + */ + public void setSignatureCheckInfo(String signatureCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureCheckInfo:" + signatureCheckInfo); + } + signatureCheckInfo_ = signatureCheckInfo; + } + + /** + * @return Returns the signatureManifestCheckInfo. + */ + public String getSignatureManifestCheckInfo() + { + if (signatureManifestCheckInfo_ == null) + { + if (settings_ != null) + { + signatureManifestCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "signatureManifestCheckInfo." + getSignatureManifestCheckCode()); + } + } + if (signatureManifestCheckInfo_ == null) + { + signatureManifestCheckInfo_ = SIG_RESP_DEFAULT_INFO + getSignatureManifestCheckCode(); + } + return signatureManifestCheckInfo_; + } + + /** + * @param signatureManifestCheckInfo + * The signatureManifestCheckInfo to set. + */ + public void setSignatureManifestCheckInfo(String signatureManifestCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureManifestCheckInfo:" + signatureManifestCheckInfo); + } + signatureManifestCheckInfo_ = signatureManifestCheckInfo; + } + + /** + * Returns the X.509 certificate of this response. + * + * @return Returns the X.509 certificate of this response. + */ + public X509Cert getCertificate() + { + return certificate_; + } + + /** + * Sets the X.509 certificate of this response. + * + * @param certificate + * The X.509 certificate to be set. + */ + public void setCertificate(X509Cert certificate) + { + this.certificate_ = certificate; + } + + public String getHashInputData() + { + return this.hashInputData; + } + + public void setHashInputData(String hashInputData) + { + this.hashInputData = hashInputData; + } + + public PdfAsException getVerificationImpossibleEx() { + return verificationImpossibleEx; + } + + public void setVerificationImpossibleEx(PdfAsException verificationImpossibleEx) { + this.verificationImpossibleEx = verificationImpossibleEx; + } + +/** + * 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". + *

+ *

+ * This methods reads out the list of possible properties from the config file + * and compares these to the extensions defined on the certificate. If they + * match, a String containing useful information about the property is added + * to the list returned. + *

+ * + * @return Returns the list of Strings representing the public properties of + * this certificate, if any. + * @throws SettingNotFoundException + */ + public List getPublicProperties() throws SettingNotFoundException + { + List props = new ArrayList(); + + SettingsReader settings = this.settings_; + + String root_oid = settings.getSetting("oid.root"); + + PropertyTree oids = settings.getPTree().getSubTree("oid"); + + Set non_critial_oids = this.certificate_.getX509Certificate().getNonCriticalExtensionOIDs(); + Iterator ext_it = non_critial_oids.iterator(); + while (ext_it.hasNext()) + { + String oid = (String) ext_it.next(); + + if (oid.startsWith(root_oid)) + { + String key = oid.replaceAll("\\.", "_"); + + String value = oids.getLastValue(key); + if (value == null) + { + value = oid; + } + + props.add(value); + } + } + + return props; + } + + /** + * The toString method + */ + public String toString() + { + String str = ""; + str += "\nSignator:" + getX509SubjectName(); + str += "\nAusteller:" + getX509IssuerName(); + str += "\nSeriennummer:" + getX509SerialNumber(); + str += "\nZertifikat-Code:" + getCertificateCheckCode() + "=" + getCertificateCheckInfo(); + str += "\nSignatur-Check-Code:" + getSignatureCheckCode() + "=" + getSignatureCheckInfo(); + str += "\nManifest-Check-Code:" + getSignatureManifestCheckCode() + "=" + getSignatureManifestCheckInfo(); + return str; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java new file mode 100644 index 0000000..5b80490 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java @@ -0,0 +1,146 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureSeparator.java,v 1.4 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.List; +import java.util.Stack; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * This class separates all signature blocks in a raw text. + * @deprecated This process of separating signature blocks is obsolete - use AbsoluteTextSignature etc. instead. + */ +public class SignatureSeparator { + /** + * The signature block stack. On top of the stack is the first signature block that can be + * extracted. First means nearest to the document text. + */ + private Stack signatureBlocks_ = null; + /** + * A list of signature type definitions. + */ + private List signatureTypes_ = null; + /** + * Indicator that shows that a raw text is signated + */ + private boolean hasSignatureBlock_ = false; + + /** + * The empty constructor. It loads all signature type infos to extract the signature block from + * the raw text. + * + * @throws SignatureTypesException + */ + public SignatureSeparator() throws SignatureTypesException { + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureTypes_ = sig_types.getSignatureTypeDefinitions(); + } + + /** + * This method takes a raw text as input and trys to separate all signature blocks. It returns + * true if a signature block is found. + * + * @param rawText + * @return true if a signature block is found false otherwise + */ + public boolean separateBlock(String rawText) { + signatureBlocks_ = new Stack(); + hasSignatureBlock_ = separateBlock(rawText, rawText.length()); + return hasSignatureBlock_; + } + + /** + * This method calls itself rekursively while signature blocks can be extracted. If a signature + * block is found (search from the bottom of the raw text) the raw text would be reduced by the + * length of the found signature block text. + * + * @param rawText the text to be separated + * @param endIndex the index to cut the tail from the raw text + * @return true if a signature block is found false otherwise + */ + private boolean separateBlock(String rawText, int endIndex) { + boolean found = false; + boolean can_separate = true; + while (can_separate) { + SignatureBlock sig_block = new SignatureBlock(signatureTypes_); + String raw_text = rawText.substring(0, endIndex); + can_separate = sig_block.separateBlockFromRawText(raw_text, true); + if (can_separate) { + signatureBlocks_.push(sig_block); + endIndex = sig_block.getStartIndex(); + found = true; + } + } + return found; + } + + /** + * This method returns the start index of the first signature block. It is used to separate the + * real document text from the signature block texts. + * + * @return the start index of the first signature block + */ + public int getStartIndex() { + int start_index = -1; + if (signatureBlocks_ != null && signatureBlocks_.size() > 0) { + SignatureBlock sig_block = (SignatureBlock) signatureBlocks_.peek(); + return sig_block.getStartIndex(); + } + return start_index; + } + + /** + * @return the first found signature object in the given raw text or null if the raw text does not + * contain any signature objects + */ + public SignatureObject getFirstSignatureObject() { + if (signatureBlocks_ != null && signatureBlocks_.size() > 0) { + SignatureBlock sig_block = (SignatureBlock) signatureBlocks_.peek(); + try { + return sig_block.getSignatureObject(); + } catch (SignatureException e) { + return null; + } + } + return null; + } + + /** + * @return all separated signature blocks as stack, first is on top + */ + public Stack getSignatureBlocks() { + return signatureBlocks_; + } + + /** + * @return true if a signature block is found false otherwise + */ + public boolean hasSignatureBlock() { + return hasSignatureBlock_; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java new file mode 100644 index 0000000..de099bf --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java @@ -0,0 +1,605 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureTypeDefinition.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +public class SignatureTypeDefinition implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 1327407307346061147L; + + /** + * The log. + */ + private static final Log logger_ = LogFactory.getLog(SignatureTypeDefinition.class); + + /** + * The type of this definition + */ + protected String type_ = null; + + /** + * A map of all key to caption tupls. + */ + private Map keyCaptionMap_ = new HashMap(); + + /** + * A map of all key to value tupls. + */ + private Map keyValueMap_ = new HashMap(); + + /** + * A list of sorted keys + */ + private Vector sortedKeys_ = null; + + /** + * A list of sorted captions + */ + private Vector sortedCaptions_ = null; + + /** + * A revert of sorted keys + */ + private Vector revertSortedKeys_ = new Vector(); + + /** + * A revert list of sorted captions + */ + private Vector revertSortedCaptions_ = new Vector(); + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + /** + * List of (visible) field definitions. + */ + protected Map field_definitions_ = null; + + /** + * List of invisible field definitions. + * + *

+ * If empty, all definitions are visible. + *

+ */ + protected Map invisible_field_definitions = null; + + + + /** + * The constructor of the signature type definition. It reads the configured + * table definition of the signature block and load the type definition of a + * given type. + * + * @param settings + * a SettingsReader instance + * @param type + * the signature type to load + * @throws SignatureException + * @see SettingsReader + */ + public SignatureTypeDefinition(SettingsReader settings, String type) throws SignatureException + { + settings_ = settings; + type_ = type; + readSigTable(SignatureTypes.MAIN_TABLE); + loadTypeDefinition(); + readFieldDefinitions(); + readInvisibleFieldDefinitions(); + } + + protected void readInvisibleFieldDefinitions() + { + this.invisible_field_definitions = new HashMap(); + for (int i = 0; i < SignatureTypes.REQUIRED_SIG_KEYS.length; i++) + { + String requiredKey = SignatureTypes.REQUIRED_SIG_KEYS[i]; + if (!this.sortedKeys_.contains(requiredKey)) + { + SignatureFieldDefinition sfd = readFieldDefinition(requiredKey); + this.invisible_field_definitions.put(sfd.field_name, sfd); + } + } + } + + /** + * Returns the List of invisible field definitions, if any. + * + *

+ * Invisible field definitions are the field definitions of required fields that are not explicitely specified in the signature profile. + *

+ *

+ * Note that the concept of invisible fields can only be used by binary signatures. + *

+ * + * @return Returns the List of invisible field definitions, if any. + */ + public List getInvisibleFieldDefinitions() + { + return new ArrayList(this.invisible_field_definitions.values()); + } + + /** + * Tells, if the signature type is text-extractable, which means that all required fields are visible. + * + * @return Returns true, if the signature type is text-extractable. + */ + public boolean isTextExtractable() + { + if (logger_.isDebugEnabled()) { + Iterator it = this.invisible_field_definitions.values().iterator(); + StringBuffer buffer = new StringBuffer(); + while (it.hasNext()) { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + buffer.append(sfd.field_name); + if (it.hasNext()) { + buffer.append(", "); + } + } + if (buffer.length() != 0) { + logger_.debug("Invisible field definitions for profile \"" + this.type_ + "\" = " + buffer.toString()); + } + } + return this.invisible_field_definitions.isEmpty(); + } + + /** + * Load the configured signature type definitions. It reads all key-captions + * tupls that are used in the signature table. It also reads all key-value + * tupls. + * + * @throws SignatureException + */ + private void loadTypeDefinition() throws SignatureException + { + if (sortedKeys_ == null) + { + sortKeys(); + } + + String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key"; + ArrayList keys = settings_.getKeys(key_prefix); + if (keys == null) + { + // exthex: no exception to enable invisible signatures + logger_.debug("There is no key defined for type:" + type_ +". assuming invisible signature"); + return; +// keep this incredible wprinz(?) lines as a puzzle: Can anyone do same thing in just one line? +// SignatureException se = new SignatureException(100, "There is no key defined for type:" + type_); +// ; +// throw se; + } + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String sig_key = (String) keys.get(key_idx); + String sig_key_val = settings_.getValueFromKey(key_prefix + "." + sig_key); + if (sortedKeys_.contains(sig_key)) + { + keyCaptionMap_.put(sig_key, sig_key_val); + } + } + String value_prefix = SignatureTypes.SIG_OBJ + type_ + ".value"; + ArrayList values = settings_.getKeys(value_prefix); + if (values != null) + { + for (int key_idx = 0; key_idx < values.size(); key_idx++) + { + String val_key = (String) values.get(key_idx); + String val_key_val = settings_.getValueFromKey(value_prefix + "." + val_key); + keyValueMap_.put(val_key, val_key_val); + } + } + } + + /** + * This method reads the table definition of singature type. It takes care + * about the linearization of the defined key-value pairs or sub tables. The + * linearisation is done reading a table from left to right and top to bottom. + * A sub table is alwais a normal cell element in the linearisation prozess. + * If a sub table exists therefore the linearisation of the subtable is taken + * es cell element in the parent table. t This method stores a revert sorted + * linearisation list of used keys in the table. This method is called + * recursivley if defined nested tables. + * + * @param tableKey + * the name of the table definition + */ + private void readSigTable(String tableKey) + { + // System.err.println("read table:" + type_ + "." + tableKey); + String table_key_prefix = SignatureTypes.SIG_OBJ + type_ + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key."; + + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys != null) + { + for (int table_key_idx = 0; table_key_idx < table_def_keys.size(); table_key_idx++) + { + String table_row_id = (String) table_def_keys.get(table_key_idx); + String table_def_keys_name = table_key + "." + table_row_id; + String table_def_string = settings_.getValueFromKey(table_def_keys_name); + if (table_row_id.matches("\\D*")) + { + continue; + } + if (table_def_string != null) + { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + // ArrayList row = new ArrayList(); + int elem_idx = elems.length; + while (elem_idx > 0) + { + elem_idx--; + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) + { + return; + } + String key = key_type[0]; + String type = key_type[1]; + // System.err.println("key:" + type_ + "." + tableKey + + // "." + key + "=" + type); + + if (SignatureTypes.TYPE_TABLE.equals(key)) + { + // read sub table + readSigTable(type); + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) + { + // ignore images + } + if (SignatureTypes.TYPE_VALUE.equals(type)) + { + String sig_key_val = settings_.getValueFromKey(key_prefix + key); + if (sig_key_val != null) + { + revertSortedKeys_.add(key); + revertSortedCaptions_.add(sig_key_val); + } + // ignore values without caption + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION).equals(type) || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE).equals(type)) + { + String sig_key_val = settings_.getValueFromKey(key_prefix + key); + if (sig_key_val != null) + { + revertSortedKeys_.add(key); + revertSortedCaptions_.add(sig_key_val); + } + } + } + } + } + } + } + + /** + * @return Returns the keys. + */ + public Map getKeyCaptionMap() + { + return keyCaptionMap_; + } + + /** + * @return Returns the keyValueMap. + */ + public Map getKeyValueMap() + { + return keyValueMap_; + } + + /** + * Returns a caption to a given key + * + * @param key + * @return the caption or null if the key is not found + */ + public String getCaptionFromKey(String key) + { + return (String) keyCaptionMap_.get(key); + } + + /** + * Returns a value to given key + * + * @param key + * @return the value or null if the key is not found + */ + public String getValueFromKey(String key) + { + return (String) keyValueMap_.get(key); + } + + /** + * @return Returns the sortedKeys. + */ + public Vector getSortedKeys() + { + if (sortedKeys_ == null) + { + sortKeys(); + } + return sortedKeys_; + } + + /** + * @return Returns the sortedCaptions. + */ + public Vector getSortedCaptions() + { + if (sortedCaptions_ == null) + { + sortKeys(); + } + return sortedCaptions_; + } + + /** + * @return Returns the revertSortedCaptions. + */ + public Vector getRevertSortedCaptions() + { + return revertSortedCaptions_; + } + + /** + * @return Returns the revertSortedKeys. + */ + public Vector getRevertSortedKeys() + { + return revertSortedKeys_; + } + + /** + * This method sort the reverted sorted key-caption and key-value lists. + * + */ + private void sortKeys() + { + // String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key."; + sortedKeys_ = new Vector(revertSortedKeys_.size()); + sortedCaptions_ = new Vector(revertSortedCaptions_.size()); + for (int key_idx = revertSortedKeys_.size() - 1; key_idx >= 0; key_idx--) + { + sortedKeys_.add(revertSortedKeys_.get(key_idx)); + sortedCaptions_.add(revertSortedCaptions_.get(key_idx)); + } + } + + /** + * This method checks if a given key is defined. + * + * @param key + * to find + * @return true if the key is find false otherwise + */ + public boolean contains(String key) + { + return (keyValueMap_.get(key) != null); + } + + /** + * The standard toString method. Used for internal tests only. + */ + public String toString() + { + String strg = this.type_ + "\n"; + Vector sk = getSortedKeys(); + Vector sc = getSortedCaptions(); + for (int i = 0; i < sk.size(); i++) + { + strg += sk.get(i) + "=" + sc.get(i) + "\n"; + } + return strg; + } + + /** + * @return Returns the signature type string. + */ + public String getType() + { + return type_; + } + + /** + * @return Returns the signature type description. + */ + public String getDescription() + { + String descr_key = SignatureTypes.SIG_OBJ + type_ + ".description"; + return settings_.getValueFromKey(descr_key); + } + + protected String getSettingsKeyBase() + { + return getSettingsKeyBase(type_); + } + + /** + * Gets the field definition of the given Field. + * + * @param field_name + * The name of the field. + * @return Returns the field's definition. + */ + public SignatureFieldDefinition readFieldDefinition(String field_name) + { + SignatureFieldDefinition sfd = new SignatureFieldDefinition(); + + sfd.field_name = field_name; + sfd.caption = this.settings_.getValueFromKey(getSettingsKeyBase() + ".key." + field_name); + sfd.value = this.settings_.getValueFromKey(getSettingsKeyBase() + ".value." + field_name); + //sfd.value = this.settings_.getValueFromKey(getSettingsKeyBase() + type_ + ".value." + field_name); + sfd.placeholder_length = -1; + String phlen_str = readPhLenStringFromSettings(this.settings_, this.type_, field_name); + if (phlen_str != null) + { + sfd.placeholder_length = Integer.parseInt(phlen_str); + } + + return sfd; + } + + protected static String getSettingsKeyBase (String type) + { + return SignatureTypes.SIG_OBJ + type; + } + + public static String readPhLenStringFromSettings(SettingsReader settings, String profile, String field_name) + { + String phlen_str = settings.getValueFromKey(getSettingsKeyBase(profile) + ".phlength." + field_name); + if (phlen_str == null) + { + phlen_str = settings.getValueFromKey("defaults.phlength." + field_name); + } + return phlen_str; + } + + protected void readFieldDefinitions() + { + this.field_definitions_ = new HashMap(); + for (int i = 0; i < this.sortedKeys_.size(); i++) + { + String key = (String) this.sortedKeys_.get(i); + SignatureFieldDefinition sfd = readFieldDefinition(key); + // sfd.brev = SignatureTypes.ALL_SIG_BREV[i]; + this.field_definitions_.put(sfd.field_name, sfd); + } + } + + /** + * Returns the list of field definitions of this Signature profile. + * + * @return Returns the list of field definitions of this Signature profile. + */ + public List getFieldDefinitions() + { + return new ArrayList(this.field_definitions_.values()); + } + + /** + * Tells if this signature profile is semantically equal to the other + * signature profile. + * + *

+ * One profile is semantically equal to another one if the captions and keys + * of both profiles are equal and have the same order. + *

+ * + * @param other + * The other signature profile. + * @return Returns true, if this profile is semantically equivalent to the + * other profile. + */ + public boolean isSemanticallyEqual(SignatureTypeDefinition other) + { + List this_keys = filterOutNonRequiredFoundKeys(this.sortedKeys_); + List other_keys = filterOutNonRequiredFoundKeys(other.sortedKeys_); + + if (this_keys.size() != other_keys.size()) + { + return false; + } + + for (int i = 0; i < this_keys.size(); i++) + { + String this_key = (String) this_keys.get(i); + String other_key = (String) other_keys.get(i); + + if (!this_key.equals(other_key)) + { + return false; + } + + String this_caption = this.getCaptionFromKey(this_key); + String other_caption = other.getCaptionFromKey(other_key); + + if (!this_caption.equals(other_caption)) + { + return false; + } + } + + return true; + } + + /** + * Filters out all non required keys from the List of keys. + * + * @param keys The List of keys. + * + * @return Returns the subset List which contains only the required keys. + */ + protected static List filterOutNonRequiredFoundKeys (List keys) + { + List required_keys = new ArrayList(keys.size()); + for (int i = 0; i < keys.size(); i++) + { + String this_key = (String) keys.get(i); + + if (!SignatureTypes.isRequiredKey(this_key)) + { + continue; + } + + required_keys.add(this_key); + } + return required_keys; + } + + public SignatureFieldDefinition getSignatureFieldDefinition(String key) { + SignatureFieldDefinition res = (SignatureFieldDefinition) this.field_definitions_.get(key); + if (res == null) { + res = (SignatureFieldDefinition) this.invisible_field_definitions.get(key); + } + return res; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java new file mode 100644 index 0000000..783512c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java @@ -0,0 +1,515 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureTypes.java,v 1.5 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +public class SignatureTypes +{ + +// 03.11.2010 changed by exthex - commented unneeded setDefaultStyles method to reduce confusion + + /** + * The settings key prefix for signature definitions. "sig_obj." + */ + public static final String SIG_OBJ = "sig_obj."; + + /** + * The settings key prefix for signature object types + */ + public static final String TYPES = SIG_OBJ + "types"; + + /** + * The settings key prefix for the default signature object type + */ + public static final String DEFAULT_TYPE = SIG_OBJ + "type.default"; + + /** + * The settings key postfix for the type description + */ + public static final String SIG_DESCR = "description"; + + /** + * The state value activating an signature definition + */ + private static final String STATE_ON = "on"; + + // /** + // * The state value de activating an signature definition + // */ + // private static final String STATE_OFF = "off"; + + /** + * The settings key prefix for the signature table object definition + */ + public static final String TABLE = "table."; + + /** + * The settings key sub prefix getting the main table definition + */ + public static final String MAIN_TABLE = "main"; + + /** + * The settings value refering to a table + */ + public final static String TYPE_TABLE = "TABLE"; + + /** + * The settings value refering to an image + */ + public final static String TYPE_IMAGE = "i"; + + /** + * The settings value refering to a text caption + */ + public final static String TYPE_CAPTION = "c"; + + /** + * The settings value refering to a text value + */ + public final static String TYPE_VALUE = "v"; + + /** + * The settings key sub prefix getting the width of columns for a table + * definition + */ + public final static String COLS_WITH = "ColsWidth"; + + /** + * The settings key sub prefix getting the style definition + */ + public final static String STYLE = "Style"; + +// /** +// * The default style definition for images. +// */ +// private Style defaultImageStyle_ = new Style(); +// +// /** +// * The default style definition for captions. +// */ +// private Style defaultCaptionStyle_ = new Style(); +// +// /** +// * The default style definition for values. +// */ +// private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the singature name + */ + public static final String SIG_NAME = "SIG_NAME"; + + /** + * Standard key get/set the signature date + */ + public static final String SIG_DATE = "SIG_DATE"; + + /** + * Standard key get/set the signator issuer + */ + public static final String SIG_ISSUER = "SIG_ISSUER"; + + /** + * Standard key get/set the siganture value + */ + public static final String SIG_VALUE = "SIG_VALUE"; + + /** + * Standard key get/set the normalisation method used + */ + public static final String SIG_NORM = "SIG_NORM"; + + /** + * Standard key get/set the signation id's used by BKU signated documents + */ + public static final String SIG_ID = "SIG_ID"; + + /** + * The EGIZ Algorithm "Kennzeichnung". + */ + public static final String SIG_KZ = "SIG_KZ"; + + /** + * Standard key get/set the reference to the signature label (image mark) + */ + public static final String SIG_LABEL = "SIG_LABEL"; + + /** + * Standard key get/set the serial number of the signature + */ + public static final String SIG_NUMBER = "SIG_NUMBER"; + + // public static final String SIG_TYPE = "SIG_TYPE"; + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * Standard key get/set the signature algorithm (sign + hash) + */ + public static final String SIG_ALG = "SIG_ALG"; + + /** + * Standard key get/set the signature note + * added by rpiazzi + */ + public static final String SIG_NOTE = "SIG_NOTE"; + + + /** + * Standard key get/set the signature subject + * Added to be able to define static signator name within config file + * added by rpiazzi + */ + public static final String SIG_SUBJECT = "SIG_SUBJECT"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureTypes.class); + + // /** + // * The normalizer reference + // */ + // private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + + // /** + // * The current signature type used reading and analysing the property tree + // */ + // private String sigType_ = null; + + // /** + // * List of all keys used in the current signature definition + // */ + // private ArrayList sigKeys_ = null; + + /** + * Array of required signature keys + */ + // public static String[] REQUIRED_SIG_KEYS = new String[]{SIG_NAME, SIG_DATE, + // SIG_ISSUER, SIG_VALUE, SIG_NUMBER, SIG_ID}; + public static String[] REQUIRED_SIG_KEYS = new String[] { SIG_DATE, + SIG_ISSUER, SIG_VALUE, SIG_NUMBER, SIG_ID, SIG_KZ }; + + /** + * Tells, if the given key is a required key. + *

+ * Note that the SIG_KZ is a required key. + *

+ * @param key The key to be tested if it is a required key. + * @return Returns true, if the key is required, false otherwise. + */ + public static boolean isRequiredKey (String key) + { + if (key.equals(SIG_KZ)) + { + return true; + } + + for (int i = 0; i < REQUIRED_SIG_KEYS.length; i++) + { + if (key.equals(REQUIRED_SIG_KEYS[i])) + { + return true; + } + } + return false; + } + + public static String[] ALL_SIG_KEYS = new String[] { SIG_NAME, SIG_DATE, + SIG_ISSUER, SIG_VALUE, SIG_NORM, SIG_ID, SIG_LABEL, SIG_NUMBER, SIG_META , SIG_ALG, SIG_NOTE}; + + public static byte [][] ALL_SIG_BREV = new byte[][] { { 'n', 'a', 'm' }, + { 'd', 'a', 't' }, { 'i', 's', 's' }, { 'v', 'a', 'l' }, + { 'n', 'o', 'r' }, { 's', 'i', 'd' }, { 'l', 'a', 'b' }, + { 's', 'n', 'r' }, { 'm', 'e', 't' }, { 'a', 'l', 'g' } }; + + // /** + // * Sorted representation of keys defined in rows + // */ + // private ArrayList sortedSigKeys_ = new ArrayList(); + + // /** + // * Reference from signature key to there corresponding value + // */ + // private Hashtable sigEntries_ = new Hashtable(8); + +// /** +// * A list of all configured signature type definitions +// */ +// private List signatureTypeDefinitions_ = new Vector(); + + /** + * A type-name to type-definition map + */ + private Map typeDefMap_ = new HashMap(); + + // /** + // * A map of required keys used to reconstruct a signature block + // */ + // private static HashMap requiredSigKeys_ = new HashMap(); + + /** + * A plain list of signature type names + */ +// ArrayList typeList_ = new ArrayList(4); + + /** + * Used as singleton to read the singnature type definitions only one times of + * a session + */ + private static SignatureTypes instance_ = null; + + /** + * This is the private constructor method to provide a singleton instance of + * this class. It inits a normalizer, the settings reader, read the default + * styles and load the configured signature types. + * + * @throws SignatureTypesException + * @see SettingsReader + */ + private SignatureTypes() throws SignatureTypesException + { + try + { + loadSettings(); + } + catch (SettingsException e) + { + throw new SignatureTypesException(e); + } +// setDefaultStyles(); + loadSignatureTypes(); + } + + /** + * This static method returns the stored instance of this class. If the + * singleton does not exist, this method creates a new singleton and gives + * this instance back to the caller. + * + * @return the stored instance of this class + * @throws SignatureTypesException + */ + public static SignatureTypes getInstance() throws SignatureTypesException + { + if (instance_ == null) + { + instance_ = new SignatureTypes(); + } + return instance_; + } + + /** + * Reloads the instance. + * @throws SignatureTypesException + */ + public static void createInstance() throws SignatureTypesException + { + instance_ = null; + getInstance(); + } + + /** + * This method load the signature definitions + * + * @throws SettingsException + * + * @throws SettingsException + * ErrorCode:101 + */ + private void loadSettings() throws SettingsException + { + if (settings_ == null) + { + settings_ = SettingsReader.getInstance(); + } + // pTree_ = settings_.getPTree(); + } + +// /** +// * This method set the default styles for images, captions and values. +// */ +// private void setDefaultStyles() +// { +// defaultImageStyle_.setPadding(3); +// defaultImageStyle_.setHAlign(Style.CENTER); +// defaultImageStyle_.setVAlign(Style.MIDDLE); +// defaultImageStyle_.setBgColor(new Color(255, 255, 255)); +// +// defaultCaptionStyle_.setHAlign(Style.CENTER); +// defaultCaptionStyle_.setVAlign(Style.MIDDLE); +// +// defaultValueStyle_.setVAlign(Style.MIDDLE); +// } + + /** + * This method load the configured signature types. It stores the definition + * representations only if the type is set to ON. It stores the type + * definition object, the definition map and the simple type name list. + */ + private void loadSignatureTypes() + { + if (settings_ != null) + { + ArrayList types = settings_.getKeys(TYPES); + for (int type_idx = 0; type_idx < types.size(); type_idx++) + { + String type = (String) types.get(type_idx); + addSignatureType(type); + } + } + } + + public void removeSignatureType(String typeName) { + this.typeDefMap_.remove(typeName); + } + + /** + * Create and add {@link SignatureTypeDefinition} from its name + * @param typeName + */ + public void addSignatureType(String typeName) { + + if (STATE_ON.equals(settings_.getSetting(TYPES + "." + typeName, null))) + { + SignatureTypeDefinition sig_type_def; + try + { + sig_type_def = new SignatureTypeDefinition(settings_, typeName); + //signatureTypeDefinitions_.add(sig_type_def); + typeDefMap_.put(typeName, sig_type_def); + //typeList_.add(type); + } + catch (SignatureException e) + { + logger_.error(e.getMessage(), e); + } + } + } + + /** + * @return a arrayList (String) of signature types names + */ + public Set getSignatureTypes() + { + return this.typeDefMap_.keySet(); + } + + /** + * @return a list of signature type definitions + */ + public List getSignatureTypeDefinitions() + { + return new ArrayList(this.typeDefMap_.values()); + } + + /** + * This method returns the corresponding signature type definition to a given + * type key + * + * @param type + * the key to get the signature type definition + * @return the stored signature type definition + */ + public SignatureTypeDefinition getSignatureTypeDefinition(String type) + { + return (SignatureTypeDefinition) typeDefMap_.get(type); + } + + public static String convertBrevToType (final byte [] brev) + { + for (int i = 0; i < ALL_SIG_BREV.length; i++) + { + if (ByteArrayUtils.compareByteArrays(ALL_SIG_BREV[i], 0, brev)) + { + return ALL_SIG_KEYS[i]; + } + } + return null; + } + + public static byte [] convertTypeToBrev (final String type) + { + for (int i = 0; i < ALL_SIG_KEYS.length; i++) + { + if (ALL_SIG_KEYS.equals(type)) + { + return ALL_SIG_BREV[i]; + } + } + return null; + } + + public static boolean isRequredSigTypeKey(String name) { + return ArrayUtils.contains(REQUIRED_SIG_KEYS, name); + } + + /** + * The standard toString method. Used for testing only. + * + * @return the string representation of the class + */ + public String toString() + { + String strg = ""; + for (Iterator it = this.typeDefMap_.values().iterator(); it.hasNext();) { + SignatureTypeDefinition std = (SignatureTypeDefinition) it.next(); + + strg += "----------TYPE:" + std.getType() + "----------\n"; + strg += std.toString(); + } + return strg; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java new file mode 100644 index 0000000..7b4e463 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java @@ -0,0 +1,490 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: X509Cert.java,v 1.4 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.Serializable; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +public class X509Cert implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 6945327015386694557L; + + /** + * The x509 certificate binary string Base64 coded + */ + private String certString_ = null; + + /** + * The name value of the issuer + */ + private String issuerName_ = null; + + /** + * The serial number of the certificate + */ + private String serialNumber_ = null; + + /** + * The digest value of the certificate + */ + private String certDigest_ = null; + + /** + * The name value of the subject + */ + private String subjectName_ = null; + + /** + * The X509Certificate object + */ + private X509Certificate x509Cert_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(X509Cert.class); + + /** + * The empty constructor not acessible from outside --> use the static init + * methods instead + */ + private X509Cert() + { + } + + /** + * Normalize the base64 coded .cer or .der string. Remove the begin and end + * statement and remove all whitespaces in the string. The result string + * (base64) is used by reconstructing the certiface sign by the verification + * process. + * + * @param certString + * the string to normalize + * @return the normalized cert string + */ + private static String normalizeCertString(String certString) + { + certString = certString.replaceAll("-----BEGIN CERTIFICATE-----", ""); + certString = certString.replaceAll("-----END CERTIFICATE-----", ""); + certString = certString.replaceAll("\\s", ""); + return certString; + } + + /** + * This method initialzes a X509Certificate by a string value. It must be + * coded Base64 or as plain binary stream. + * + * @param certString + * the certificate string to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByString(String certString) + { + if (certString == null) + { + return null; + } + certString = normalizeCertString(certString); + X509Cert x509_cert = new X509Cert(); + x509_cert.setCertString(certString); + try + { + byte[] b64_dec = certString.getBytes("US-ASCII"); + if (CodingHelper.isB64(b64_dec)) + { + b64_dec = CodingHelper.decodeBase64(b64_dec); + } + else + { + b64_dec = CodingHelper.encodeBase64(b64_dec).getBytes("US-ASCII"); + } + ByteArrayInputStream bais = new ByteArrayInputStream(b64_dec); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (java.security.cert.CertificateException ce) + { + // nothing to do, cause certString is not X509 conformc + logger_.error(ce.getMessage(), ce); + } + catch (IOException ioe) + { + // nothing to do, cause certString is not X509 conform + logger_.error(ioe.getMessage(), ioe); + } + return x509_cert; + } + + public static X509Cert initByX509Certificate(X509Certificate cert) throws CertificateEncodingException { + X509Cert x509_cert = new X509Cert(); + x509_cert.setX509Cert(cert); + x509_cert.setCertString(CodingHelper.encodeBase64(cert.getEncoded())); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + return x509_cert; + } + + public static X509Cert initByByteArray(byte[] data) + { + X509Cert x509_cert = new X509Cert(); + try + { + ByteArrayInputStream bais = new ByteArrayInputStream(data); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (java.security.cert.CertificateException ce) + { + // nothing to do, cause certString is not X509 conformc + logger_.error(ce.getMessage(), ce); + + } + catch (IOException ioe) + { + // nothing to do, cause certString is not X509 conform + logger_.error(ioe.getMessage(), ioe); + } + + return x509_cert; + } + + /** + * This method initialzes a X509Certificate by a file path value. The file + * must be a plain binary file like .cer format. + * + * @param filePath + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFilePath(String filePath) + { + if (filePath == null) + { + return null; + } + X509Cert x509_cert = new X509Cert(); + try + { + FileInputStream fis = new FileInputStream(filePath); + X509Certificate cert = null; + try + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + cert = (X509Certificate) cf.generateCertificate(fis); + } + catch (java.security.cert.CertificateException ce) + { + fis.close(); + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + fis.close(); + x509_cert.setX509Cert(cert); + String cert_string = FileHelper.readFromFile(filePath); + x509_cert.setCertString(normalizeCertString(cert_string)); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (IOException ioe) + { + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + return x509_cert; + + } + + /** + * This method initialzes a X509Certificate by a file value. The file must be + * a plain binary file like .cer format. + * + * @param certFile + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFile(File certFile) + { + return initByFilePath(certFile.getAbsolutePath()); + } + + /** + * This method checks if a certificate file is X509 conform. + * + * @return true if a certificate file is X509 conform, false otherwise + */ + public boolean isX509Cert() + { + return x509Cert_ != null; + } + + /** + * @return Returns the certificate digest value. + * @deprecated Should not be used any more. + */ + public String getCertDigest() + { + if (certDigest_ == null) + { + if (certString_ != null) + { + byte[] cert_b64 = CodingHelper.decodeBase64(certString_); + String sigAlgName = this.x509Cert_.getSigAlgName(); + String digestAlg = sigAlgName.split("/")[0]; + if (sigAlgName.toLowerCase().indexOf("with") != -1 ) { + digestAlg = sigAlgName.substring(0,sigAlgName.toLowerCase().indexOf("with")); + } + byte[] cert_hash = CodingHelper.buildDigest(cert_b64, digestAlg); + certDigest_ = new String(CodingHelper.encodeBase64(cert_hash)); + } + } + return certDigest_; + } + + /** + * @return Returns the certificate Base64 binary string. + */ + public String getCertString() + { + return certString_; + } + + /** + * @return Returns the issuer string. + */ + public String getIssuerName() + { + return issuerName_; + } + + /** + * @return Returns the serial number. + */ + public String getSerialNumber() + { + return serialNumber_; + } + + /** + * @return Returns the real X509Certifcate object. + * @see X509Certificate + */ + public X509Certificate getX509Certificate() + { + return x509Cert_; + } + + /** + * @return Returns the subject name. + */ + public String getSubjectName() + { + return subjectName_; + } + + // /** + // * @param certDigest + // * The certDigest to set. + // */ + // private void setCertDigest(String certDigest) + // { + // certDigest_ = certDigest; + // } + + /** + * @param certString + * The certString to set. + */ + private void setCertString(String certString) + { + certString_ = certString; + } + + /** + * @param issuerString + * The issuerString to set. + */ + private void setIssuerName(String issuerString) + { + issuerName_ = issuerString; + } + + /** + * @param serialNumber + * The serialNumber to set. + */ + private void setSerialNumber(String serialNumber) + { + serialNumber_ = serialNumber; + } + + /** + * @param cert + * The x509Cert to set. + */ + private void setX509Cert(X509Certificate cert) + { + x509Cert_ = cert; + } + + /** + * @param subjectName + * The subjectName to set. + */ + private void setSubjectName(String subjectName) + { + subjectName_ = subjectName; + } + + public byte[] getTBSCertificate() throws CertificateEncodingException + { + return x509Cert_.getTBSCertificate(); + } + + public String getSigAlgName() + { + return x509Cert_.getSigAlgName(); + } + + public String getSigAlgOID() + { + return x509Cert_.getSigAlgOID(); + } + + public List getExtendedKeyUsage() + { + List list = null; + try + { + list = x509Cert_.getExtendedKeyUsage(); + } + catch (CertificateParsingException e) + { + logger_.error(e.getMessage(), e); + } + return null; + } + + /** + * @return the public key of the X509Certificate + */ + public PublicKey getPublicKey() + { + return x509Cert_.getPublicKey(); + } + + /** + * This method checks, if a X509Certificate has a public key with the rsa + * algorithm. + * + * @return true if the public key is produced with rsa, false otherwise + */ + public boolean isRSA() + { + return (x509Cert_.getPublicKey().getAlgorithm()).indexOf("RSA") >= 0; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java new file mode 100644 index 0000000..aab8e6b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java @@ -0,0 +1,63 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: A1Connector.java,v 1.2 2006/08/25 17:09:17 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; + +/** + * @author wprinz + */ +public class A1Connector extends BKUConnector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("a1", "A-1"); + + /** + * Constructor. + * + * @throws SignatureException + * F.e. + */ + public A1Connector() throws SignatureException + { + super(); + } + + /** + * Overrides the type of the BKUConnector to use the A1 settings. + */ + protected String getType() + { + return CONNECTOR_INFORMATION.getIdentifier(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java new file mode 100644 index 0000000..c3b6421 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java @@ -0,0 +1,896 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BKUConnector.java,v 1.5 2006/10/31 08:18:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.UnsupportedEncodingException; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connector for communicating with BKU. + * + * @deprecated use the new connectors. + * + * @author wlackner + * @author wprinz + */ +public class BKUConnector implements LocalConnector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("bku", "BKU"); + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BKUConnector.class); + + /** + * The empty constructor + */ + public BKUConnector() //throws SignatureException + { + //loadSettings(); + } + + /** + * load the inital signature settings + * + * @see SettingsReader + */ + public void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * This method calls the BKU signing a given text. The signaton type is to + * used initializing the corresponding SigantureObject. The initialized + * SignatureObject is filled out by the parsed BKU-Response.
+ * If an error request is send back from BKU, an error message is generated an + * an exception is thrown. + * + * @param sigType + * the type of the SignatureObject that should be returned + * @param userName + * the name of the user calling this method + * @param signText + * the text that shoulf be signed from BKU + * @return the complete SingatureObject of the given type filled by values + * from the BKU-Request + * @throws SignatureException + * @see SignatureObject + */ + public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException + { + String request_string = prepareSignRequest(userName, signText, sigType); + + String sign_url = getSignURL(sigType); + Properties response_properties = sendRequest(sign_url, request_string); + + return analyzeSignResponse(response_properties, sigType); + } + + /** + * This method generates the BKU verify prozess. It checks if the given + * SignatureObject is signed by MOA or BKU. The verify template string is + * filled out by the corresponding method. + * + * @param normalizedText + * the normalized text to verify + * @param sigObject + * the SignatureObject holding the singature values + * @return a SignatureResponse object if the verify prozess does not fails + * @throws SignatureException + * @see SignatureResponse + */ + public SignatureResponse doVerify(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String request_string = prepareVerifyRequest(normalizedText, sigObject); + + String verify_url = getVerifyURL(sigObject.getSignationType()); + Properties response_properties = sendRequest(verify_url, request_string); + + return analyzeVerifyResponse(response_properties); + } + + /** + * This method parses the BKU-Response string. It separates the + * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, + * X509Certificate, CertDigest, DigestValue and the signation id-s. If the + * X509Certificate is extracted it would be stored in the certificates + * directory. + * + * @param xmlResponse + * the response string from the BKU sign-request + * @param sigObj + * the SignatureObject that should be filled + * @throws SignatureException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + private void parseCreateXMLResponse(Properties response_properties, SignatureObject sigObj) throws SignatureException + { + String xmlResponse = response_properties.getProperty("response_string"); + + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); + Pattern sig_val_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + Pattern sig_cer_d_p_e = Pattern.compile(""); + Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + Pattern dig_val_p_e = Pattern.compile(""); + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + + String sig_val = ""; + String iss_nam = ""; + String ser_num = ""; + String sig_tim = ""; + String sig_cer = ""; + String sig_dig = ""; + + // SignatureValue + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start()); + sig_val = sig_val.replaceAll("\\s", ""); + sigObj.setSignationValue(sig_val); + } + // X509IssuerName + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sigObj.setSignationIssuer(iss_nam); + } + // X509SerialNumber + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sigObj.setSignationSerialNumber(ser_num); + } + // SigningTime + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + sigObj.setSignationDate(sig_tim); + } + // CertDigest + if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + { + String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start()); + Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest); + Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest); + if (dig_val_m_s.find() && dig_val_m_e.find()) + { + sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + sigObj.setX509CertificateDigest(sig_dig); + } + } + // extract Subject Name from X509Certificate + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + sig_cer = sig_cer.replaceAll("\\s", ""); + sigObj.setX509Certificate(sig_cer); + X509Cert cert = X509Cert.initByString(sig_cer); + if (cert.isX509Cert()) + { + sigObj.setX509Certificate(cert.getCertString()); + String serial_num = cert.getSerialNumber(); + String subject_name = cert.getSubjectName(); + if (!ser_num.equals(serial_num)) + { + SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!"); + throw se; + } + sigObj.setSignationName(subject_name); + } + } + + // extract Signature Id's + String[] ids = new String[5]; + ids[0] = extractId(xmlResponse, "signature-"); + ids[1] = extractId(xmlResponse, "signed-data-reference-"); + ids[2] = extractId(xmlResponse, "signed-data-object-"); + ids[3] = extractId(xmlResponse, "etsi-data-reference-"); + ids[4] = extractId(xmlResponse, "etsi-data-object-"); + + //TODO hotfix - already deprecated + String final_ids =SignatureObject.formatSigIds(response_properties, ids); + //sigObj.setSignationIDs(ids); + sigObj.setSignationIDs(final_ids); + } + + /** + * This emthod extracts id-values from a text. The id is given by the name. + * + * @param text + * the id-value that should extract from + * @param name + * the id-key + * @return the value of the given key in the text + */ + private String extractId(String text, String name) + { + String id = null; + int start_idx = text.indexOf(name) + name.length(); + int end_idx = text.indexOf("\"", start_idx); + + // TODO hotfix! - already deprecated + final int quot_end_idx = end_idx; + final int squot_end_idx = text.indexOf("'", start_idx); + end_idx = Math.min(quot_end_idx, squot_end_idx); + // TODO hotfix end! - already deprecated + + id = text.substring(start_idx, end_idx); + if (logger_.isDebugEnabled()) + { + logger_.debug("extract id:" + name + id); + } + return id; + } + + /** + * This method reads the verify template from the file system and fills out + * the template with the SignatureObject values. + * + * @param normalizedText + * the normalized text to veryfied + * @param sigObject + * the SignatureObject holding the singature values + * @return the filled verify template string + * @throws SignatureException + * ErrorCode (311, 312, 313) + * @see SignatureObject + * @see CodingHelper + */ + public String getVerifyTemplate(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + try + { + if (normalizedText == null || normalizedText.length() == 0) + { + SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty."); + throw se; + } + if (sigObject == null) + { + SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set."); + throw se; + } + + String verify_template = getVerifyTemplateFileName(sigObject.getSignationType()); + String sig_prop_filename = getSigPropFileName(sigObject.getSignationType()); + + String ids_string = sigObject.getSignationIds(); + logger_.debug("ids_string = " + ids_string); + String[] ids = SignatureObject.parseSigIds(ids_string); + + // TODO hotfix - already deprecated + final boolean neue_bku = ids[5] != null; + logger_.debug("ids[5] = " + ids[5]); + logger_.debug("neue_bku = " + neue_bku); + if (neue_bku) + { + verify_template = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2"); //"./templates/BKUVerifyTemplateB64_neueBKU.xml"; + sig_prop_filename = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2.SP"); //"./templates/BKUVerifyTemplateSP_neueBKU.xml"; + } + + + //String ver_temp_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); + String ver_temp_str = this.settings_.readInternalResourceAsString(verify_template); + //String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_filename)); + String sig_prop_str = this.settings_.readInternalResourceAsString(sig_prop_filename); + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_template); + logger_.debug(sig_prop_filename); + } + + String x509_cert_string = sigObject.getX509CertificateString(); + if (x509_cert_string == null) + { + SignatureException se = new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "Document certificate is not defined."); + throw se; + } + String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa"); + X509Cert x509_cert = sigObject.getX509Cert(); + if (x509_cert.isRSA()) + { + cert_alg = settings_.getValueFromKey("cert.alg.rsa"); + } + + sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); + + String issuer_name = sigObject.getSignationIssuer(); + // The issuer is already unicode, so it mustn't be encoded again. + //byte[] issuer_name = CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); + // new String(issuer_name); // this would double encode the String, not to mention the missing encoding + sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", issuer_name); + + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); + sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); + sig_prop_str = sig_prop_str.replaceFirst("SigIdReplace", ids[0]); + sig_prop_str = sig_prop_str.replaceFirst("SigDataRefReplace", ids[1]); + + ver_temp_str = ver_temp_str.replaceFirst("CertAlgReplace", cert_alg); + ver_temp_str = ver_temp_str.replaceFirst("TemplateQualifyingPropertiesReplace", sig_prop_str); + byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"), "sha1"); + + // TODO hotfix - already deprecated + if (neue_bku) + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = sig_prop_str.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = sig_prop_str.substring(hash_start, hash_end); + logger_.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); + + logger_.debug("\n--------------------- ETSI properties string to be hashed: start ---------------------"); + logger_.debug(string_to_be_hashed); + logger_.debug("\n--------------------- ETSI properties string to be hashed: stop ---------------------"); + + final byte [] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); + sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, "sha1"); + } + + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from QualifyingProperties:start"); + //logger_.debug("DATA :" + sig_prop_str); + logger_.debug("DIGEST:" + sig_prop_hash); + logger_.debug("build digest from QualifyingProperties:end"); + } + + ver_temp_str = ver_temp_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue()); + ver_temp_str = ver_temp_str.replaceFirst("X509CertificateReplace", x509_cert_string); + byte[] data_value = normalizedText.getBytes("UTF-8"); + byte[] data_value_hash = CodingHelper.buildDigest(data_value, "sha1"); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + // String object_data = new String(data_value); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from data object:start"); + //logger_.debug("DATA :" + normalizedText); + logger_.debug("DIGEST:" + object_data_hash); + logger_.debug("build digest from data object:end"); + } + + //String raw_b64 = CodingHelper.encodeUTF8AsBase64(normalizedText); + String raw_b64 = CodingHelper.encodeBase64(data_value); + + ver_temp_str = ver_temp_str.replaceFirst("Base64ContentReplace", raw_b64); + ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); + + ver_temp_str = ver_temp_str.replaceAll("SigIdReplace", ids[0]); + ver_temp_str = ver_temp_str.replaceAll("SigDataRefReplace", ids[1]); + ver_temp_str = ver_temp_str.replaceAll("SigDataObjURIReplace", ids[2]); + ver_temp_str = ver_temp_str.replaceAll("EtsiDataRefReplace", ids[3]); + ver_temp_str = ver_temp_str.replaceAll("EtsiDataObjURIReplace", ids[4]); + if (logger_.isDebugEnabled()) + { + //logger_.debug("VERIFY REQUEST:" + ver_temp_str); + } + + return ver_temp_str; + } + catch (UnsupportedEncodingException e) + { + throw new SignatureException(310, e); + } + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the BKU-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + private SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + if (logger_.isInfoEnabled()) + { + logger_.info("Try parsing the verify response"); + } + + Pattern sub_nam_p_s = Pattern.compile(""); + Pattern sub_nam_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile(""); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile(""); + Pattern ser_num_p_e = Pattern.compile(""); + + Pattern sig_chk_p_s = Pattern.compile(""); + Pattern sig_chk_p_e = Pattern.compile(""); + Pattern man_chk_p_s = Pattern.compile(""); + Pattern man_chk_p_e = Pattern.compile(""); + Pattern cer_chk_p_s = Pattern.compile(""); + Pattern cer_chk_p_e = Pattern.compile(""); + + // [tknall] start qualified certificate + Pattern cert_qualified_p = Pattern.compile(""); + Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); + // [tknall] stop qualified certificate + + Pattern code_p_s = Pattern.compile(""); + Pattern code_p_e = Pattern.compile(""); + Pattern info_p_s = Pattern.compile(""); + Pattern info_p_e = Pattern.compile(""); + + Pattern cert_p_s = Pattern.compile(""); + Pattern cert_p_e = Pattern.compile(""); + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + SignatureResponse sig_res = new SignatureResponse(); + + // [tknall] start qualified certificate + sig_res.setQualifiedCertificate(cert_qualified_m.find()); + // [tknall] stop qualified certificate + + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + Matcher info_m_s = info_p_s.matcher(sig_chk); + Matcher info_m_e = info_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = sig_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureCheckInfo(info); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + Matcher info_m_s = info_p_s.matcher(man_chk); + Matcher info_m_e = info_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = man_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureManifestCheckInfo(info); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + Matcher info_m_s = info_p_s.matcher(cer_chk); + Matcher info_m_e = info_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = cer_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setCertificateCheckInfo(info); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + return sig_res; + } + + + + public String prepareSignRequest(String userName, String signText, + String signType) throws SignatureException + { + if (logger_.isInfoEnabled()) + { + logger_.info("Call " + getType() + " connector from user:" + userName); + } + String keybox_identifier = getSignKeyboxIdentifier(signType); + String sign_request_filename = getSignRequestTemplateFileName(signType); + + //String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + String sign_req_str = this.settings_.readInternalResourceAsString(sign_request_filename); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_signText.xml :" + signText); + } + String raw_b64 = CodingHelper.encodeUTF8AsBase64(signText); + if (sign_req_str == null || raw_b64 == null) + { + throw new SignatureException(300, "Can not read the create xml request template"); + } + sign_req_str = sign_req_str.replaceFirst("KeyboxIdentifierReplace", keybox_identifier); + sign_req_str = sign_req_str.replaceFirst("Base64ContentReplace", raw_b64); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_request.xml :"+ sign_req_str); + } + + return sign_req_str; + } + + public String prepareVerifyRequest(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); + + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); + String verify_req_str = this.settings_.readInternalResourceAsString(verify_request); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request); + } + + String verify_template_str = null; + if (sigObject.isMOASigned()) + { + MOAConnector moa_conn = new MOAConnector(); + // get the MOA-template + verify_template_str = moa_conn.getVerifyTemplate(normalizedText, sigObject); + } + else + { + // get the BKU-template + verify_template_str = getVerifyTemplate(normalizedText, sigObject); + } + verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + if (logger_.isDebugEnabled()) + { + logger_.debug("verify_req_str.xml : " + verify_req_str); + } + + return verify_req_str; + } + + /** + * Sends the request to the given URL. + * + * @param url + * The URL. + * @param request_string + * The request string. + * @return Returns the response string. + * @throws SignatureException + * F.e. + */ + protected Properties sendRequest(String url, String request_string) throws SignatureException + { + try + { + Properties response_properties = BKUPostConnection.doPostRequest(url, request_string); + return response_properties; + } + catch (Exception e) + { + SignatureException se = new SignatureException(320, e); + throw se; + } + } + + public SignatureObject analyzeSignResponse(Properties response_properties, + String sigType) throws SignatureException + { + //String sign_request_filename = getSignRequestTemplateFileName(sigType); + + // TODO hotfix - already deprecated + String response_string = response_properties.getProperty("response_string"); + + SignatureObject sig_obj = new SignatureObject(); + sig_obj.setRawSignatureResponse(response_string); + try + { + sig_obj.setSigType(sigType); + sig_obj.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(300, "Cannot init signature object with type:" + sigType, e); + throw se; + } + if (logger_.isDebugEnabled()) + { + logger_.debug("Signature Type is:" + sig_obj.getSignationType()); + } + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + // System.err.println(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(sign_request_filename + "_response.xml : " + response_string); + logger_.error("BKU Error response: " + response_string); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + logger_.debug("signature_response_string: " + response_string); + } + parseCreateXMLResponse(response_properties, sig_obj); + } + } + sig_obj.setSigResponse(response_string); + return sig_obj; + } + + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException + { + String response_string = response_properties.getProperty("response_string"); + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(getType() + "_response.xml : " + response_string); + logger_.error(getType() + "_response.xml : " + response_string); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = null; + if (erc_m_s.find() && erc_m_e.find()) + { + error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + } + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(getType() + "_response.xml : " + response_string); + } + return parseVerifyXMLResponse(response_string); + } + } + return null; + } + + protected String getConnectorValueFromProfile(String profile, String key) + { + String value = settings_.getValueFromKey("sig_obj." + profile + "." + key); + if (value == null) + { + value = settings_.getValueFromKey(key); + } + return value; + } + + public String getSignURL(String profile) + { + final String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignRequestTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignKeyboxIdentifier(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".KeyboxIdentifier"; + return getConnectorValueFromProfile(profile, key); + } + + public String getVerifyURL(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyRequestTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSigPropFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template.SP"; + return getConnectorValueFromProfile(profile, key); + } + + /** + * Returns the type of this BKU-like connector. + * + *

+ * All settings keys will be prefixed by this type. So to reuse the BKU + * connector, a deriving class has to implement this method specifying an own + * type. + *

+ * + * @return Returns the type of this BKU-like connector. + */ + protected String getType() + { + return CONNECTOR_INFORMATION.getIdentifier(); + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java new file mode 100644 index 0000000..b676ed8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java @@ -0,0 +1,157 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BKUPostConnection.java,v 1.3 2006/10/11 07:56:10 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.IOException; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * @author wprinz + */ +public abstract class BKUPostConnection +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BKUPostConnection.class); + + /** + * This method connects the BKU server getting the request and the url. The + * request is an XML Message send and recieve by the HttpClient module. The + * Response message of the BKU server is is send back to the calling method. + * + * @param url + * the URL which the BKU server is running + * @param request + * the request string (XML) to send. + * @return the response string (XML) of the BKU server + * @throws IOException + * @throws HttpException + * ErrorCode:320 + */ + public static Properties doPostRequest(String url, String request) throws HttpException, IOException + { + + PostMethod post_method = new PostMethod(url); + + // It is very important to specify the charset of the content (the request) + // as UTF-8 this way. + // The HttpClient will then perform the URL encoding assuming that the + // request is UTF-8 as the BKU expects. + // If the MethodParams are omitted, the HttpClient will assume that the + // request is ISO-8859-1 and thereby the BKU cannot properly decode it. + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); + post_method.setParams(method_params); + + // This is just a hint: do not set the content-type this way or the BKU will + // assume it as text/XML, but the HttpClient sends it as URL-encoded. + // The HttpClient will automatically generate the proper Content-Type: + // application/x-www-form-urlencoded + // post.addRequestHeader(new Header("Content-Type", + // "text/xml;charset=UTF-8")); + + NameValuePair[] data = { new NameValuePair("XMLRequest", request) }; + post_method.setRequestBody(data); + + HttpClient http_client = new HttpClient(); + int method_response = http_client.executeMethod(post_method); + logger_.debug("method_response = " + method_response); + + Properties response_properties = new Properties(); + + if (logger_.isDebugEnabled()) + { + Header[] response_headers = post_method.getResponseHeaders(); + logger_.debug("#" + response_headers.length + " headers in response:"); + for (int i = 0; i < response_headers.length; i++) + { + logger_.debug(" response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue()); + } + } + + Header server_header = post_method.getResponseHeader("Server"); + logger_.debug("server_header: name = " + server_header.getName() + ", value = " + server_header.getValue()); + + parseBKUVersion(server_header.getValue(), response_properties); + + + byte[] response_body = post_method.getResponseBody(); + String response_string = new String(response_body, "UTF-8"); + + // Alternatively this could be used. + // The HttpClient is assumed to use the Content-Type provided by the + // response. + // String response_string = post.getResponseBodyAsString(); + + response_properties.setProperty("response_string", response_string); + + return response_properties; + } + + // TODO hotfix + public static void parseBKUVersion(String header_value, Properties properties) + { + // dummy bku header starts with Apache Coyote... + //Pattern pattern = Pattern.compile("^citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)$"); + //Pattern pattern = Pattern.compile("^.*citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)$"); + Pattern pattern = Pattern.compile("^.*citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)(.*)$"); + Matcher m = pattern.matcher(header_value); + + m.matches(); + + logger_.debug("group count = " + m.groupCount()); + + for (int i = 0; i <= m.groupCount(); i++) + { + logger_.debug(" group[" + i + "] = " + m.group(i)); + } + + final String cceVersion = m.group(1); + final String productName = m.group(2); + final String productVersion = m.group(3); + + logger_.debug("cceVersion = " + cceVersion); + logger_.debug("productName = " + productName); + logger_.debug("productVersion = " + productVersion); + + properties.setProperty("cceVersion", cceVersion); + properties.setProperty("productName", productName); + properties.setProperty("productVersion", productVersion); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java new file mode 100644 index 0000000..24dd728 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java @@ -0,0 +1,77 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * @author wprinz + * + */ +public interface Connector +{ +//23.11.2010 changed by exthex - added reconstructXMLDsig(SignatureData data, SignSignatureObject so) + + /** + * Performs a sign. + * + * @param data + * The data to be signed. + * @return Returns the signature object containing the signature data. + * @throws ConnectorException + * Thrown if something goes wrong. + */ + + public SignSignatureObject doSign(SignatureData data) throws ConnectorException; + + /** + * Performs a verification. + * + * @param data + * The data to be verified. + * @param so + * The signature object with the signature information. + * @param dsig + * The xmldsig info which will be enveloped in the verify request. + * @return Returns the SignatureResponse with the result of the verification. + * @throws ConnectorException + * Thrown if something goes wrong. + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException; + + /** + * Reconstruct the xmldsig info of the given {@link SignSignatureObject} + * + * @param data + * @param so + * @return + * @throws ConnectorException + */ + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java new file mode 100644 index 0000000..2fee4da --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java @@ -0,0 +1,353 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.LocRefDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.MultipartDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; + +/** + * Helper class that provides static methods that help the application to + * "choose" the right connector for a given task. + * + * @deprecated functionality split to ConnectorChooser implementations in framework commandline and web + * + * @author wprinz + */ +public final class ConnectorChooser +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(ConnectorChooser.class); + + public static LocalConnector chooseLocalConnectorForSign(String connector, + String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing LocalConnector for signation..."); + + log.debug("connector type = " + connector); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + + if (Constants.SIGNATURE_DEVICE_MOC.equals(connector)) { + + return new LocRefDetachedMOCCAConnector(cp, loc_ref_url); + + } else if (Constants.SIGNATURE_DEVICE_BKU.equals(connector)){ + + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + + } + + log.error("Currently only the BKU connector is fully implemented."); + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + + public static Connector chooseWebConnectorForSign(String connector, + String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing Connector for WEB signation..."); + + log.debug("connector type = " + connector); + + if (!connector.equals(Constants.SIGNATURE_DEVICE_MOA)) + { + log.error("Currently only the MOA connector is available for non local WEB signation."); + } + + log.debug("choosing locref detached MOA connector."); + + //TODO TR: Hier umschalten, um von SwA-Requests zurueckzuwechseln. + // Loc_Ref-Connector +// return new DetachedLocRefMOAConnector(profile, loc_ref_url); + // SwA-Connector + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new MOASoapWithAttachmentConnector(cp); + } + +// public static Connector chooseCommandlineConnectorForSign(String connector, +// String profile) throws ConnectorException +// { +// log.debug("Choosing Connector for commandline signation..."); +// +// log.debug("connector type = " + connector); +// +// if (connector.equals(BKU)) +// { +// log.debug("sig_app is BKU ==> MultipartDetachedBKUConnector"); //$NON-NLS-1$ +// +// return new MultipartDetachedBKUConnector(profile); +// } +// if (connector.equals(MOA)) +// { +// // TODO MOA detached signing is not allowed at the commandline +// log.warn("Detached MOA is not supported on the commandline. -> choosing Base64 temporarily."); +// return new EnvelopingBase64MOAConnector(profile); +// } +// +// throw new ConnectorException(300, "Unknown connector type '" + connector + "' specified."); +// } + + public static LocalConnector chooseLocalConnectorForVerify(String connector, + PdfASID sig_kz, String sig_id, String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing LocalConnector for verification..."); + + log.debug("connector type = " + connector); + log.debug("sig_kz = " + sig_kz); + log.debug("sig_id = " + sig_id); + + if (!connector.equals("bku")) + { + log.error("Currently only the BKU connector is fully implemented."); + } + + if (sig_kz == null) + { + log.debug("sig_kz is null -> must be old signature -> choosing old Base64 connector."); + + return new OldEnvelopingBase64BKUConnector(profile); + } + + log.debug("sig_kz is not null -> must be one of the newer ... base64, base64 hotfix, or detached"); + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + log.debug("sig_kz version is 1.0.0 -> choosing base64 (old or hotfix)"); + + if (sig_id == null) + { + log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter)."); + + return new EnvelopedBase64BKUConnector(profile); + } + + String[] sig_id_parts = sig_id.split("@"); + if (sig_id_parts.length == 2) + { + log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector"); + + return new OldEnvelopingBase64BKUConnector(profile); + } + if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX)) + { + log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector"); + + return new EnvelopedBase64BKUConnector(profile); + } + + throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); + } + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0) || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_2_0)) + { + log.debug("sig_kz version is 1.1.0/1.2.0 -> choosing detached (loc ref) connector."); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown. Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + + public static Connector chooseWebConnectorForVerify(String connector, + PdfASID sig_kz, String sig_id, String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing Connector for WEB verification..."); + + log.debug("connector type = " + connector); + log.debug("sig_kz = " + sig_kz); + log.debug("sig_id = " + sig_id); + + if (!connector.equals("moa")) + { + log.error("Currently only the MOA connector is available for non local WEB signation."); + } + + if (sig_kz == null || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + log.debug("sig_kz is null or sig_kz version is 1.0.0 -> choosing Base64 connector."); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new EnvelopingBase64MOAConnector(cp); + } + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0) || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_2_0)) + { + log.debug("sig_kz version is 1.1.0/1.2.0 -> choosing detached (loc ref) connector."); + + //throw new ConnectorException(ErrorCode.DETACHED_SIGNATURE_NOT_SUPPORTED, "The MOA detached connector is not suitable for verification."); + // TODO TR: Switch her for SwA or Detached-URL Connector + // the following line is used in connection with LocRef-Connector +// return new DetachedLocRefMOAConnector(profile, loc_ref_url); + // the following line is uesed in connection with SwA-Connector + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new MOASoapWithAttachmentConnector(cp); + } + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown. Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + +// public static Connector chooseCommandlineConnectorForVerify(String connector, +// PdfASID sig_kz, String sig_id, String profile) throws ConnectorException +// { +// log.debug("Choosing Connector for Commandline verification..."); +// +// log.debug("connector type = " + connector); +// log.debug("sig_kz = " + sig_kz); //$NON-NLS-1$ +// log.debug("sig_id = " + sig_id); //$NON-NLS-1$ +// +// if (sig_kz == null) +// { +// log.debug("sig_kz is null -> chose an old enveloped base64 connector"); //$NON-NLS-1$ +// +// return chooseEnvelopedBase64ConnectorOld(profile, connector); +// } +// +// log.debug("sig_kz is not null -> one of the newer signatures"); +// +// if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) +// { +// log.debug("Version is 1.0.0 -> Base64 Signatur (old or Hotfix)."); +// +// if (sig_id == null) +// { +// log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter)."); +// +// return chooseEnvelopedBase64ConnectorHotfix(profile, connector); +// } +// +// String[] sig_id_parts = sig_id.split("@"); +// if (sig_id_parts.length == 2) +// { +// log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector"); +// +// return chooseEnvelopedBase64ConnectorOld(profile, connector); +// } +// if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX)) +// { +// log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector"); +// +// return chooseEnvelopedBase64ConnectorHotfix(profile, connector); +// } +// +// throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); +// } +// if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0)) +// { +// log.debug("Version is 1.1.0 -> chose a detached connector."); +// +// return chooseDetachedMultipartConnector(profile, connector); +// } +// +// throw new ConnectorException(310, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown."); +// } + + protected static final String BKU = "bku"; //$NON-NLS-1$ + + protected static final String MOA = "moa"; //$NON-NLS-1$ + + protected static Connector chooseEnvelopedBase64ConnectorOld(String profile, + String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> OldEnvelopingBase64BKUConnector"); //$NON-NLS-1$ + + return new OldEnvelopingBase64BKUConnector(profile); + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> EnvelopingBase64MOAConnector"); //$NON-NLS-1$ + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new EnvelopingBase64MOAConnector(cp); + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + protected static Connector chooseEnvelopedBase64ConnectorHotfix( + String profile, String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> EnvelopedBase64BKUConnector"); //$NON-NLS-1$ + + return new EnvelopedBase64BKUConnector(profile); + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> EnvelopedBase64MOAConnector"); //$NON-NLS-1$ + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new EnvelopingBase64MOAConnector(cp); + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + protected static Connector chooseDetachedMultipartConnector(String profile, + String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> DetachedMultipartBKUConnector"); //$NON-NLS-1$ + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new MultipartDetachedBKUConnector(cp); + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> DetachedMOAConnector"); //$NON-NLS-1$ + + String msg = "A Detached signature cannot be verified with the MOA connector (yet)."; //$NON-NLS-1$ + log.error(msg); + throw new ConnectorException(ErrorCode.DETACHED_SIGNATURE_NOT_SUPPORTED, msg); + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java new file mode 100644 index 0000000..fa340cd --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java @@ -0,0 +1,55 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +/** + * This class contains the key constants used by the Connectors to retrieve + * templates etc. from the Configuration. + * + * @author wprinz + */ +public abstract class ConnectorConfigurationKeys +{ + + /** + * 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 key used to read out the available for web property. + */ + public static final String AVAILABLE_FOR_WEB = "available_for_web"; + + /** + * The key used to read out the available for commandline property. + */ + public static final String AVAILABLE_FOR_COMMANDLINE = "available_for_commandline"; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java new file mode 100644 index 0000000..451f367 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java @@ -0,0 +1,52 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.security.cert.X509Certificate; + +/** + * Base class for connector environments + * + * @author dferbas + * + */ +public abstract class ConnectorEnvironment { + + public abstract String getCertAlgEcdsa(); + + public abstract String getCertAlgRsa(); + + public abstract String getVerifyTemplate(); + + public String getDefaultAlgForCert(X509Certificate cert) { + String cert_alg; + cert_alg = getCertAlgEcdsa(); + if (cert.getPublicKey().getAlgorithm().indexOf("RSA") >= 0) //$NON-NLS-1$ + { + cert_alg = getCertAlgRsa(); + } + return cert_alg; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java new file mode 100644 index 0000000..5279a03 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java @@ -0,0 +1,91 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.util.Properties; + +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * @author wprinz + */ +public interface LocalConnector +{ +//23.11.2010 changed by exthex - added XMLDsigData parameter to prepareVerifyRequest to allow reuse + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException; + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException; + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @param dsigData + * The previously recreated xmldsig block of the signature + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException; + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java new file mode 100644 index 0000000..ef355a0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java @@ -0,0 +1,921 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: MOAConnector.java,v 1.5 2006/10/31 08:18:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.exceptions.WebException; +import at.knowcenter.wag.egov.egiz.sig.Connector; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connector to access the MOA service. + * + * @deprecated + * @author wlackner + * @author wprinz + */ +public class MOAConnector implements Connector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("moa", "MOA"); + + /** + * The class type value. + * + *

+ * Just for convenience. + *

+ */ + private static final String TYPE = CONNECTOR_INFORMATION.getIdentifier(); + + /** + * The connector description. + */ + public static final String DESCRIPTION = "MOA"; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * MOA siganture verification mode + */ + public static final String SERVICE_VERIFY = "SignatureVerification"; + + /** + * MOA siganture creation mode + */ + public static final String SERVICE_SIGN = "SignatureCreation"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(MOAConnector.class); + + /** + * The empty constructor + */ + public MOAConnector() throws SignatureException + { + loadSettings(); + } + + /** + * load the inital signature settings + * + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * This method calls the MOA signing a given text. The signaton type is to + * used initializing the corresponding SigantureObject. The initialized + * SignatureObject is filled out by the parsed MOA-Response.
+ * If an error request is send back from MOA, an error message is generated an + * an exception is thrown. + * + * @param sigType + * the type of the SignatureObject that should be returned + * @param userName + * the name of the user calling this method + * @param signText + * the text that shoulf be signed from MOA + * @return the complete SingatureObject of the given type filled by values + * from the MOA-Request + * @throws SignatureException + * ErrorCode 300 + * @see SignatureObject + */ + public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException + { + SignatureObject sig_obj = new SignatureObject(); + try + { + sig_obj.setSigType(sigType); + sig_obj.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(300, "Can ot init signature object with type:" + sigType, e); + throw se; + } + if (logger_.isDebugEnabled()) + { + logger_.debug("Signature Type is:" + sig_obj.getSignationType()); + } + if (logger_.isInfoEnabled()) + { + logger_.info("Call " + TYPE + " from user:" + userName); + } + + String url = getSignURL(sigType); + + String sign_request_filename = getSignRequestTemplateFileName(sigType); + String key_ident = getSignKeyIdentifier(sigType); + + //String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + String sign_req_str = this.settings_.readInternalResourceAsString(sign_request_filename); + if (sign_req_str == null) + { + SignatureException se = new SignatureException(300, "File not found:" + sign_request_filename); + throw se; + } + + sign_req_str = sign_req_str.replaceFirst("KeyIdentifierReplace", key_ident); + if (logger_.isDebugEnabled()) + { + //logger_.debug("error_signature_response = " + sign_req_str); + // FileHelper.writeToFile(sign_request_filename + "_signText.xml", + // signText); + } + // sign_req_str = sign_req_str.replaceFirst("XMLContentReplace", signText); + // now use the the base64 Template + signText = CodingHelper.encodeUTF8AsBase64(signText); + sign_req_str = sign_req_str.replaceFirst("Base64ContentReplace", signText); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_req_str); + // FileHelper.writeToFile(sign_request_filename + "_request.xml", + // sign_req_str); + } + + String response_string = ""; + try + { + response_string = MOAConnector.connectMOA(sign_req_str, MOAConnector.SERVICE_SIGN, url); + sig_obj.setRawSignatureResponse(response_string); + } + catch (WebException we) + { + SignatureException se = new SignatureException(we.getErrorCode(), we); + throw se; + } + + if (!response_string.equals("")) + { + if (logger_.isInfoEnabled()) + { + logger_.info("get MOA response"); + } + Pattern erc_p_s = Pattern.compile(""); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + // System.err.println(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("error_signature_response = " + response_string); + // FileHelper.writeToFile(sign_request_filename + "_response.xml", + // response_string); + //logger_.error("Write error response to file:" + sign_request_filename + "_response.xml"); + } + Pattern erm_p_s = Pattern.compile(""); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + logger_.debug("error_code = " + error_code); + String error_mess = ""; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + logger_.debug(error_mess); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug("response_string = " + response_string); + // FileHelper.writeToFile(sign_request_filename + "_response.xml", + // response_string); + } + parseCreateXMLResponse(response_string, sig_obj); + } + } + sig_obj.setSigResponse(response_string); + return sig_obj; + } + + /** + * This method parses the MOA-Response string. It separates the + * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, + * X509Certificate, CertDigest and DigestValues. If the X509Certificate is + * extracted it would be stored in the certificates directory. + * + * @param xmlResponse + * the response string from the MOA sign-request + * @param sigObj + * the SignatureObject that should be filled + * @throws SignatureException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + private void parseCreateXMLResponse(String xmlResponse, SignatureObject sigObj) throws SignatureException + { + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); + Pattern sig_val_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + Pattern sig_cer_d_p_e = Pattern.compile(""); + Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + Pattern dig_val_p_e = Pattern.compile(""); + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + + String sig_val = ""; + String iss_nam = ""; + String ser_num = ""; + String sig_tim = ""; + String sig_cer = ""; + String sig_dig = ""; + + // SignatureValue + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start()); + sig_val = sig_val.replaceAll("\\s", ""); + sigObj.setSignationValue(sig_val); + } + // X509IssuerName + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sigObj.setSignationIssuer(iss_nam); + } + // X509SerialNumber + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sigObj.setSignationSerialNumber(ser_num); + } + // SigningTime + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + sigObj.setSignationDate(sig_tim); + } + // CertDigest + if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + { + String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start()); + Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest); + Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest); + if (dig_val_m_s.find() && dig_val_m_e.find()) + { + sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + sigObj.setX509CertificateDigest(sig_dig); + } + } + // extract Subject Name from X509Certificate + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + sig_cer = sig_cer.replaceAll("\\s", ""); + X509Cert cert = X509Cert.initByString(sig_cer); + if (cert.isX509Cert()) + { + sigObj.setX509Certificate(cert.getCertString()); + String serial_num = cert.getSerialNumber(); + String subject_name = cert.getSubjectName(); + if (!ser_num.equals(serial_num)) + { + SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!"); + throw se; + } + sigObj.setSignationName(subject_name); + } + } + } + + /** + * This method reads the verify template from the file system and fills out + * the template with the SignatureObject values. + * + * @param normalizedText + * the normalized text to veryfied + * @param sigObject + * the SignatureObject holding the singature values + * @return the filled verify template string + * @throws SignatureException + * ErrorCode (311, 312, 313) + * @see SignatureObject + * @see CodingHelper + */ + public String getVerifyTemplate(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + try + { + if (normalizedText == null || normalizedText.length() == 0) + { + SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty."); + throw se; + } + if (sigObject == null) + { + SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set."); + throw se; + } + String verify_template = getVerifyTemplateFileName(sigObject.getSignationType()); + String sig_prop_template = getSigPropFileName(sigObject.getSignationType()); + + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); + String verify_req_str = this.settings_.readInternalResourceAsString(verify_template); + + //String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_template)); + String sig_prop_str = this.settings_.readInternalResourceAsString(sig_prop_template); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_template); + //logger_.debug(sig_prop_template); + } + + String x509Certificate = sigObject.getX509CertificateString(); + if (x509Certificate == null) + { + SignatureException se = new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "Document certificate is not defined."); + throw se; + } + String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa"); + X509Cert x509_cert = sigObject.getX509Cert(); + if (x509_cert.isRSA()) + { + cert_alg = settings_.getValueFromKey("cert.alg.rsa"); + } + + sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); + // The issuer is already a valid Unicode String. + // No need to convert it - not to mention the missing encoding. + // byte[] issuer_name = + // CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); + // new String(issuer_name) + sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", sigObject.getSignationIssuer()); + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); + sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); + + verify_req_str = verify_req_str.replaceFirst("CertAlgReplace", cert_alg); + verify_req_str = verify_req_str.replaceFirst("TemplateSignedPropertiesReplace", sig_prop_str); + byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"), "sha1"); // added + // the + // ("UTF-8") + // encoding + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + verify_req_str = verify_req_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from SignedProperties:start"); + //logger_.debug("DATA :" + sig_prop_str); + logger_.debug("DIGEST:" + sig_prop_hash); + logger_.debug("build digest from SignedProperties:end"); + } + + verify_req_str = verify_req_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue()); + verify_req_str = verify_req_str.replaceFirst("X509CertificateReplace", x509Certificate); + byte[] data_value = normalizedText.getBytes("UTF-8"); + byte[] data_value_hash = CodingHelper.buildDigest(data_value, "sha1"); + // byte[] data_value_hash = + // CodingHelper.buildDigest(normalizedText.getBytes()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + //String object_data = normalizedText; // new String(data_value); + // System.err.println(object_data_hash); + // very_req_str = very_req_str.replaceFirst("ObjectDataReplace", + // object_data); + String raw_b64 = CodingHelper.encodeBase64(data_value); + verify_req_str = verify_req_str.replaceFirst("Base64ContentReplace", raw_b64); + + verify_req_str = verify_req_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); + if (logger_.isDebugEnabled()) + { + // FileHelper.writeToFile(verify_template + "_verifyText.xml", + // normalizedText); + logger_.debug("build digest from data object:start"); + //logger_.debug("DATA :" + object_data); + logger_.debug("DIGEST:" + object_data_hash); + logger_.debug("build digest from data object:end"); + } + return verify_req_str; + } + catch (UnsupportedEncodingException e) + { + throw new SignatureException(310, e); + } + } + + /** + * This method generates the MOA verify prozess. It checks if the given + * SignatureObject is signed by MOA or BKU. The verify template string is + * filled out by the corresponding method. + * + * @param normalizedText + * the normalized text to verify + * @param sigObject + * the SignatureObject holding the singature values + * @return a SignatureResponse object if the verify prozess does not fails + * @throws SignatureException + * @see SignatureResponse + */ + public SignatureResponse doVerify(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String verify_url = getVerifyURL(sigObject.getSignationType()); // settings_.getValueFromKey(TYPE + // + "." + + // Signature.VALUE_MODE_VERIFY + // + + // ".url"); + String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); // settings_.getValueFromKey(TYPE + // + + // "." + // + + // Signature.VALUE_MODE_VERIFY + // + + // ".request"); + String trust_profile = getVerifyTrustProfileID(sigObject.getSignationType()); + + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); + String verify_req_str = this.settings_.readInternalResourceAsString(verify_request); + + String verify_template_str = null; + if (sigObject.isMOASigned()) + { + verify_template_str = getVerifyTemplate(normalizedText, sigObject); + } + else + { + BKUConnector bku_conn = new BKUConnector(); + verify_template_str = bku_conn.getVerifyTemplate(normalizedText, sigObject); + } + verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + verify_req_str = verify_req_str.replaceFirst("TrustProfileIDReplace", trust_profile); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_req_str); + // FileHelper.writeToFile(verify_request + "_request.xml", + // verify_req_str); + } + String response_string = ""; + try + { + response_string = MOAConnector.connectMOA(verify_req_str, MOAConnector.SERVICE_VERIFY, verify_url); + } + catch (WebException we) + { + if (logger_.isDebugEnabled()) + { + we.printStackTrace(); + } + SignatureException se = new SignatureException(we.getErrorCode(), we); + throw se; + } + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(response_string); + // FileHelper.writeToFile(verify_request + "_response.xml", + // response_string); + logger_.error("Write error response to file:" + verify_request + "_response.xml"); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request + "_response.xml " + response_string); + } + return parseVerifyXMLResponse(response_string); + } + } + return null; + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the MOA-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + private SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + if (logger_.isInfoEnabled()) + { + logger_.info("Try parsing the verify response"); + } + Pattern sub_nam_p_s = Pattern.compile(""); + Pattern sub_nam_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile(""); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile(""); + Pattern ser_num_p_e = Pattern.compile(""); + + // [tknall] start qualified certificate + Pattern cert_qualified_p = Pattern.compile(""); + Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); + // [tknall] stop qualified certificate + + Pattern sig_chk_p_s = Pattern.compile(""); + Pattern sig_chk_p_e = Pattern.compile(""); + Pattern man_chk_p_s = Pattern.compile(""); + Pattern man_chk_p_e = Pattern.compile(""); + Pattern cer_chk_p_s = Pattern.compile(""); + Pattern cer_chk_p_e = Pattern.compile(""); + + Pattern code_p_s = Pattern.compile(""); + Pattern code_p_e = Pattern.compile(""); + + Pattern cert_p_s = Pattern.compile(""); + Pattern cert_p_e = Pattern.compile(""); + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + SignatureResponse sig_res = new SignatureResponse(); + + // [tknall] start qualified certificate + sig_res.setQualifiedCertificate(cert_qualified_m.find()); + // [tknall] stop qualified certificate + + // public authority + Pattern publicAuthority_p = Pattern.compile(""); + Matcher publicAuthority_m = publicAuthority_p.matcher(xmlResponse); + sig_res.setPublicAuthority(false); + sig_res.setPublicAuthorityCode(null); + if (publicAuthority_m.find()) { + sig_res.setPublicAuthority(true); + } else { + Matcher publicAuthority_m_s = Pattern.compile("").matcher(xmlResponse); + Matcher publicAuthority_m_e = Pattern.compile("").matcher(xmlResponse); + if (publicAuthority_m_s.find() && publicAuthority_m_e.find()) { + sig_res.setPublicAuthority(true); + String codePart = xmlResponse.substring(publicAuthority_m_s.end(), publicAuthority_m_e.start()); + Matcher code_m_s = code_p_s.matcher(codePart); + Matcher code_m_e = code_p_e.matcher(codePart); + if (code_m_s.find() && code_m_e.find()) { + String code = codePart.substring(code_m_s.end(), code_m_e.start()); + sig_res.setPublicAuthorityCode(code); + } + } + } + + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + return sig_res; + } + + protected String getConnectorValueFromProfile(String profile, String key) + { + String value = settings_.getValueFromKey("sig_obj." + profile + "." + key); + if (value == null) + { + value = settings_.getValueFromKey(key); + } + return value; + } + + public String getSignURL(String profile) + { + final String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignRequestTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignKeyIdentifier(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".KeyIdentifier"; + return getConnectorValueFromProfile(profile, key); + } + + public String getVerifyURL(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyRequestTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSigPropFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template.SP"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTrustProfileID(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".TrustProfileID"; + return getConnectorValueFromProfile(profile, key); + } + + /** + * This method connects the moa server getting the requestString, the given + * serviseMode and the endpointUrl. The requestString is the envelope of the + * SOAP Message send and recieve by the AXIS module. The Response SOAP message + * of the MOA server is parsed by AXIS and the message envelope is send back + * to the calling method. + * + * @param requestString + * the request string (XML) to send. + * @param serviceMode + * the mode which connect to MOA + * @param endpointURL + * the URL which the MOA server is running + * @return the response string (XML) of the MOA server + * @throws WebException + */ + public static String connectMOA(String requestString, String serviceMode, + String endpointURL) throws WebException + { + try + { + if (logger_.isInfoEnabled()) + { + logger_.info(serviceMode); + logger_.info(endpointURL); + } + // Parser/DOMBuilder instanzieren + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + // XML Datei in einen DOM-Baum umwandeln + ByteArrayInputStream bais = new ByteArrayInputStream(requestString.getBytes("UTF-8")); + Document xmlRequest = builder.parse(bais); + + // Call oeffnen + Call call = null; + + // Neues BodyElement anlegen und mit dem DOM-Baum fuellen + SOAPBodyElement body = new SOAPBodyElement(xmlRequest.getDocumentElement()); + SOAPBodyElement[] params = new SOAPBodyElement[] { body }; + + // AXIS-Server instanzieren + Service service = ServiceFactory.newInstance().createService(new QName(serviceMode)); + call = service.createCall(); + call.setTargetEndpointAddress(endpointURL); + + // Call ausloesen und die Antworten speichern + if (logger_.isInfoEnabled()) + { + logger_.info("Calling MOA:" + endpointURL); + } + Vector responses = (Vector) call.invoke(params); + + // Erstes Body Element auslesen + SOAPBodyElement response = (SOAPBodyElement) responses.get(0); + + // Aus der Response den DOM-Baum lesen + Document root_response = response.getAsDocument(); + if (logger_.isInfoEnabled()) + { + logger_.info("Return from MOA:" + serviceMode); + } + + // XML-Formatierung konfiguieren + OutputFormat format = new OutputFormat((Document) root_response); + format.setLineSeparator("\n"); + format.setIndenting(false); + format.setPreserveSpace(true); + format.setOmitXMLDeclaration(false); + format.setEncoding("UTF-8"); + + // Ausgabe der Webservice-Antwort auf die Konsole + // XMLSerializer conSerializer = new XMLSerializer(System.out, format); + // conSerializer.serialize(root_response); + + // Ausgabe der Webservice-Antwort in Datei + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XMLSerializer response_serializer = new XMLSerializer(baos, format); + response_serializer.serialize(root_response); + return baos.toString("UTF-8"); + } + catch (Exception e) + { + throw new WebException(e); + } + // serialize signature only + + // if + // (root_response.getDocumentElement().getLocalName().equals("CreateXMLSignatureResponse")) + // { + // Element signature = (Element) + // root_response.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", + // "Signature").item(0); + // String signatureFile = getProperty(mode + "Request").substring(0, + // getProperty(mode + + // "Request").lastIndexOf('.')) + ".Signature.xml"; + // fileSerializer = new XMLSerializer(new FileOutputStream(signatureFile), + // format); + // fileSerializer.serialize(signature); + // } + + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java new file mode 100644 index 0000000..7caf422 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java @@ -0,0 +1,172 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +/** + * This class contains String constants that are frequently used in various + * connector templates to fill in the data into the templates. + * + * @author wprinz + */ +public final class TemplateReplaces +{ + /** + * The placeholder text in the template to be replaced by the keybox + * identifier. + */ + public static final String KEYBOX_IDENTIFIER_REPLACE = "KeyboxIdentifierReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the mime type. + */ + public static final String MIME_TYPE_REPLACE = "MimeTypeReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the XML content of + * another template. + */ + public static final String XML_CONTENT_REPLACE = "XMLContentReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the cert alg. + */ + public static final String CERT_ALG_REPLACE = "CertAlgReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the digest value of + * the signed data. + */ + public static final String DIGEST_VALUE_SIGNED_DATA_REPLACE = "DigestValueSignedDataReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the signature value. + */ + public static final String SIGNATURE_VALUE_REPLACE = "SignatureValueReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the X.509 + * certificate. + */ + public static final String X509_CERTIFICATE_REPLACE = "X509CertificateReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the signing time. + */ + public static final String SIGNING_TIME_REPLACE = "SigningTimeReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the certificate + * digest. + */ + public static final String DIGEST_VALUE_CERTIFICATE_REPLACE = "DigestValueX509CertificateReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the issuer name. + */ + public static final String X509_ISSUER_NAME_REPLACE = "X509IssuerNameReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the serial number. + */ + public static final String X509_SERIAL_NUMBER_REPLACE = "X509SerialNumberReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the signed + * properties digest. + */ + public static final String DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE = "DigestValueSignedPropertiesReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the SigDataRef. + */ + public static final String SIG_DATA_REF_REPLACE = "SigDataRefReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the EtsiDataRef. + */ + public static final String ETSI_DATA_REF_REPLACE = "EtsiDataRefReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the SigDataObjURI. + */ + public static final String SIG_DATA_OBJ_URI_REPLACE = "SigDataObjURIReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the EtsiDataObjURI. + */ + public static final String ETSI_DATA_OBJ_URI_REPLACE = "EtsiDataObjURIReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the SigId. + */ + public static final String SIG_ID_REPLACE = "SigIdReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the key identifier. + */ + public static final String KEY_IDENTIFIER_REPLACE = "KeyIdentifierReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the LocRefContent + * URL. + */ + public static final String LOC_REF_CONTENT_REPLACE = "LocRefContentReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the trust profile ID. + */ + public static final String TRUST_PROFILE_ID_REPLACE = "TrustProfileIDReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the return hash input data element. + */ + public static final String RETURN_HASH_INPUT_DATA_REPLACE = "ReturnHashInputDataReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the dateTime element. + */ + public static final String DATE_TIME_REPLACE = "DateTimeReplace"; // $NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the Base64 content. + */ + public static final String BASE64_CONTENT_REPLACE = "Base64ContentReplace"; //$NON-NLS-1$ + +//dferbas + /** + * The placeholder text in the template to be replaced by the digest method for data. + */ + public static final String DATA_DIGEST_REPLACE = "DataDigestReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the digest method for properties. + */ + public static final String PROPERTIES_DIGEST_REPLACE = "PropertiesDigestReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the digest method for cert. + */ + public static final String CERT_DIGEST_REPLACE = "CertDigestReplace"; //$NON-NLS-1$ + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java new file mode 100644 index 0000000..64306ab --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java @@ -0,0 +1,695 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Properties; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.internal.LocalBKUParams; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Contains static helper methods used by the BKU Connectors. + * + * @author wprinz + */ +public final class BKUHelper +{ + + private static final Pattern ALLOWED_SL_RESPONSE_PATTERN = Pattern.compile("^.*<[\\w]*:?(CreateXMLSignatureResponse|VerifyXMLSignatureResponse)[^>]*>(.*).*$", Pattern.DOTALL); + + /** + * The log. + */ + private static Log log = LogFactory.getLog(BKUHelper.class); + + /** + * Encodes the given SignatureData to a valid Base64Content. + * + *

+ * The data is Base64 encoded. If the mime-type suggests that the data is + * binary, it is Base64 encoded for a second time. + *

+ * + * @param data + * The data to be converted to a valid Base64 content. + * @return Returns the Base64 content. + */ + public static String prepareBase64Content(SignatureData data) + { + // PERF: base64 encoding needs byte array + byte [] d = DataSourceHelper.convertDataSourceToByteArray(data.getDataSource()); + + String base64 = CodingHelper.encodeBase64(d); + if (data.getMimeType().equals("application/pdf")) //$NON-NLS-1$ + { + log.debug("The data is application/pdf - so the binary data is Base64 encoded."); //$NON-NLS-1$ + base64 = CodingHelper.encodeUTF8AsBase64(base64); + } + return base64; + + } + + /** + * Prepares the enveloping data. + *

+ * This is useful for building the hash. + *

+ * + * @param data + * The data to be prepared. + * @return Returns the prepared data. + */ + public static byte[] prepareEnvelopingData(SignatureData data) + { + // PERF: prepareEnvelopingData needs byte array + byte[] enc = DataSourceHelper.convertDataSourceToByteArray(data.getDataSource()); + + if (data.getMimeType().equals("application/pdf")) //$NON-NLS-1$ + { + log.debug("The data is application/pdf - so the binary data is Base64 encoded."); //$NON-NLS-1$ + String base64 = CodingHelper.encodeBase64(enc); + try + { + enc = base64.getBytes("US-ASCII"); //$NON-NLS-1$ + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); //$NON-NLS-1$ + } + } + return enc; + } + + /** + * Checks the response xml for an error description and if found throws an + * appropriate exception. + * + * @param response_string + * The response xml. + * @throws ConnectorException + * f.e. + */ + public static void checkResponseForError(String response_string) throws ConnectorException + { + if (StringUtils.isEmpty(response_string)) { + throw new ConnectorException(ErrorCode.UNABLE_TO_RECEIVE_SUITABLE_RESPONSE, "No suitable response received."); + } + log.debug("Checking response for error: " + response_string); + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); //$NON-NLS-1$ + Pattern erc_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + log.error("Found error in response: " + response_string); //$NON-NLS-1$ + + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); //$NON-NLS-1$ + Pattern erm_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new ExternalErrorException(error_code, error_mess); + } + log.debug("No error found. Assuring that CreateXMLSignatureResponse or VerifyXMLSignatureResponse elements are available."); + + // assure that a CreateXMLSignatureResponse or a VerifyXMLSignatureResponse is available + Matcher slMatcher = ALLOWED_SL_RESPONSE_PATTERN.matcher(response_string); + if (!slMatcher.matches()) { + throw new ConnectorException(ErrorCode.UNABLE_TO_RECEIVE_SUITABLE_RESPONSE, "No suitable response received: " + response_string); + } + + } + + /** + * This method parses the BKU-Response string. + * + *

+ * It separates the SignatureValue, X509IssuerName, SigningTime, + * X509SerialNumber, X509Certificate, CertDigest, DigestValue and the + * signation id-s. If the X509Certificate is extracted it would be stored in + * the certificates directory. + *

+ * + * @param xmlResponse + * The response string. + * @return Returns the parsed signature object holding the data. + * + * @throws ConnectorException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + public static SignSignatureObject parseCreateXMLResponse(String xmlResponse, + IdFormatter id_formatter, ConnectorEnvironment environment) throws ConnectorException + { + if (log.isDebugEnabled()) { + log.debug("xmlResponse = " + xmlResponse); + } + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); //$NON-NLS-1$ + Pattern sig_val_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); //$NON-NLS-1$ + Pattern iss_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); //$NON-NLS-1$ + Pattern sig_tim_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); //$NON-NLS-1$ + Pattern ser_num_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); //$NON-NLS-1$ + Pattern sig_cer_p_e = Pattern.compile(""); //$NON-NLS-1$ + + // Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + // //$NON-NLS-1$ + // Pattern sig_cer_d_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + // Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + // //$NON-NLS-1$ + // Pattern dig_val_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + // Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + // Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + // Matcher dig_val_m_s = dig_val_p_s.matcher(xmlResponse); + // Matcher dig_val_m_e = dig_val_p_e.matcher(xmlResponse); + + // SignatureValue + String sig_val = null; + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = removeAllWhitespace(xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start())); + } + log.debug("sig_val = " + sig_val); //$NON-NLS-1$ + + // X509IssuerName + String iss_nam = null; + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + } + log.debug("iss_nam = " + iss_nam); //$NON-NLS-1$ + + // X509SerialNumber + String ser_num = null; + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = removeAllWhitespace(xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start())); + } + log.debug("ser_num = " + ser_num); //$NON-NLS-1$ + + // SigningTime + String sig_tim = null; + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + } + log.debug("sig_tim = " + sig_tim); //$NON-NLS-1$ + + // CertDigest + // if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + // { + // String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), + // sig_cer_d_m_e.start()); + // if (dig_val_m_s.find() && dig_val_m_e.find()) + // { + // sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + // //sigObj.setX509CertificateDigest(sig_dig); + // } + // } + + // X509Certificate + X509Certificate cert = null; + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + String sig_cer = removeAllWhitespace(xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start())); + + try + { + byte[] der = CodingHelper.decodeBase64(sig_cer); + ByteArrayInputStream bais = new ByteArrayInputStream(der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$ + cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + } + catch (UnsupportedEncodingException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (CertificateException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (IOException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + } + log.debug("X509Certificate = " + cert); //$NON-NLS-1$ + + if (log.isDebugEnabled()) + { + + String cert_iss = cert.getIssuerDN().getName(); + log.debug("certificate's issuer = " + cert_iss); //$NON-NLS-1$ + log.debug("response's issuer = " + iss_nam); //$NON-NLS-1$ + log.debug("issuer matches = " + cert_iss.equals(iss_nam)); //$NON-NLS-1$ + log.debug("ser number matches = " + cert.getSerialNumber().toString().equals(ser_num)); //$NON-NLS-1$ + } + + // extract Subject Name from X509Certificate + // if (sig_cer_m_s.find() && sig_cer_m_e.find()) + // { + // sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + // sig_cer = sig_cer.replaceAll("\\s", ""); + // //sigObj.setX509Certificate(sig_cer); + // X509Cert cert = X509Cert.initByString(sig_cer); + // if (cert.isX509Cert()) + // { + // //sigObj.setX509Certificate(cert.getCertString()); + // String serial_num = cert.getSerialNumber(); + // String subject_name = cert.getSubjectName(); + // if (!ser_num.equals(serial_num)) + // { + // ConnectorException se = new ConnectorException(303, "Serialnumber of + // certificate and tag X509SerialNumber differs!"); + // throw se; + // } + // //sigObj.setSignationName(subject_name); + // } + // } + + // extract Signature Id's + String[] ids = new String[5]; + ids[0] = extractId(xmlResponse, "signature-"); //$NON-NLS-1$ + ids[1] = extractId(xmlResponse, "signed-data-reference-"); //$NON-NLS-1$ + ids[2] = extractId(xmlResponse, "signed-data-object-"); //$NON-NLS-1$ + ids[3] = extractId(xmlResponse, "etsi-data-reference-"); //$NON-NLS-1$ + ids[4] = extractId(xmlResponse, "etsi-data-object-"); //$NON-NLS-1$ + + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); + + SignSignatureObject so = new SignSignatureObject(); + so.date = sig_tim; + so.issuer = iss_nam; + so.signatureValue = sig_val; + so.x509Certificate = cert; + + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); + so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); + + String defaultCertAlg = environment.getDefaultAlgForCert(cert); + + if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { + // do not embed default alg + algs = null; + } + + String final_ids = id_formatter.formatIds(ids, algs); + so.id = final_ids; + + return so; + } + + /** + * Removes all whitespaces ("\\s") from the String. + * + * @param str + * The String. + * @return The String with all whitespaces removed. + */ + public static String removeAllWhitespace(String str) + { + return str.replaceAll("\\s", ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * This emthod extracts id-values from a text. The id is given by the name. + * + * @param text + * the id-value that should extract from + * @param name + * the id-key + * @return the value of the given key in the text + */ + private static String extractId(String text, String name) + { + String id = null; + // fatal bug; fixed by tknall (start) + int startOfName = text.indexOf(name); + if (startOfName == -1) { + log.debug("No id for name \"" + name + "\" extracted. Probably detached signature. Returning empty id: \"\""); //$NON-NLS-1$ + return ""; + } + // stop + + int start_idx = startOfName + name.length(); + int end_idx = text.indexOf("\"", start_idx); //$NON-NLS-1$ + + final int quot_end_idx = end_idx; + final int squot_end_idx = text.indexOf("'", start_idx); //$NON-NLS-1$ + end_idx = Math.min(quot_end_idx, squot_end_idx); + id = text.substring(start_idx, end_idx); + if (log.isDebugEnabled()) + { + log.debug("extract id:" + name + id); //$NON-NLS-1$ + } + return id; + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the BKU-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + public static SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + log.debug("parseVerifyXMLResponse:"); //$NON-NLS-1$ + + Pattern sub_nam_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern sub_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_e = Pattern.compile(""); //$NON-NLS-1$ + + Pattern sig_chk_p_s = Pattern.compile("<[\\w]*:?SignatureCheck>"); //$NON-NLS-1$ + Pattern sig_chk_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern man_chk_p_s = Pattern.compile("<[\\w]*:?SignatureManifestCheck>"); //$NON-NLS-1$ + Pattern man_chk_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern cer_chk_p_s = Pattern.compile("<[\\w]*:?CertificateCheck>"); //$NON-NLS-1$ + Pattern cer_chk_p_e = Pattern.compile(""); //$NON-NLS-1$ + + // [tknall] start qualified certificate + Pattern cert_qualified_p = Pattern.compile("<[\\w]*:?QualifiedCertificate/>"); //$NON-NLS-1$ + Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); + // [tknall] stop qualified certificate + + Pattern code_p_s = Pattern.compile("<[\\w]*:?Code>"); //$NON-NLS-1$ + Pattern code_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern info_p_s = Pattern.compile("<[\\w]*:?Info>"); //$NON-NLS-1$ + Pattern info_p_e = Pattern.compile(""); //$NON-NLS-1$ + + Pattern cert_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern cert_p_e = Pattern.compile(""); //$NON-NLS-1$ + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + Pattern hash_data_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern hash_data_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher hash_data_m_s = hash_data_p_s.matcher(xmlResponse); + Matcher hash_data_m_e = hash_data_p_e.matcher(xmlResponse); + + + SignatureResponse sig_res = new SignatureResponse(); + + // public authority (tknall) + Pattern publicAuthority_p = Pattern.compile(""); + Matcher publicAuthority_m = publicAuthority_p.matcher(xmlResponse); + sig_res.setPublicAuthority(false); + sig_res.setPublicAuthorityCode(null); + if (publicAuthority_m.find()) { + sig_res.setPublicAuthority(true); + } else { + Matcher publicAuthority_m_s = Pattern.compile("").matcher(xmlResponse); + Matcher publicAuthority_m_e = Pattern.compile("").matcher(xmlResponse); + if (publicAuthority_m_s.find() && publicAuthority_m_e.find()) { + sig_res.setPublicAuthority(true); + String codePart = xmlResponse.substring(publicAuthority_m_s.end(), publicAuthority_m_e.start()); + Matcher code_m_s = code_p_s.matcher(codePart); + Matcher code_m_e = code_p_e.matcher(codePart); + if (code_m_s.find() && code_m_e.find()) { + String code = codePart.substring(code_m_s.end(), code_m_e.start()); + sig_res.setPublicAuthorityCode(code); + } + } + } + + // [tknall] start qualified certificate + sig_res.setQualifiedCertificate(cert_qualified_m.find()); + // [tknall] stop qualified certificate + + if (hash_data_m_s.find() && hash_data_m_e.find()) + { + String hashInputData = xmlResponse.substring(hash_data_m_s.end(), hash_data_m_e.start()); + + Pattern b64_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern b64_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher b64_m_s = b64_p_s.matcher(hashInputData); + Matcher b64_m_e = b64_p_e.matcher(hashInputData); + + boolean hashInputDataFound = b64_m_s.find() && b64_m_e.find(); + + String b64 = hashInputDataFound ? hashInputData.substring(b64_m_s.end(), b64_m_e.start()) : ""; + + sig_res.setHashInputData(b64); + } + + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + Matcher info_m_s = info_p_s.matcher(sig_chk); + Matcher info_m_e = info_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = sig_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureCheckInfo(info); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + Matcher info_m_s = info_p_s.matcher(man_chk); + Matcher info_m_e = info_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = man_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureManifestCheckInfo(info); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + Matcher info_m_s = info_p_s.matcher(cer_chk); + Matcher info_m_e = info_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = cer_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setCertificateCheckInfo(info); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + log.debug("parseVerifyXMLResponse finished."); //$NON-NLS-1$ + return sig_res; + } + + public static String formDateTimeElement(Date verificationTime) + { + return formDateTimeElement(verificationTime, null); + } + + public static String formDateTimeElement(Date verificationTime, String namespace) + { + String nsPrefix = StringUtils.isBlank(namespace) ? "" : (namespace + ":"); + + String dateTimeElement = ""; + if (verificationTime != null) + { + log.debug("VerificationTime = " + verificationTime); + + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + String dateTime = df.format(verificationTime) + "Z"; + log.debug("DateTime (VerificationTime in UTC) = " + dateTime); + + dateTimeElement = "<" + nsPrefix + "DateTime>" + dateTime + ""; + }; + return dateTimeElement; + } + + public static String getBKUIdentifier(Properties parsedResponseProperties) { + + // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser + String bkuServerHeader = parsedResponseProperties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY); + + // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl + String bkuUserAgentHeader = parsedResponseProperties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY); + + String bkuSignatureLayout = parsedResponseProperties.getProperty(BKUPostConnection.BKU_SIGNATURE_LAYOUT_HEADER_KEY); + + return getBKUIdentifier(bkuServerHeader, bkuUserAgentHeader, bkuSignatureLayout); + } + + public static String getBKUIdentifier(String bkuServerHeader, String bkuUserAgentHeader, String bkuSignatureLayout) { + + log.debug("BKU response header \"user-agent\": " + bkuUserAgentHeader); + log.debug("BKU response header \"server\": " + bkuServerHeader); + log.trace("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\": " + bkuSignatureLayout); + + String result = null; + + if (bkuServerHeader != null) { + result = bkuServerHeader; + } else if (bkuUserAgentHeader != null) { + result = bkuUserAgentHeader; + } else { + log.warn("Unable to find any BKU identifier (neither header value \"user-agent\" nor \"server\".)"); + } + + if (bkuSignatureLayout != null && result != null) { + log.debug("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\" found."); + String signatureLayoutData = " " + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "/" + bkuSignatureLayout; + if (!result.endsWith(signatureLayoutData)) { + log.debug("Appending signature layout value \"" + bkuSignatureLayout + "\" to bku identifier."); + result += signatureLayoutData; + } else { + log.debug("Signature layout already encoded in server/user-agent header."); + } + } + + if (result != null) { + log.debug("Returning BKU identifier \"" + result + "\""); + } else { + log.debug("Returning null BKU identifier."); + } + + return result; + } + + public static String getBKUIdentifier(LocalBKUParams bkuParams) { + return getBKUIdentifier(bkuParams.getServer(), bkuParams.getUserAgent(), bkuParams.getSignatureLayout()); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java new file mode 100644 index 0000000..04b817f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java @@ -0,0 +1,179 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; + +/** + * Helper class with methods that use the Apache Https Client to send HTTP + * requests. + * + * @author wprinz + */ +public final class BKUPostConnection +{ + /** + * The response Properties key that identifies the response string. + */ + public static final String RESPONSE_STRING_KEY = "response_string"; //$NON-NLS-1$ + + /** + * The response Properties key that identifies the BKU Server header. + */ + public static final String BKU_SERVER_HEADER_KEY = "BKU-Server-Header"; //$NON-NLS-1$ + + /** + * The response property that declares the signature layout being applied. + */ + public static final String BKU_SIGNATURE_LAYOUT_HEADER_KEY = "BKU-Signature-Layout"; //$NON-NLS-1$ + + /** + * The response Properties key that identifies the BKU User-Agent header. + */ + public static final String BKU_USER_AGENT_HEADER_KEY = "BKU-User-Agent-Header"; //$NON-NLS-1$ + + /** + * The log. + */ + private static Log log = LogFactory.getLog(BKUPostConnection.class); + + /** + * Sends a multipart/form-data HTTP Post request to the given URL. + * + * @param url The url the request is directed to. + * @param request The request XML, which will be the UTF-8 text/xml first part of the message. + * @param data The binary second part of the message. + * @return Returns the response properties which, among others, contain the response String. + * @throws HttpException + * @throws IOException + */ + public static Properties doPostRequestMultipart(String url, String request, + final SignatureData data) throws HttpException, IOException + { + log.debug("doPostRequestMultipart:"); //$NON-NLS-1$ + + StringPart xmlpart = new StringPart("XMLRequest", request, "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + + // TODO this is a BUG in BKU that doesn't allow the Content-Type header + xmlpart.setContentType(null); + xmlpart.setTransferEncoding(null); + // BKU 2.7.4 can't handle the Content-Type Header for the XML + // xmlpart.setContentType("text/xml"); + // xmlpart.setTransferEncoding(null); + + final String filename = data.getMimeType().equals("application/pdf") ? "myfile.pdf" : "myfile.txt"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + PartSource ps = new PartSource() { + public InputStream createInputStream() throws IOException + { + return data.getDataSource().createInputStream(); + } + + public String getFileName() + { + return filename; + } + + public long getLength() + { + return data.getDataSource().getLength(); + } + }; + //ByteArrayPartSource baps = new ByteArrayPartSource(filename, data.getData()); + FilePart filepart = new FilePart("fileupload", ps); //$NON-NLS-1$ + filepart.setContentType(data.getMimeType()); + + // not really needed since external referenced data has to be taken "as-is" (binary stream) for + // digest calculation, so neither content type nor charset is relevant + filepart.setCharSet(data.getCharacterEncoding()); + + Part[] parts = { xmlpart, filepart }; + + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); //$NON-NLS-1$ + + PostMethod post_method = new PostMethod(url); + post_method.setParams(method_params); + + MultipartRequestEntity mprqe = new MultipartRequestEntity(parts, post_method.getParams()); + post_method.setRequestEntity(mprqe); + + HttpClient http_client = new HttpClient(); + + int method_response = http_client.executeMethod(post_method); + log.debug("method_response = " + method_response); //$NON-NLS-1$ + + Properties response_properties = new Properties(); + + if (log.isDebugEnabled()) + { + Header[] response_headers = post_method.getResponseHeaders(); + for (int i = 0; i < response_headers.length; i++) + { + log.debug(" response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + Header server_header = post_method.getResponseHeader("Server"); //$NON-NLS-1$ + if (server_header != null) { + response_properties.setProperty(BKU_SERVER_HEADER_KEY, server_header.getValue()); + } else { + log.warn("BKU response header \"Server\" is empty."); + } + + Header signatureLayoutHeader = post_method.getResponseHeader(Constants.BKU_HEADER_SIGNATURE_LAYOUT); //$NON-NLS-1$ + if (signatureLayoutHeader != null) { + response_properties.setProperty(BKU_SIGNATURE_LAYOUT_HEADER_KEY, signatureLayoutHeader.getValue()); + } + + String responseCharSet = post_method.getResponseCharSet(); + if (!"UTF8".equalsIgnoreCase(responseCharSet) && !"UTF-8".equalsIgnoreCase(responseCharSet)) { + log.warn("BKU response charset is not UTF-8!"); //$NON-NLS-1$ + } + String response_string = post_method.getResponseBodyAsString(); + + response_properties.setProperty(RESPONSE_STRING_KEY, response_string); + + log.debug("doPostRequestMultipart finished."); //$NON-NLS-1$ + + return response_properties; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java new file mode 100644 index 0000000..a8de41e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java @@ -0,0 +1,823 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.DetachedLocRefMOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connects to the BKU using the detached multipart/formdata requests. + * + *

+ * This feature is available since BKU version 2.7.4. + *

+ * + * @author wprinz + */ +public class DetachedBKUConnector implements Connector, LocalConnector +{ +//23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedBKUConnector.class); + + /** + * The connector parameters. + */ + protected ConnectorParameters params = null; + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param connectorParameters + * The connectot parameters. + * @throws ConnectorException + * f.e. + */ + public DetachedBKUConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException + { + this.params = connectorParameters; + this.environment = new Environment(this.params.getProfileId(), loc_ref_content); + } + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequestDetached:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); + String mime_type = data.getMimeType(); + String loc_ref_content = this.environment.getLocRefContent(); + + if (log.isDebugEnabled()) + { + log.debug("sign keybox identifier = " + sign_keybox_identifier); //$NON-NLS-1$ + log.debug("mime type = " + mime_type); //$NON-NLS-1$ + log.debug("loc_ref_content = " + loc_ref_content); //$NON-NLS-1$ + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + + log.debug("sign_request_xml = " + sign_request_xml); + log.debug("prepareSignRequestDetached finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); + log.debug("BKU identifier: " + (bkuIdentifier != null ? ("\"" + bkuIdentifier + "\"") : "n/a")); + + SignatureLayoutHandler sigLayout; + try { + sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier); + } catch (SettingsException e) { + throw new ConnectorException(e.getErrorCode(), e.getMessage()); + } + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string, this.environment); + + so.response_properties = response_properties; + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + public static String[] parseSigIds(String sig_ids) + { + if (sig_ids == null || sig_ids.length() == 0) + { + return null; + } + + // int index = sig_ids.indexOf(PdfAS.IDS); + // if (index < 0) + // { + // return null; + // } + // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + + String[] ids_str = sig_ids.split("@"); + + String etsi_string = null; + if (ids_str.length == 3) + { + etsi_string = ids_str[0]; + String[] rest_ids = new String[] { ids_str[1], ids_str[2] }; + ids_str = rest_ids; + } + + String base = ids_str[0]; + String[] ids = ids_str[1].split("-"); + String[] real_ids = new String[6]; // the last one contains the etsi string + real_ids[0] = base + "-" + ids[0]; + real_ids[1] = "0-" + base + "-" + ids[1]; + real_ids[2] = "0-" + base + "-" + ids[2]; + real_ids[3] = "0-" + base + "-" + ids[3]; + real_ids[4] = "0-" + base + "-" + ids[4]; + real_ids[5] = etsi_string; + + if (log.isDebugEnabled()) + { + for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + { + log.debug("real_ids[" + id_idx + "] = " + real_ids[id_idx]); + } + } + + return real_ids; + } + + /** + * Sends the request and data to the given URL. + * + *

+ * This method mainly handles communication exceptions. The actual send work + * is done by doPostRequestMultipart. + *

+ * + * @see BKUPostConnection#doPostRequestMultipart(String, String, + * SignatureData) + * + * @param url + * The URL to send the request to. + * @param request_string + * The request XML. + * @param data + * The data. + * @return Returns the response properties containing among others the + * response XML. + * @throws ConnectorException + * f.e. + */ + protected Properties sendRequest(String url, String request_string, + SignatureData data) throws ConnectorException + { + try + { + Properties response_properties = BKUPostConnection.doPostRequestMultipart(url, request_string, data); + return response_properties; + } + catch (Exception e) + { + ConnectorException se = new ConnectorException(320, e); + throw se; + } + } + + /** + * Performs a sign. + * + * @param data + * The data to be signed. + * @return Returns the signature object containing the signature data. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); + log.debug("sign_request_xml = " + sign_request_xml); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, sign_request_xml, data); + + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * Performs a verification. + * + * @param data + * The data to be verified. + * @param so + * The signature object with the signature information. + * @return Returns the SignatureResponse with the result of the verification. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + // TODO debug - remove + // try + // { + // FileOutputStream fos = new + // FileOutputStream("C:\\wprinz\\Filer\\egiz2\\verify_request.utf8.xml"); + // //$NON-NLS-1$ + // fos.write(verify_request_xml.getBytes("UTF-8")); //$NON-NLS-1$ + // fos.close(); + // } + // catch (Exception e) + // { + // log.error(e); + // } + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, verify_request_xml, data); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getLocRefContent()); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime(), "sl")); + + return verify_request_xml; + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + // MOA + if (SigKZIDHelper.isMOASigned(so)) + { + log.debug("The signature is MOA signed -> getting XML content from DetachedLocRefMOA connector."); + DetachedLocRefMOAConnector moa_conn = new DetachedLocRefMOAConnector(this.environment.getProfile(), "loc ref not needed here"); + return moa_conn.prepareXMLContent(data, so); + + // MOCCA + } else if (SigKZIDHelper.isMOCCASigned(so)) { + log.debug("MOCCA signature detected."); + String algorithmId = SigKZIDHelper.parseAlgorithmId(so.id); + log.debug("Algorithm = " + algorithmId); + LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId); + return mocca_connector.prepareXMLContent(data, so); + + // ATRUST + } else if (SigKZIDHelper.isATrustSigned(so)) { + log.debug("ATrust signature detected"); + MOASoapWithAttachmentConnector moaConn = new MOASoapWithAttachmentConnector(this.params); + moaConn.reInitVerifyTemplate(MOASoapWithAttachmentConnector.ATRUST_VERIFY_TEMPLATE_KEY); + return moaConn.prepareXMLContent(data, so); + } + // TD + else if (SigKZIDHelper.isBKUSigned(so)) { + log.debug("TD signature signature detected."); + return prepareXMLContent(data, so); + } + // unknown + else { + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "Unsupported signature (" + so.id + ", " +so.kz + "). Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + } + + /** + * Prepares the XML content the holds the actual signature data. + * + *

+ * This strongly rebuilds the XML content as retuned from a sign request. + *

+ * + * @param data + * The data. + * @param so + * The signature object containing the signature information. + * @return Returns the XML content. + * @throws ConnectorException + * f.e. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + + String ids_string = so.getSigID(); + String[] ids = SignatureObject.parseSigIds(ids_string); + + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + { +// byte[] data_value = data.getData(); +// byte[] data_value_hash = CodingHelper.buildDigest(data_value); + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + // SIG id replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_REF_REPLACE, ids[1]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_REF_REPLACE, ids[3]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_OBJ_URI_REPLACE, ids[2]); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_OBJ_URI_REPLACE, ids[4]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, ids[0]); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "bku.sign.KeyboxIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "bku.sign.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "bku.sign.url"; //$NON-NLS-1$ + + /** + * BKU template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/bku."; + + /** + * signing file template sufix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; + + /** + * verifing template file sufix + */ + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + + /** + * verifing file template key sufix + */ + protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "bku.verify.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "bku.verify.template.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "bku.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String loc_ref_content = null; + + protected String sign_keybox_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String loc_ref_content) throws ConnectorException + { + this.profile = profile; + + this.loc_ref_content = loc_ref_content; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); + + String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; + + // try to load template from file + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + // when first load failed (the template file does'nt exist), load it from default template file + if(this.sign_request_template == null) + { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + } + + if (this.sign_request_template == null) + { + throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + // verify + + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + + // try to load template file for verifing + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + + if(this.verify_request_template == null) + { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + } + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + // load template key file + String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + VERIFY_TEMPLATE_SUFIX; + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + if(this.verify_template == null) + { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the LocRef content. + * + * @return Returns the LocRef content. + */ + public String getLocRefContent() + { + return this.loc_ref_content; + } + + /** + * Returns the sign keybox identifier. + * + * @return Returns the sign keybox identifier. + */ + public String getSignKeyboxIdentifier() + { + return this.sign_keybox_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, + String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + } + + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, true); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java new file mode 100644 index 0000000..170cc45 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java @@ -0,0 +1,666 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.UnsupportedEncodingException; +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * @author wprinz + * + */ +public class EnvelopedBase64BKUConnector implements Connector, LocalConnector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + + /** + * The log. + */ + private static Log log = LogFactory.getLog(EnvelopedBase64BKUConnector.class); + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + *

+ * This is the new "hotfix" base64 connector. + *

+ * + * @param profile + * The profile from which the Environment should be assembled. + * @throws ConnectorException + * f.e. + */ + public EnvelopedBase64BKUConnector(String profile) throws ConnectorException + { + this.environment = new Environment(profile); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); +// DebugHelper.debugStringToFile(sign_request_xml, "BKU_EnvB64_sign_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, sign_request_xml); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "BKU_EnvB64_sign_response.xml"); //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); +// DebugHelper.debugStringToFile(verify_request_xml, "BKU_EnvB64_verify_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, verify_request_xml); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "BKU_EnvB64_verify_response.xml"); //$NON-NLS-1$ + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + +// /** +// * This emthod extracts id-values from a text. The id is given by the name. +// * +// * @param text +// * the id-value that should extract from +// * @param name +// * the id-key +// * @return the value of the given key in the text +// */ +// private String extractId(String text, String name) +// { +// String id = null; +// int start_idx = text.indexOf(name) + name.length(); +// int end_idx = text.indexOf("\"", start_idx); +// +// // TODO hotfix! +// final int quot_end_idx = end_idx; +// final int squot_end_idx = text.indexOf("'", start_idx); +// end_idx = Math.min(quot_end_idx, squot_end_idx); +// // TODO hotfix end! +// +// id = text.substring(start_idx, end_idx); +// if (log.isDebugEnabled()) +// { +// log.debug("extract id:" + name + id); +// } +// return id; +// } + + /** + * Prepares the XML content the holds the actual signature data. + * + *

+ * This strongly rebuilds the XML content as retuned from a sign request. + *

+ * + * @param data + * The data. + * @param so + * The signature object containing the signature information. + * @return Returns the XML content. + * @throws ConnectorException + * f.e. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + String ids_string = so.getSigID(); + String[] ids = SignatureObject.parseSigIds(ids_string); + + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + byte[] data_value = BKUHelper.prepareEnvelopingData(data); + { + byte[] data_value_hash = CodingHelper.buildDigest(data_value, algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + // SIG id replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_REF_REPLACE, ids[1]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_REF_REPLACE, ids[3]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_OBJ_URI_REPLACE, ids[2]); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Base64 content replace + String base64 = CodingHelper.encodeBase64(data_value); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_OBJ_URI_REPLACE, ids[4]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, ids[0]); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + + // Signed Properties hash + { + String sig_prop_hash = computeSignedPropertiesReplace(verify_xml, algSuite); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + protected String computeSignedPropertiesReplace(String verify_xml, AlgorithmSuiteObject algSuite) + { + try + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + return sig_prop_hash; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Very Strange: UTF-8 character encoding not supported.", e); + } + } + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequest:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); + String base64 = BKUHelper.prepareBase64Content(data); + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + log.debug("prepareSignRequest finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + +// log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + if (SigKZIDHelper.isMOASigned(so)) + { + log.debug("The signature is MOA signed -> getting XML content from Base64MOA connector."); + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(this.environment.getProfile()); + EnvelopingBase64MOAConnector moa_conn = new EnvelopingBase64MOAConnector(cp); + return moa_conn.prepareXMLContent(data, so); + } + else + { + return prepareXMLContent(data, so); + } + } + +/** + * Sends the request to the given URL. + * + * @param url + * The URL. + * @param request_string + * The request string. + * @return Returns the response string. + * @throws ConnectorException + * F.e. + */ + protected Properties sendRequest(String url, String request_string) throws ConnectorException + { + try + { + Properties response_properties = at.knowcenter.wag.egov.egiz.sig.connectors.BKUPostConnection.doPostRequest(url, request_string); + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(320, e); + } + } + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); + log.debug("BKU identifier: \"" + bkuIdentifier + "\""); + + SignSignatureObject so = BKUHelper.parseCreateXMLResponse(response_string, new HotfixIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "bku.sign.KeyboxIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "bku.sign.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "bku.sign.url"; //$NON-NLS-1$ + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "bku.verify.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "bku.verify.template.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "bku.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String sign_keybox_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile) throws ConnectorException + { + this.profile = profile; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); + + String sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + if (this.sign_request_template == null) + { + throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + log.debug("Verify request template filename = " + verify_request_filename); + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + log.debug("Verify request template = " + this.verify_request_template); + + String verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the sign keybox identifier. + * + * @return Returns the sign keybox identifier. + */ + public String getSignKeyboxIdentifier() + { + return this.sign_keybox_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, + String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + } + + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, false); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java new file mode 100644 index 0000000..c5e1513 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java @@ -0,0 +1,46 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; + +/** + * @author wprinz + * + */ +public class LocRefDetachedBKUConnector extends DetachedBKUConnector +{ + + /** + * @param connectorParameters + * @param loc_ref_content + * @throws ConnectorException + */ + public LocRefDetachedBKUConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException + { + super(connectorParameters, loc_ref_content); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java new file mode 100644 index 0000000..cfaa55d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; + +/** + * @author wprinz + * + */ +public class MultipartDetachedBKUConnector extends DetachedBKUConnector +{ + protected static final String MULTIPART_LOC_REF_CONTENT = "formdata:fileupload"; //$NON-NLS-1$ + + public MultipartDetachedBKUConnector(ConnectorParameters connectorParameters) throws ConnectorException + { + super(connectorParameters, MULTIPART_LOC_REF_CONTENT); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java new file mode 100644 index 0000000..58bdec6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java @@ -0,0 +1,135 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.UnsupportedEncodingException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * + *

+ * This is the old base64 connector. The difference is in the way the sign + * response is parsed and the verify content_xml. + *

+ * + * @author wprinz + * + */ +public class OldEnvelopingBase64BKUConnector extends EnvelopedBase64BKUConnector +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(OldEnvelopingBase64BKUConnector.class); + + // TODO implement signing - with old pre 2.7.2 BKUs... not really necessary + // though because this connector is only used for verification + + public OldEnvelopingBase64BKUConnector(String profile) throws ConnectorException + { + super(profile); + + this.environment = new OverriddenEnvironment(profile); + } + + + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector#computeSignedPropertiesReplace(java.lang.String) + */ + protected String computeSignedPropertiesReplace(String verify_xml, AlgorithmSuiteObject algSuite) + { + try + { + final String ETSI_QUALIFYING_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_QUALIFYING_PROPERTIES_END_TAG, hash_start) + ETSI_QUALIFYING_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_QUALIFYING_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:QualifyingProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + return sig_prop_hash; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Very Strange: UTF-8 character encoding not supported.", e); + } + } + + + + public static class OverriddenEnvironment extends EnvelopedBase64BKUConnector.Environment + { + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "bku.verify.template.base64old"; //$NON-NLS-1$ + + public OverriddenEnvironment(String profile) throws ConnectorException + { + super(profile); + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, e); + } + + String verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java new file mode 100644 index 0000000..72f181e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java @@ -0,0 +1,272 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.Serializable; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.AdditionalSignatureInformation; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.AlgorithmSignatureInformation; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.ConnectorSignatureInformation; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation; + +/** + * @author wprinz + * + */ +public class SignSignatureObject implements Serializable, MandatorySignatureInformation, ConnectorSignatureInformation, AlgorithmSignatureInformation, AdditionalSignatureInformation +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -2689261480444802213L; + + public String date = null; + public String issuer = null; + public String signatureValue = null; + + public String id = null; + public String kz = null; + + public String sigAlgorithm; + + public String sigTimeStamp; + + /** + * This is used to transport the response properties to the Detached signator. + */ + public Properties response_properties = null; + + /** + * The X509Certificate. + * + *

+ * This also provides the serial number and name. + *

+ */ + public X509Certificate x509Certificate = null; + + // dferbas + public Map subjectDNMap = new HashMap(); + public Map issuerDNMap = new HashMap(); + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getDate() + */ + public String getDate() + { + return this.date; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getIssuer() + */ + public String getIssuer() + { + return this.issuer; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getSerialNumber() + */ + public String getSerialNumber() + { + return this.x509Certificate.getSerialNumber().toString(); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getSignatureValue() + */ + public String getSignatureValue() + { + return this.signatureValue; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.ConnectorSignatureInformation#getSigID() + */ + public String getSigID() + { + return this.id; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.AlgorithmSignatureInformation#getSigKZ() + */ + public String getSigKZ() + { + return this.kz; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.AdditionalSignatureInformation#getName() + */ + public String getName() + { + return this.x509Certificate.getSubjectDN().toString(); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.AdditionalSignatureInformation#getX509Certificate() + */ + public X509Certificate getX509Certificate() + { + return this.x509Certificate; + } + + public String getSigAlgorithm() { + return this.sigAlgorithm; + } + + public String retrieveStringValue(String sigKey) + { + // mandatory + if (sigKey.equals(SignatureTypes.SIG_DATE)) + { + return getDate(); + } + if (sigKey.equals(SignatureTypes.SIG_VALUE)) + { + return getSignatureValue(); + } + if (sigKey.equals(SignatureTypes.SIG_ISSUER)) + { + return getIssuer(); + } + if (sigKey.equals(SignatureTypes.SIG_NUMBER)) + { + return getSerialNumber(); + } + + // connector + if (sigKey.equals(SignatureTypes.SIG_ID)) + { + return getSigID(); + } + + // algorithm + if (sigKey.equals(SignatureTypes.SIG_KZ)) + { + return getSigKZ(); + } + + // additional + if (sigKey.equals(SignatureTypes.SIG_NAME)) + { + return getName(); + } + + if (sigKey.equals(SignatureTypes.SIG_SUBJECT)) + { + return getName(); + } + + if (sigKey.equals(SignatureTypes.SIG_ALG)) { + return getSigAlgorithm(); + } + + throw new RuntimeException("The key '" + sigKey + "' is not a recognized SignatorObject member."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // dferbas + + + /** + * Get a timestamp if available as b64 string + * @see TimeStamper + * @return + */ + public String getSigTimeStamp() { + return this.sigTimeStamp; + } + + public Map getSubjectDNMap() { + if (this.subjectDNMap.size() == 0 && this.getX509Certificate() != null) { + //rpiazzi workaround + //the problem with atrust encoding special characters (Sonderzeichen) wrong + //led to this workaround. As special characters are of the form e.g. "&#xxx;" + //Example: for "Georg Müller" atrust returns "Georg Müller" + //By calling this.getX509Certificate().getSubjectDN().getName() you get "Georg Mü\;ller", + //After that the down called method fillDNMap replaces the "\" with a "+" + //Because of this the workaround in at.gv.egiz.pdfas.impl.signator.binary.BinarySignator_1_0_0.fillReplacesWithValues() + //which replaces the wrong codes of atrust with the special chars does not work + //------------------------------------------------------------------------------ + //The workaround here is to call this.getX509Certificate().getSubjectDN.toString() + //instead of this.getX509Certificate().getSubjectDN.getName() + if (this.getX509Certificate().getSubjectDN().toString().contains(";") || + this.getX509Certificate().getSubjectDN().toString().contains("#") || + this.getX509Certificate().getSubjectDN().toString().contains("&")) { + fillDNMap(this.getX509Certificate().getSubjectDN().toString(), this.subjectDNMap); + } + else { + fillDNMap(this.getX509Certificate().getSubjectDN().getName(), this.subjectDNMap); + } + //end workaround + } + return this.subjectDNMap; + } + + public String certSubjectDNPart(String key) { + return (String)this.getSubjectDNMap().get(key); + } + + public Map getIssuerDNMap() { + if (this.issuerDNMap.size() == 0 && this.getX509Certificate() != null) { + fillDNMap(this.getX509Certificate().getIssuerDN().getName(), this.issuerDNMap); + } + return this.issuerDNMap; + } + + public String certIssuerDNPart(String key) { + return (String)this.getIssuerDNMap().get(key); + } + + private void fillDNMap(String dn, Map dnMap) { + + // split at "," but not at "\," + String[] arr = dn.split("\\s*(? , + entry[1] = entry[1].replaceAll("\\\\+", "+"); // \+ -> + + entry[1] = entry[1].replaceAll("\\\\\"", "\""); // \" -> " + entry[1] = entry[1].replaceAll("\\\\\\\\", "\\"); // \\ -> \ + entry[1] = entry[1].replaceAll("\\\\<,", "<"); // \< -> < + entry[1] = entry[1].replaceAll("\\\\>", ">"); // \> -> > + entry[1] = entry[1].replaceAll("\\\\;", ";"); // \; -> ; + entry[1] = entry[1].replaceAll("\\\\#", "#"); // \# -> # + + dnMap.put(entry[0], entry[1]); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java new file mode 100644 index 0000000..4eb6e39 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java @@ -0,0 +1,76 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +//package at.knowcenter.wag.egov.egiz.sig.connectors.bku; +// +//import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +//import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +// +///** +// * @author wprinz +// * +// */ +//public abstract class SignSignatureObjectHelper +//{ +// public static String retrieveStringValueFromSignatureObject (SignSignatureObject so, String key) +// { +// // mandatory +// if (key.equals(SignatureTypes.SIG_DATE)) +// { +// return so.getDate(); +// } +// if (key.equals(SignatureTypes.SIG_VALUE)) +// { +// return so.getSignatureValue(); +// } +// if (key.equals(SignatureTypes.SIG_ISSUER)) +// { +// return so.getIssuer(); +// } +// if (key.equals(SignatureTypes.SIG_NUMBER)) +// { +// return so.getSerialNumber(); +// } +// +// // connector +// if (key.equals(SignatureTypes.SIG_ID)) +// { +// return so.getSigID(); +// } +// +// // algorithm +// if (key.equals(SignatureTypes.SIG_KZ)) +// { +// return so.getSigKZ(); +// } +// +// // additional +// if (key.equals(SignatureTypes.SIG_NAME)) +// { +// return so.getName(); +// } +// +// throw new RuntimeException("The key '" + key + "' is not a recognized SignatorObject member."); //$NON-NLS-1$ //$NON-NLS-2$ +// } +// +//} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java new file mode 100644 index 0000000..ea90841 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java @@ -0,0 +1,661 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.DetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * Connects to MOA providing the Data detached as LocRef on a local resource. + * + * @author wprinz + */ +public class DetachedLocRefMOAConnector implements Connector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + /** + * The SIG_ID prefix. + */ + // public static final String SIG_ID_PREFIX = "etsi-bku-detached@"; //$NON-NLS-1$ + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedLocRefMOAConnector.class); + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param profile + * The profile from which the Environment should be assembled. + * @throws SettingsException + * f.e. + * @throws SignatureException + * f.e. + */ + public DetachedLocRefMOAConnector(String profile, String signature_data_url) throws ConnectorException + { + this.environment = new Environment(profile, signature_data_url); + } + + protected String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequestDetached:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_key_identifier = this.environment.getSignKeyIdentifier(); + String loc_ref_content = this.environment.getSignatureDataUrl(); + String mime_type = data.getMimeType(); + if (log.isDebugEnabled()) + { + log.debug("sign keybox identifier = " + sign_key_identifier); //$NON-NLS-1$ + log.debug("LocRefContent = " + loc_ref_content); //$NON-NLS-1$ + log.debug("mime type = " + mime_type); //$NON-NLS-1$ + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEY_IDENTIFIER_REPLACE, sign_key_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + + log.debug("prepareSignRequestDetached finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector#analyzeSignResponse(java.util.Properties) + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new DetachedLocRefMOAIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); +// DebugHelper.debugStringToFile(sign_request_xml, "MOA_DetLocRef_sign_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_SIGN, sign_request_xml); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "MOA_DetLocRef_sign_response.xml"); //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_VERIFY, verify_request_xml); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getSignatureDataUrl()); + + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + { +// byte[] data_value = data.getData(); +// byte[] data_value_hash = CodingHelper.buildDigest(data_value); + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + protected Properties sendRequest(String url, String mode, String request_string) throws ConnectorException + { + try + { + Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(330, e); + } + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moa.sign.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moa.sign.url"; //$NON-NLS-1$ + + /** + * MOA template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/moa."; + + /** + * signing file template sufix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; + + /** + * verifing template file sufix + */ + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + + /** + * verifing file template key sufix + */ + protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moa.verify.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moa.verify.template.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "moa.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key of the trust profile id. + */ + protected static final String VERIFY_TRUST_PROFILE_ID = "moa.verify.TrustProfileID"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String signature_data_url = null; + + protected String sign_key_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String verify_trust_profile_id = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws SettingsException + * f.e. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String signature_data_url) throws ConnectorException + { + this.profile = profile; + + this.signature_data_url = signature_data_url; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); + + String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; + + // try to load template from file + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + if (this.sign_request_template == null) + { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + } + + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + if (this.sign_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + + // try to load template file for verifing + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + + if (this.verify_request_template == null) + { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + } + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + // load template key file + String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_TEMPLATE_SUFIX; + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + if (this.verify_template == null) + { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.verify_trust_profile_id = settings.getValueFromKey(VERIFY_TRUST_PROFILE_ID); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the URL where to load the detached data from. + * + * @return Returns the URL where to load the detached data from. + */ + public String getSignatureDataUrl() + { + return this.signature_data_url; + } + + /** + * Returns the sign key identifier. + * + * @return Returns the sign key identifier. + */ + public String getSignKeyIdentifier() + { + return this.sign_key_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the verify trust profile id. + * + * @return Returns the verify trust profile id. + */ + public String getVerifyTrustProfileId() + { + return this.verify_trust_profile_id; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, true); + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + if (!SigKZIDHelper.isMOASigned(so)) + { + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(this.environment.getProfile()); + DetachedBKUConnector bku_connector = new DetachedBKUConnector(cp, "not needed here"); + return bku_connector.prepareXMLContent(data, so); + } + else + { + return prepareXMLContent(data, so); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java new file mode 100644 index 0000000..6f2d171 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java @@ -0,0 +1,638 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.OldMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * @author wprinz + * + */ +public class EnvelopingBase64MOAConnector implements Connector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + /** + * The log. + */ + private static Log log = LogFactory.getLog(EnvelopingBase64MOAConnector.class); + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + protected ConnectorParameters params = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param profile + * The profile from which the Environment should be assembled. + * @throws ConnectorException + * f.e. + */ + public EnvelopingBase64MOAConnector(ConnectorParameters connectorParameters) throws ConnectorException + { + this.params = connectorParameters; + this.environment = new Environment(connectorParameters.getProfileId(), connectorParameters.getSignatureKeyIdentifier()); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); + log.debug("sign_request_xml = " + sign_request_xml); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_SIGN, sign_request_xml); + + log.debug("response_string = " + response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY));; //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_VERIFY, verify_request_xml); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + protected Properties sendRequest(String url, String mode, + String request_string) throws ConnectorException + { + try + { + Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(330, e); + } + } + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + protected String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequest:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_key_identifier = this.environment.getSignKeyIdentifier(); + String base64 = BKUHelper.prepareBase64Content(data); + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEY_IDENTIFIER_REPLACE, sign_key_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + log.debug("prepareSignRequest finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); + + String returnHashInputDataElement = ""; + if (this.params.isReturnHashInputData()) + { + returnHashInputDataElement = MOASoapWithAttachmentConnector.RETURN_HASH_INPUT_DATA; + } + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.RETURN_HASH_INPUT_DATA_REPLACE, returnHashInputDataElement); + + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime())); + + + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new OldMOAIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the XML content the holds the actual signature data. + * + *

+ * This strongly rebuilds the XML content as retuned from a sign request. + *

+ * + * @param data + * The data. + * @param so + * The signature object containing the signature information. + * @return Returns the XML content. + * @throws ConnectorException + * f.e. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + byte[] data_value = BKUHelper.prepareEnvelopingData(data); + { + byte[] data_value_hash = CodingHelper.buildDigest(data_value, algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + // Base64 content replace -> do this at last for performance + String base64 = CodingHelper.encodeBase64(data_value); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moa.sign.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moa.sign.url"; //$NON-NLS-1$ + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moa.verify.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moa.verify.template.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "moa.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key of the trust profile id. + */ + protected static final String VERIFY_TRUST_PROFILE_ID = "moa.verify.TrustProfileID"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String sign_key_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String verify_trust_profile_id = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String signKeyIdentifier) throws ConnectorException + { + this.profile = profile; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + if (signKeyIdentifier != null) + { + this.sign_key_identifier = signKeyIdentifier; + } + else + { + this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); + } + + String sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + if (this.sign_request_template == null) + { + throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + if (this.verify_request_template == null) + { + throw new ConnectorException(300, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + String verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + if (this.verify_template == null) + { + throw new ConnectorException(300, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.verify_trust_profile_id = settings.getValueFromKey(VERIFY_TRUST_PROFILE_ID); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the sign key identifier. + * + * @return Returns the sign key identifier. + */ + public String getSignKeyIdentifier() + { + return this.sign_key_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the verify trust profile id. + * + * @return Returns the verify trust profile id. + */ + public String getVerifyTrustProfileId() + { + return this.verify_trust_profile_id; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, + String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, false); + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + if (!SigKZIDHelper.isMOASigned(so)) + { + if (SigKZIDHelper.isOldBKU(so)) + { + OldEnvelopingBase64BKUConnector bku_connector = new OldEnvelopingBase64BKUConnector(this.environment.getProfile()); + return bku_connector.prepareXMLContent(data, so); + } + else + { + EnvelopedBase64BKUConnector bku_connector = new EnvelopedBase64BKUConnector(this.environment.getProfile()); + return bku_connector.prepareXMLContent(data, so); + } + } + else + { + return prepareXMLContent(data, so); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java new file mode 100644 index 0000000..b52b39b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java @@ -0,0 +1,152 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.commons.httpclient.util.EncodingUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class FilePartMR extends + org.apache.commons.httpclient.methods.multipart.FilePart { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(FilePartMR.class); + + /** Content dispostion characters */ + protected static final String CONTENT_ID = "Content-Id: "; + + /** Content dispostion as a byte array */ + protected static final byte[] CONTENT_ID_BYTES = + EncodingUtil.getAsciiBytes(CONTENT_ID); + + private String contentID = ""; + + public FilePartMR(String arg0, PartSource arg1) { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, File arg1) throws FileNotFoundException { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, String arg1, File arg2) + throws FileNotFoundException { + super(arg0, arg1, arg2); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, PartSource arg1, String arg2, String arg3) { + super(arg0, arg1, arg2, arg3); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, File arg1, String arg2, String arg3) + throws FileNotFoundException { + super(arg0, arg1, arg2, arg3); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, String arg1, File arg2, String arg3, + String arg4) throws FileNotFoundException { + super(arg0, arg1, arg2, arg3, arg4); + // TODO Auto-generated constructor stub + } + + + public void setContentID(String contentid) { + this.contentID = contentid; + } + + public String getContentID() { + return this.contentID; + } + + /** + * Write the content id header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentIDHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContendID instead of ContentDisposition(OutputStream out)"); + out.write(CONTENT_ID_BYTES); + out.write(EncodingUtil.getAsciiBytes(getContentID())); + } + + /** + * Write all the data to the output stream. + * If you override this method make sure to override + * #length() as well + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + public void send(OutputStream out) throws IOException { + LOG.trace("enter send(OutputStream out)"); + sendStart(out); + + sendContentIDHeader(out); + sendContentTypeHeader(out); + sendTransferEncodingHeader(out); + sendEndOfHeader(out); + sendData(out); + sendEnd(out); + } + + + /** + * Return the full length of all the data. + * If you override this method make sure to override + * #send(OutputStream) as well + * + * @return long The length. + * @throws IOException If an IO problem occurs + */ + public long length() throws IOException { + LOG.trace("enter length()"); + if (lengthOfData() < 0) { + return -1; + } + ByteArrayOutputStream overhead = new ByteArrayOutputStream(); + sendStart(overhead); + + sendContentIDHeader(overhead); + sendContentTypeHeader(overhead); + sendTransferEncodingHeader(overhead); + sendEndOfHeader(overhead); + sendEnd(overhead); + return overhead.size() + lengthOfData(); + } + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java new file mode 100644 index 0000000..8cb9a92 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java @@ -0,0 +1,228 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * @author wprinz + * + */ +public class MOAHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(MOAHelper.class); + + /** + * This method parses the MOA-Response string. + * + *

+ * It separates the SignatureValue, X509IssuerName, SigningTime, + * X509SerialNumber, X509Certificate, CertDigest and DigestValues. If the + * X509Certificate is extracted it would be stored in the certificates + * directory. + *

+ * + * @param xmlResponse + * the response string from the MOA sign-request + * @throws ConnectorException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + public static SignSignatureObject parseCreateXMLResponse(String xmlResponse, IdFormatter id_formatter, ConnectorEnvironment environment) throws ConnectorException + { + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); //$NON-NLS-1$ + Pattern sig_val_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); //$NON-NLS-1$ + Pattern iss_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); //$NON-NLS-1$ + Pattern sig_tim_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); //$NON-NLS-1$ + Pattern ser_num_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); //$NON-NLS-1$ + Pattern sig_cer_p_e = Pattern.compile(""); //$NON-NLS-1$ + + // Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + // //$NON-NLS-1$ + // Pattern sig_cer_d_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + // Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + // //$NON-NLS-1$ + // Pattern dig_val_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + // Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + // Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + // Matcher dig_val_m_s = dig_val_p_s.matcher(xmlResponse); + // Matcher dig_val_m_e = dig_val_p_e.matcher(xmlResponse); + + // SignatureValue + String sig_val = null; + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = BKUHelper.removeAllWhitespace(xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start())); + } + log.debug("sig_val = " + sig_val); //$NON-NLS-1$ + + // X509IssuerName + String iss_nam = null; + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + } + log.debug("iss_nam = " + iss_nam); //$NON-NLS-1$ + + // X509SerialNumber + String ser_num = null; + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = BKUHelper.removeAllWhitespace(xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start())); + } + log.debug("ser_num = " + ser_num); //$NON-NLS-1$ + + // SigningTime + String sig_tim = null; + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + } + log.debug("sig_tim = " + sig_tim); //$NON-NLS-1$ + + // CertDigest + // if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + // { + // String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), + // sig_cer_d_m_e.start()); + // if (dig_val_m_s.find() && dig_val_m_e.find()) + // { + // sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + // //sigObj.setX509CertificateDigest(sig_dig); + // } + // } + + // X509Certificate + X509Certificate cert = null; + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + String sig_cer = BKUHelper.removeAllWhitespace(xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start())); + + try + { + byte[] der = CodingHelper.decodeBase64(sig_cer); + ByteArrayInputStream bais = new ByteArrayInputStream(der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$ + cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + } + catch (UnsupportedEncodingException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (CertificateException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (IOException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + } + log.debug("X509Certificate = " + cert); //$NON-NLS-1$ + + if (log.isDebugEnabled()) + { + + String cert_iss = cert.getIssuerDN().getName(); + log.debug("certificate's issuer = " + cert_iss); //$NON-NLS-1$ + log.debug("response's issuer = " + iss_nam); //$NON-NLS-1$ + log.debug("issuer matches = " + cert_iss.equals(iss_nam)); //$NON-NLS-1$ + log.debug("ser number matches = " + cert.getSerialNumber().toString().equals(ser_num)); //$NON-NLS-1$ + } + + SignSignatureObject so = new SignSignatureObject(); + so.date = sig_tim; + so.issuer = iss_nam; + so.signatureValue = sig_val; + so.x509Certificate = cert; + + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); + + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); + so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); + + String defaultCertAlg = environment.getDefaultAlgForCert(cert); + + if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { + // do not embed default alg + algs = null; + } + + + + so.id = id_formatter.formatIds(null, algs); + + return so; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java new file mode 100644 index 0000000..7aa3d7b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java @@ -0,0 +1,277 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import java.util.Vector; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; + +import at.knowcenter.wag.egov.egiz.exceptions.WebException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; + +/** + * @author wprinz + * + */ +public final class MOASoapConnection +{ + /** + * MOA siganture verification mode + */ + public static final String SERVICE_VERIFY = "SignatureVerification"; //$NON-NLS-1$ + + /** + * MOA siganture creation mode + */ + public static final String SERVICE_SIGN = "SignatureCreation"; //$NON-NLS-1$ + + /** + * The log. + */ + private static Log log = LogFactory.getLog(MOASoapConnection.class); + + /** + * This method connects the moa server getting the requestString, the given + * serviseMode and the endpointUrl. The requestString is the envelope of the + * SOAP Message send and recieve by the AXIS module. The Response SOAP message + * of the MOA server is parsed by AXIS and the message envelope is send back + * to the calling method. + * + * @param requestString + * the request string (XML) to send. + * @param serviceMode + * the mode which connect to MOA + * @param endpointURL + * the URL which the MOA server is running + * @return the response string (XML) of the MOA server + * @throws WebException + */ + public static Properties connectMOA(String requestString, String serviceMode, + String endpointURL) throws WebException + { + try + { + if (log.isDebugEnabled()) + { + log.debug(serviceMode); + log.debug(endpointURL); + } + // Parser/DOMBuilder instanzieren + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + // XML Datei in einen DOM-Baum umwandeln + ByteArrayInputStream bais = new ByteArrayInputStream(requestString.getBytes("UTF-8")); //$NON-NLS-1$ + Document xmlRequest = builder.parse(bais); + + // Call öffnen + Call call = null; + + // Neues BodyElement anlegen und mit dem DOM-Baum füllen + SOAPBodyElement body = new SOAPBodyElement(xmlRequest.getDocumentElement()); + SOAPBodyElement[] params = new SOAPBodyElement[] { body }; + + // AXIS-Server instanzieren + Service service = ServiceFactory.newInstance().createService(new QName(serviceMode)); + call = service.createCall(); + call.setTargetEndpointAddress(endpointURL); + + // Call auslösen und die Antworten speichern + log.debug("Calling MOA: " + endpointURL); //$NON-NLS-1$ + Vector responses = (Vector) call.invoke(params); + + // Erstes Body Element auslesen + SOAPBodyElement response = (SOAPBodyElement) responses.get(0); + + // Aus der Response den DOM-Baum lesen + Document root_response = response.getAsDocument(); + log.debug("Return from MOA: " + serviceMode); //$NON-NLS-1$ + + // XML-Formatierung konfiguieren + OutputFormat format = new OutputFormat((Document) root_response); + format.setLineSeparator("\n"); //$NON-NLS-1$ + format.setIndenting(false); + format.setPreserveSpace(true); + format.setOmitXMLDeclaration(false); + format.setEncoding("UTF-8"); //$NON-NLS-1$ + + // Ausgabe der Webservice-Antwort auf die Konsole + // XMLSerializer conSerializer = new XMLSerializer(System.out, format); + // conSerializer.serialize(root_response); + + // Ausgabe der Webservice-Antwort in Datei + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XMLSerializer response_serializer = new XMLSerializer(baos, format); + response_serializer.serialize(root_response); + String response_string = baos.toString("UTF-8"); //$NON-NLS-1$ + + Properties response_properties = new Properties(); + response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, response_string); + + return response_properties; + } + catch (Exception e) + { + throw new WebException(e); + } + // serialize signature only + + // if + // (root_response.getDocumentElement().getLocalName().equals("CreateXMLSignatureResponse")) + // { + // Element signature = (Element) + // root_response.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", + // "Signature").item(0); + // String signatureFile = getProperty(mode + "Request").substring(0, + // getProperty(mode + + // "Request").lastIndexOf('.')) + ".Signature.xml"; + // fileSerializer = new XMLSerializer(new FileOutputStream(signatureFile), + // format); + // fileSerializer.serialize(signature); + // } + + } + + public static Properties doPostRequestMultipart(String url, String serviceMode, String request, + final SignatureData data) throws HttpException, IOException + { + log.debug("doPostRequestMultipart:"); //$NON-NLS-1$ + + // Wrap XMLRequest into SOAP-Body + request = "" + + request.substring(request.indexOf("?>")+2)+ // do not forget to eliminate any additional XML-header + ""; + + StringPartMR xmlpart = new StringPartMR("test", request, "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + xmlpart.setContentType("text/xml"); + xmlpart.setContentID(""); + + // add file to be signed + final String filename = data.getMimeType().equals("application/pdf") ? "myfile.pdf" : "myfile.txt"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + PartSource ps = new PartSource() { + public InputStream createInputStream() throws IOException + { + return data.getDataSource().createInputStream(); + } + + public String getFileName() + { + return filename; + } + + public long getLength() + { + return data.getDataSource().getLength(); + } + }; + //ByteArrayPartSource baps = new ByteArrayPartSource(filename, data.getData()); + FilePartMR filepart = new FilePartMR("fileupload", ps); //$NON-NLS-1$ + filepart.setContentType(data.getMimeType()); + filepart.setContentID(""); + + // not really needed since external referenced data has to be taken "as-is" (binary stream) for + // digest calculation, so neither content type nor charset is relevant + filepart.setCharSet(data.getCharacterEncoding()); + + Part[] parts = { xmlpart, filepart }; + + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); //$NON-NLS-1$ + + PostMethod post_method = new PostMethod(url); + post_method.setParams(method_params); + + + post_method.addRequestHeader("SOAPAction",serviceMode); + +// MultipartRequestEntity mprqe = new MultipartRequestEntity(parts, post_method.getParams()); + MultipartRelatedEntity mprqe = new MultipartRelatedEntity(parts, post_method.getParams()); + mprqe.setContentType("text/xml"); + mprqe.setStartID(""); + + post_method.setRequestEntity(mprqe); + // post_method.setRequestHeader("Content-Type", "multipart/related; type=\"text/xml\"; boundary=\""+"\""); + HttpClient http_client = new HttpClient(); + + int method_response = http_client.executeMethod(post_method); + log.debug("method_response = " + method_response); //$NON-NLS-1$ + + Properties response_properties = new Properties(); + + if (log.isDebugEnabled()) + { + Header[] response_headers = post_method.getResponseHeaders(); + for (int i = 0; i < response_headers.length; i++) + { + log.debug(" response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + Header server_header = post_method.getResponseHeader("Server"); //$NON-NLS-1$ + + response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, server_header.getValue()); + + String charset = post_method.getResponseCharSet(); + log.debug("MOA response charset is \"" + charset + "\""); + if (!"UTF-8".equalsIgnoreCase(charset) && !"UTF8".equalsIgnoreCase(charset)) //$NON-NLS-1$ + { + log.warn("MOA response charset is not UTF-8!"); //$NON-NLS-1$ + } + String response_string = post_method.getResponseBodyAsString(); + + response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, response_string); + + log.debug("doPostRequestMultipart finished."); //$NON-NLS-1$ + return response_properties; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java new file mode 100644 index 0000000..db0a04f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java @@ -0,0 +1,745 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.DetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connects to MOA providing the Data detached as LocRef on a local resource. + * + * @author wprinz + */ +public class MOASoapWithAttachmentConnector implements Connector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + public static final String ATRUST_VERIFY_TEMPLATE_KEY = "atrust.verify.template.detached"; + +/** + * The SIG_ID prefix. + */ + // public static final String SIG_ID_PREFIX = "etsi-bku-detached@"; //$NON-NLS-1$ + /** + * The log. + */ + private static Log log = LogFactory.getLog(MOASoapWithAttachmentConnector.class); + + protected static final String MULTIPART_LOC_REF_CONTENT = "formdata:fileupload"; //$NON-NLS-1$ + + protected static final String RETURN_HASH_INPUT_DATA = ""; //$NON-NLS-1$ + + /** + * The connector parameters. + */ + protected ConnectorParameters params = null; + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param connectorParameters + * The parameters for this connector. + * @throws ConnectorException + * f.e. + */ + public MOASoapWithAttachmentConnector(ConnectorParameters connectorParameters) throws ConnectorException + { + this.params = connectorParameters; + this.environment = new Environment(this.params.getProfileId(), this.params.getSignatureKeyIdentifier(), MULTIPART_LOC_REF_CONTENT); + } + + protected String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequestDetached:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_key_identifier = this.environment.getSignKeyIdentifier(); + String loc_ref_content = this.environment.getSignatureDataUrl(); + String mime_type = data.getMimeType(); + if (log.isDebugEnabled()) + { + log.debug("sign keybox identifier = " + sign_key_identifier); //$NON-NLS-1$ + log.debug("LocRefContent = " + loc_ref_content); //$NON-NLS-1$ + log.debug("mime type = " + mime_type); //$NON-NLS-1$ + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEY_IDENTIFIER_REPLACE, sign_key_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + + log.debug("prepareSignRequestDetached finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector#analyzeSignResponse(java.util.Properties) + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new DetachedLocRefMOAIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); +// DebugHelper.debugStringToFile(sign_request_xml, "MOA_DetLocRef_sign_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_SIGN, sign_request_xml, data); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "MOA_DetLocRef_sign_response.xml"); //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_VERIFY, verify_request_xml, data); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getSignatureDataUrl()); + + String returnHashInputDataElement = ""; + if (this.params.isReturnHashInputData()) + { + returnHashInputDataElement = RETURN_HASH_INPUT_DATA; + } + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.RETURN_HASH_INPUT_DATA_REPLACE, returnHashInputDataElement); + + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime())); + + + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + + // MOA + if (SigKZIDHelper.isMOASigned(so)) { + log.debug("MOA signature detected."); + return prepareXMLContent(data, so); + + // MOCCA + } else if (SigKZIDHelper.isMOCCASigned(so)) { + log.debug("MOCCA signature detected."); + String algorithmId = SigKZIDHelper.parseAlgorithmId(so.id); + log.debug("Algorithm = " + algorithmId); + LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId); + return mocca_connector.prepareXMLContent(data, so); + + // ATrust + } else if (SigKZIDHelper.isATrustSigned(so)) { + log.debug("A-Trust signature detected."); + this.environment.reInitVerifyTemplate(ATRUST_VERIFY_TEMPLATE_KEY); + return prepareXMLContent(data, so); + + // TD bku + } else if (SigKZIDHelper.isBKUSigned(so)) { + log.debug("TD bku signature detected."); + DetachedBKUConnector bku_connector = new DetachedBKUConnector(this.params, "not needed here"); + return bku_connector.prepareXMLContent(data, so); + } else { + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "Unsupported signature (" + so.id + ", " +so.kz + "). Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + + } + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + + String verify_xml = null; + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + + // data digest replace + { +// byte[] data_value = data.getData(); +// byte[] data_value_hash = CodingHelper.buildDigest(data_value); + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + + protected Properties sendRequest(String url, String mode, String request_string, SignatureData data) throws ConnectorException + { + try + { + // for performance measurement +// long startTime = 0; +// if (log.isInfoEnabled()) { +// startTime = System.currentTimeMillis(); +// } + +// Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); + log.debug("Connecting to " + url); + Properties response_properties = MOASoapConnection.doPostRequestMultipart(url,mode, request_string, data ); + + // for performance measurement +// if (log.isInfoEnabled()) { +// long endTime = System.currentTimeMillis(); +// String toReport = "MOA-PROCESSING;-;-;" + (endTime - startTime) + ";"; +// log.info(toReport); +// } + + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(330, e); + } + } + + public void reInitVerifyTemplate(String templatePropKey) throws ConnectorException { + this.environment.reInitVerifyTemplate(templatePropKey); + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moa.sign.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moa.sign.url"; //$NON-NLS-1$ + + /** + * MOA template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/moa."; + + /** + * signing file template sufix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; + + /** + * verifing template file sufix + */ + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + + /** + * verifing file template key sufix + */ + protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moa.verify.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moa.verify.template.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "moa.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key of the trust profile id. + */ + protected static final String VERIFY_TRUST_PROFILE_ID = "moa.verify.TrustProfileID"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String signature_data_url = null; + + protected String sign_key_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String verify_trust_profile_id = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + + public void reInitVerifyTemplate(String templatePropKey) throws ConnectorException { + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + String verify_request_filename = getConnectorValueFromProfile(settings, this.profile, templatePropKey); + this.verify_template = settings.readInternalResourceAsString(verify_request_filename); + + } + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws SettingsException + * f.e. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String signKeyIdentifier, String signature_data_url) throws ConnectorException + { + this.profile = profile; + + this.signature_data_url = signature_data_url; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + if (signKeyIdentifier != null) + { + this.sign_key_identifier = signKeyIdentifier; + } + else + { + this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); + } + + String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; + + // try to load template from file + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + if (this.sign_request_template == null) + { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + } + + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + if (this.sign_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + + // try to load template file for verifing + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + + if (this.verify_request_template == null) + { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + } + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + // load template key file + String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_TEMPLATE_SUFIX; + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + if (this.verify_template == null) + { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.verify_trust_profile_id = settings.getValueFromKey(VERIFY_TRUST_PROFILE_ID); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the URL where to load the detached data from. + * + * @return Returns the URL where to load the detached data from. + */ + public String getSignatureDataUrl() + { + return this.signature_data_url; + } + + /** + * Returns the sign key identifier. + * + * @return Returns the sign key identifier. + */ + public String getSignKeyIdentifier() + { + return this.sign_key_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the verify trust profile id. + * + * @return Returns the verify trust profile id. + */ + public String getVerifyTrustProfileId() + { + return this.verify_trust_profile_id; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, true); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java new file mode 100644 index 0000000..dd9f8b8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java @@ -0,0 +1,79 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.httpclient.util.EncodingUtil; + +public class MultipartRelatedEntity extends MultipartRequestEntity { + + /** The Content-Type for multipart/related. */ + private static final String MULTIPART_RELATED_CONTENT_TYPE = "multipart/related"; + + + private String startID; + + private String contentType; + + public MultipartRelatedEntity(Part[] parts, HttpMethodParams params) { + super(parts, params); + // TODO Auto-generated constructor stub + } + + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + + public String getStartID() { + return startID; + } + + + public void setStartID(String startID) { + this.startID = startID; + } + + + /* (non-Javadoc) + * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType() + */ + public String getContentType() { + StringBuffer buffer = new StringBuffer(MULTIPART_RELATED_CONTENT_TYPE); + buffer.append("; type=\""); + buffer.append(EncodingUtil.getAsciiString(this.contentType.getBytes())); + buffer.append("\"; start=\""); + buffer.append(EncodingUtil.getAsciiString(getStartID().getBytes())); + buffer.append("\"; boundary=\""); + buffer.append(EncodingUtil.getAsciiString(getMultipartBoundary())); + buffer.append("\""); + return buffer.toString(); + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java new file mode 100644 index 0000000..2efcbcc --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java @@ -0,0 +1,189 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.httpclient.util.EncodingUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class StringPartMR extends StringPart { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(StringPartMR.class); + + + /** Content dispostion characters */ + protected static final String CONTENT_ID = "Content-Id: "; + + /** Content dispostion as a byte array */ + protected static final byte[] CONTENT_ID_BYTES = + EncodingUtil.getAsciiBytes(CONTENT_ID); + + private String contentID = ""; + + public StringPartMR(String name, String value, String charset) { + super(name, value, charset); + // TODO Auto-generated constructor stub + } + + public StringPartMR(String name, String value) { + super(name, value); + // TODO Auto-generated constructor stub + } + + /** + * Write the content disposition header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendDispositionHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContendID instead of ContentDisposition(OutputStream out)"); + // Do nothing ! + } + + /** + * Write the content id header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentIDHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContendID instead of ContentDisposition(OutputStream out)"); + out.write(CONTENT_ID_BYTES); + out.write(EncodingUtil.getAsciiBytes(getContentID())); + } + + + /** + * Write the content type header to the specified output stream + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentTypeHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContentTypeHeader(OutputStream out)"); + String contentType = getContentType(); + if (contentType != null) { + out.write(CRLF_BYTES); + out.write(CONTENT_TYPE_BYTES); + out.write(EncodingUtil.getAsciiBytes(contentType)); + String charSet = getCharSet(); + if (charSet != null) { + out.write(CHARSET_BYTES); + out.write(EncodingUtil.getAsciiBytes(charSet)); + } + } + } + + /** + * Write the content transfer encoding header to the specified + * output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendTransferEncodingHeader(OutputStream out) throws IOException { + LOG.trace("enter sendTransferEncodingHeader(OutputStream out)"); + String transferEncoding = getTransferEncoding(); + if (transferEncoding != null) { + out.write(CRLF_BYTES); + out.write(CONTENT_TRANSFER_ENCODING_BYTES); + out.write(EncodingUtil.getAsciiBytes(transferEncoding)); + } + } + + public void setContentID(String contentid) { + this.contentID = contentid; + } + + public String getContentID() { + return this.contentID; + } + + /** + * Write the end of the header to the output stream + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendEndOfHeader(OutputStream out) throws IOException { + LOG.trace("enter sendEndOfHeader(OutputStream out)"); + out.write(CRLF_BYTES); + out.write(CRLF_BYTES); + } + + + /** + * Write all the data to the output stream. + * If you override this method make sure to override + * #length() as well + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + public void send(OutputStream out) throws IOException { + LOG.trace("enter send(OutputStream out)"); + sendStart(out); + + sendContentIDHeader(out); + sendContentTypeHeader(out); + sendTransferEncodingHeader(out); + sendEndOfHeader(out); + sendData(out); + sendEnd(out); + } + + + /** + * Return the full length of all the data. + * If you override this method make sure to override + * #send(OutputStream) as well + * + * @return long The length. + * @throws IOException If an IO problem occurs + */ + public long length() throws IOException { + LOG.trace("enter length()"); + if (lengthOfData() < 0) { + return -1; + } + ByteArrayOutputStream overhead = new ByteArrayOutputStream(); + sendStart(overhead); + + sendContentIDHeader(overhead); + sendContentTypeHeader(overhead); + sendTransferEncodingHeader(overhead); + sendEndOfHeader(overhead); + sendEnd(overhead); + return overhead.size() + lengthOfData(); + } + + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java new file mode 100644 index 0000000..12fc709 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java @@ -0,0 +1,623 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.mocca; + +import java.security.cert.X509Certificate; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connector for MOCCA. + * @author tknall + */ +public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + + private static Log log = LogFactory.getLog(LocRefDetachedMOCCAConnector.class); + + /** + * The connector parameters. + */ + protected ConnectorParameters params = null; + + /** + * The environment of this connector containing templates. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector according to the + * given profile. + * @param connectorParameters The connectot parameters. + * @throws ConnectorException Thrown in case of error. + */ + public LocRefDetachedMOCCAConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException { + this(connectorParameters, loc_ref_content, null); + } + + /** + * Constructor that builds the configuration environment for this connector according to the + * given profile. + * @param connectorParameters The connectot parameters. + * @param algorithmId The algorithm idenifier. + * @throws ConnectorException Thrown in case of error. + */ + public LocRefDetachedMOCCAConnector(ConnectorParameters connectorParameters, String loc_ref_content, String algorithmId) throws ConnectorException { + this.params = connectorParameters; + this.environment = new Environment(this.params.getProfileId(), loc_ref_content, algorithmId); + } + + /** + * Sends the request to the given URL. This method handles communication exceptions. + * The actual send work is done by doPostRequestMultipart. + * @see BKUPostConnection#doPostRequestMultipart(String, String, SignatureData) + * @param url The URL to send the request to. + * @param request_string The request XML. + * @param data The data. + * @return Returns the response properties containing among others the response XML. + * @throws ConnectorException Thrown in case of an error. + */ + protected Properties sendRequest(String url, String request_string, SignatureData data) throws ConnectorException { + try { + Properties response_properties = BKUPostConnection.doPostRequestMultipart(url, request_string, data); + return response_properties; + } catch (Exception e) { + ConnectorException se = new ConnectorException(320, e); + throw se; + } + } + + /** + * Starts a signature process. + * @param data The data to be signed. + * @return Returns the signature object containing the signed data. + * @throws ConnectorException Thrown in case of an error. + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException { + log.debug("doSign:"); + + String sign_request_xml = prepareSignRequest(data); + log.debug("sign_request_xml = " + sign_request_xml); + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, sign_request_xml, data); + + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); + return sso; + } + + /** + * Verification is not supported by MOCCA. Therefore this method always throws a + * {@link ConnectorException} with error code {@link ErrorCode#SIGNATURE_VERIFICATION_NOT_SUPPORTED}. + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException { + throw new ConnectorException(ErrorCode.SIGNATURE_VERIFICATION_NOT_SUPPORTED, "Signature Verification is not supported by MOCCA."); + } + + /** + * This method analyzes a signature response of the signature device. + * @param response_properties The response elements of the signature device. + * @return The parsed signed signature object. + * @throws ConnectorException Thrown in case of an error. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException { + log.debug("analyzeSignResponse:"); + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); + log.debug("BKU identifier: \"" + bkuIdentifier + "\""); + SignatureLayoutHandler sigLayout; + try { + sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier); + } catch (SettingsException e) { + throw new ConnectorException(e.getErrorCode(), e.getMessage()); + } + + BKUHelper.checkResponseForError(response_string); + +// SignSignatureObject so = MOCCAHelper.parseCreateXMLResponse(response_string, new DetachedMOCIdFormatter()); + SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string, this.environment); + so.response_properties = response_properties; + log.debug("analyzeSignResponse finished."); + return so; + } + + /** + * Verification is not supported by MOCCA. Therefore this method always throws a + * {@link ConnectorException} with error code {@link ErrorCode#SIGNATURE_VERIFICATION_NOT_SUPPORTED}. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException { + throw new ConnectorException(ErrorCode.SIGNATURE_VERIFICATION_NOT_SUPPORTED, "Signature Verification is not supported by MOCCA."); + } + + /** + * Prepares the signature request xml to be sent using the sign request template. + * @param data The signature data. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException Thrown in case of an error. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException { + log.debug("prepareSignRequestDetached:"); + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); + String mime_type = data.getMimeType(); + String loc_ref_content = this.environment.getLocRefContent(); + + if (log.isDebugEnabled()) { + log.debug("sign keybox identifier = " + sign_keybox_identifier); + log.debug("mime type = " + mime_type); + log.debug("loc_ref_content = " + loc_ref_content); + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + + log.debug("sign_request_xml = " + sign_request_xml); + log.debug("prepareSignRequestDetached finished."); + return sign_request_xml; + } + + /** + * Verification is not supported by MOCCA. Therefore this method always throws a + * {@link ConnectorException} with error code {@link ErrorCode#SIGNATURE_VERIFICATION_NOT_SUPPORTED}. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException { + throw new ConnectorException(ErrorCode.SIGNATURE_VERIFICATION_NOT_SUPPORTED, "Signature Verification is not supported by MOCCA."); + } + + /** + * Prepares the xml content of a signature creation request including the link to the signature data. + * @param data The signature data. + * @param so The signature object containing the signature information. + * @return Returns the xml content. + * @throws ConnectorException Thrown in case of an error. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException { + log.debug("prepareXMLContent:"); + try { + + String ids_string = so.getSigID(); + String sigId = this.parseSigId(ids_string); + + X509Certificate cert = so.getX509Certificate(); + + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + // template replacements + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, sigId); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + Pattern spPattern = Pattern.compile("(<(\\w+:)?SignedProperties.*>.*)"); + Matcher matcher = spPattern.matcher(verify_xml); + if (matcher.find()) { + log.debug("SignedProperties found."); + String string_to_be_hashed = matcher.group(1); + log.debug("SignedProperties string to be hashed: " + string_to_be_hashed); + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); + return verify_xml; + } catch (Exception e) { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + /** + * Holds environment configuration information like templates. + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment { + + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "moc.sign.KeyboxIdentifier"; + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moc.sign.request.detached"; + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moc.sign.url"; + + /** + * BKU template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/moc."; + + /** + * signing file template suffix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFFIX = ".sign.request.xml"; + + /** + * verifing template file suffix + */ + /* signature verification is not supported by mocca + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + */ + + /** + * verifing file template key suffix + */ + protected static final String VERIFY_TEMPLATE_SUFFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + /* signature verification is not supported by mocca + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moc.verify.request.detached"; + */ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moc.verify.template.detached"; + + /** + * The configuration key of the verify URL. + */ + /* signature verification is not supported by mocca + protected static final String xxxVERIFY_URL_KEY = "moc.verify.url"; + */ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; + + protected String profile = null; + + protected String loc_ref_content = null; + + protected String sign_keybox_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + /* signature verification is not supported by mocca + protected String verify_request_template = null; + */ + + protected String verify_template = null; + + /* signature verification is not supported by mocca + protected String verify_url = null; + */ + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + protected String algorithmId = null; + + /** + * Initializes the environment with a given profile. + * @param profile The configuration profile. + * @param algorithmId The algorithm identifer. + * @throws ConnectorException Thrown in case of an error. + */ + public Environment(String profile, String loc_ref_content, String algorithmId) throws ConnectorException { + this.profile = profile; + + this.loc_ref_content = loc_ref_content; + + SettingsReader settings = null; + try { + settings = SettingsReader.getInstance(); + } catch (SettingsException e) { + throw new ConnectorException(300, e); + } + + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); + + if (algorithmId == null) { + this.algorithmId = settings.getValueFromKey("default.moc.algorithm.id"); + } else { + this.algorithmId = algorithmId; + } + + // SIGN REQUEST + + // try specific file + String sign_request_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + SIGN_TEMPLATE_FILE_SUFFIX; + log.debug("Trying to load specific sign request file " + sign_request_filename); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + // try default request file + if (this.sign_request_template == null) { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + log.debug("Specific file not found. Trying default sign request file " + sign_request_filename); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + } + + // request file is needed !!! + if (this.sign_request_template == null) { + throw new ConnectorException(300, "Can not read the create xml request template"); + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + + // VERIFY REQUEST + /* signature verification is not supported by mocca + + // try specific file + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moc.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + log.debug("Trying to load specific verify request file " + verify_request_filename); + this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + + // try default request file + if (this.verify_request_template == null) { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + log.debug("Specific file not found. Trying default verify request file " + verify_request_filename); + this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + } + + // request file is needed !!! + if (this.verify_request_template == null) { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); + } + + */ + + // load template file + // try specific file + String verify_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + VERIFY_TEMPLATE_SUFFIX; + log.debug("Trying to load specific signature template file " + verify_filename); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + // try default signature template file + if (this.verify_template == null) { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + log.debug("Specific signature template file not found. Trying default signature template file " + verify_filename); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + // signature template is needed !!! + if (this.verify_template == null) { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); + } + + /* signature verification is not supported by mocca + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + */ + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + /** + * Returns the profile name. + * @return The profile name. + */ + public String getProfile() { + return this.profile; + } + + /** + * Returns the LocRef content. + * + * @return Returns the LocRef content. + */ + public String getLocRefContent() { + return this.loc_ref_content; + } + + /** + * Returns the sign keybox identifier. + * + * @return Returns the sign keybox identifier. + */ + public String getSignKeyboxIdentifier() { + return this.sign_keybox_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + /* signature verification is not supported by mocca + public String getVerifyRequestTemplate() { + return this.verify_request_template; + } + */ + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + /* signature verification is not supported by mocca + public String getVerifyURL() { + return this.verify_url; + } + */ + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, String profile, String key) { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-2$ + if (value == null) { + value = settings.getValueFromKey(key); + } + return value; + } + } + + /** + * Parses the common part for all id attributes from a given signature parameter string. + * @param sigIdString The given signature parameter string. + * @return The common part of all id attributes. + */ + protected String parseSigId(String sigIdString) { + String[] parts = sigIdString.split("@"); + String result = null; + if (parts != null && parts.length > 1) { + result = parts[1].trim(); + } + return result; + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = prepareXMLContent(data, so); + return new XMLDsigData(xmldsig, true); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java new file mode 100644 index 0000000..6b90fa1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java @@ -0,0 +1,223 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.connectors.mocca; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector.Environment; +import at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Provides useful methods for the usage of the open source cce mocca. + * + * @author tknall + */ +public final class MOCCAHelper { + + /** + * Prevents this plain util class from being instantiated. + */ + private MOCCAHelper() { + } + + /** + * The logging implementation. + */ + private final static Log log = LogFactory.getLog(MOCCAHelper.class); + + /** + * This method parses the signature creation response of the signature + * device mocca. + * + * @param xmlResponse The response string. + * @return Returns the parsed signature object holding the data. + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + public final static SignSignatureObject parseCreateXMLResponse(String xmlResponse, IdFormatter id_formatter, ConnectorEnvironment environment) throws ConnectorException { + + if (log.isDebugEnabled()) { + log.debug("xmlResponse = " + xmlResponse); + } + + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName[^>]*>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber[^>]*>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + // SignatureValue + String sig_val = null; + Pattern signatureValuePattern = Pattern.compile("<(\\w+:)?SignatureValue( Id=\"[\\w-]+\")?>\\s*(.*)\\s*", Pattern.DOTALL); + Matcher signatureValueMatcher = signatureValuePattern.matcher(xmlResponse); + if (signatureValueMatcher.find()) { + sig_val = signatureValueMatcher.group(3); + if (sig_val != null) { + sig_val = sig_val.replaceAll("\\s", ""); + } + } + log.debug("sig_val = " + sig_val); + + // X509IssuerName + String iss_nam = null; + if (iss_nam_m_s.find() && iss_nam_m_e.find()) { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + } + log.debug("iss_nam = " + iss_nam); + + // X509SerialNumber + String ser_num = null; + if (ser_num_m_s.find() && ser_num_m_e.find()) { + ser_num = BKUHelper.removeAllWhitespace(xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start())); + } + log.debug("ser_num = " + ser_num); + + // SigningTime + String sig_tim = null; + if (sig_tim_m_s.find() && sig_tim_m_e.find()) { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + } + log.debug("sig_tim = " + sig_tim); + + // X509Certificate + X509Certificate cert = null; + if (sig_cer_m_s.find() && sig_cer_m_e.find()) { + String sig_cer = BKUHelper.removeAllWhitespace(xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start())); + + try { + byte[] der = CodingHelper.decodeBase64(sig_cer); + ByteArrayInputStream bais = new ByteArrayInputStream(der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + } catch (UnsupportedEncodingException e) { + throw new ConnectorException(300, e); + } catch (CertificateException e) { + throw new ConnectorException(300, e); + } catch (IOException e) { + throw new ConnectorException(300, e); + } + } + log.debug("X509Certificate = " + cert); + + if (log.isDebugEnabled()) { + + String cert_iss = cert.getIssuerDN().getName(); + log.debug("certificate's issuer = " + cert_iss); + log.debug("response's issuer = " + iss_nam); + log.debug("issuer matches = " + cert_iss.equals(iss_nam)); + log.debug("ser number matches = " + cert.getSerialNumber().toString().equals(ser_num)); + } + + SignSignatureObject so = new SignSignatureObject(); + + // extract Signature Id's + String[] ids = extractIds(xmlResponse); + // dferbas + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); + + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); + so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); + + String defaultCertAlg = environment.getDefaultAlgForCert(cert); + + if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { + // do not embed default alg + algs = null; + } + + String final_ids = id_formatter.formatIds(ids, algs); + + + so.date = sig_tim; + so.issuer = iss_nam; + so.signatureValue = sig_val; + so.x509Certificate = cert; + + so.id = final_ids; + + return so; + } + + /** + * Extraction of the id attributes from the xml response. + * + * @param xmlResponse The xml response. + * @return The parsed id attributes. + */ + public final static String[] extractIds(String xmlResponse) { + return new String[] { extractId(xmlResponse) }; + } + + /** + * There is only one special common part of all id attributes of this + * connector that has to be stored. This method returns that single part. + * + * @param xmlResponse The xml response. + * @return The parsed common part of all id attributes. + */ + private final static String extractId(String xmlResponse) { + final Pattern ID_PATTERN = Pattern.compile("Id\\s*=\\s*\"\\s*Signature-([\\p{XDigit}]+)-\\d+\\s*\""); + Matcher matcher = ID_PATTERN.matcher(xmlResponse); + if (matcher.find() && matcher.groupCount() > 0) { + return matcher.group(1); + } + return null; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java new file mode 100644 index 0000000..359e49b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java @@ -0,0 +1,101 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author wprinz + * + */ +public class DetachedIdFormatter implements IdFormatter +{ + /** + * The SIG_ID prefix. + * Default value: etsi-bka-1.0 + */ + public static String SIG_ID_PREFIX = "etsi-bka-1.0"; //$NON-NLS-1$ + + /** + * Key value in property file + */ + public static final String SIG_ID_PROPERTY_KEY = "default.bku.algorithm.id"; + + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedIdFormatter.class); + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + // read id from property file and use it + try { + SIG_ID_PREFIX = SettingsReader.getInstance().getValueFromKey(SIG_ID_PROPERTY_KEY); + } catch (SettingsException e) { + log.error(e.getMessage(), e); + } + + // ids algorithm: + String join = ""; //$NON-NLS-1$ + String base = null; + for (int arr_idx = 0; arr_idx < ids.length; arr_idx++) + { + String id = ids[arr_idx]; + if (log.isDebugEnabled()) + { + log.debug("Set BKU id:" + id); //$NON-NLS-1$ + } + int id_idx = id.lastIndexOf("-"); //$NON-NLS-1$ + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + if (cur_id.equalsIgnoreCase("")) //$NON-NLS-1$ + { + cur_id = "0"; //$NON-NLS-1$ + } + + join += "-" + cur_id; //$NON-NLS-1$ + } + String idstr = base + "@" + join.substring(1); //$NON-NLS-1$ + + // dferbas + StringBuffer final_ids = new StringBuffer(SIG_ID_PREFIX); + //String final_ids = SIG_ID_PREFIX + "@" + idstr; + if (algorithmParams != null && algorithmParams.length() > 0) { + final_ids.append(":").append(algorithmParams); + } + final_ids.append("@").append(idstr); + return final_ids.toString(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java new file mode 100644 index 0000000..a83540b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java @@ -0,0 +1,80 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.lang.BooleanUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author wprinz + * + */ +public class DetachedLocRefMOAIdFormatter implements IdFormatter +{ + /** + * The SIG_ID prefix. + * Default value: etsi-bka-moa-1.0 + */ + public static String SIG_ID_PREFIX = "etsi-bka-moa-1.0"; //$NON-NLS-1$ + + private static final Logger logger_ = ConfigLogger.getLogger(DetachedLocRefMOAIdFormatter.class); + + /** + * Key value in property file + */ + public static final String SIG_ID_PROPERTY_KEY = "default.moa.algorithm.id"; + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + // read id from property file and use it + + try + { + // dferbas +// if (!BooleanUtils.toBoolean(SettingsReader.getInstance().getValueFromKey("moa.id.field.visible"))) { +// return null; +// } + + + SIG_ID_PREFIX = SettingsReader.getInstance().getValueFromKey(SIG_ID_PROPERTY_KEY); + } catch (SettingsException e) + { + logger_.error(e.getMessage(), e); + } + + // dferbas + if (algorithmParams != null && algorithmParams.length() > 0) { + return SIG_ID_PREFIX + ":" + algorithmParams; + } else { + return SIG_ID_PREFIX; + } + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java new file mode 100644 index 0000000..1ba7916 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java @@ -0,0 +1,78 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author tknall + * + */ +public class DetachedMOCIdFormatter implements IdFormatter { + + /** + * Key value in property file + */ + private static final String SIG_ID_PROPERTY_KEY = "default.moc.algorithm.id"; + + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedIdFormatter.class); + + private String algorithmId; + + public DetachedMOCIdFormatter(String algorithmId) { + this.algorithmId = algorithmId; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) { + // read id from property file and use it + String prefix = null; + try { + prefix = SettingsReader.getInstance().getValueFromKey(SIG_ID_PROPERTY_KEY); + } catch (SettingsException e) { + log.error(e.getMessage(), e); + } + prefix = StringUtils.defaultIfEmpty(this.algorithmId, prefix); + + // dferbas + StringBuffer formattedIds = new StringBuffer(prefix); + if (algorithmParams != null && algorithmParams.length() > 0) { + formattedIds.append(":").append(algorithmParams); + } + formattedIds.append("@").append(ids[0]); + return formattedIds.toString(); + + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java new file mode 100644 index 0000000..ea6637a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java @@ -0,0 +1,74 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author wprinz + * + */ +public class HotfixIdFormatter implements IdFormatter +{ + /** + * The SIG_ID prefix. + */ + public static final String SIG_ID_PREFIX = "etsi-bka-1.0"; //$NON-NLS-1$ + + /** + * The log. + */ + private static Log log = LogFactory.getLog(HotfixIdFormatter.class); + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + // ids algorithm: + String join = ""; //$NON-NLS-1$ + String base = null; + for (int arr_idx = 0; arr_idx < ids.length; arr_idx++) + { + String id = ids[arr_idx]; + if (log.isDebugEnabled()) + { + log.debug("Set BKU id:" + id); //$NON-NLS-1$ + } + int id_idx = id.lastIndexOf("-"); //$NON-NLS-1$ + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + join += "-" + cur_id; //$NON-NLS-1$ + } + + String idstr = base + "@" + join.substring(1); //$NON-NLS-1$ + String final_ids = SIG_ID_PREFIX + "@" + idstr; + + return final_ids; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java new file mode 100644 index 0000000..9747055 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java @@ -0,0 +1,34 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +/** + * @author wprinz + * + */ +public interface IdFormatter +{ + public String formatIds (String [] ids, String algorithmParams); + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java new file mode 100644 index 0000000..ff0c9f3 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +/** + * @author wprinz + * + */ +public class OldMOAIdFormatter implements IdFormatter +{ + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + return null;//"etsi-bka-moa-1.0"; + } + +} + diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java new file mode 100644 index 0000000..8e79dc4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigid; + +/** + * {@link IdFormatter} implementation that uses specified algorithmid but not additional parameters.
+ * usage A-Trust bku + * @author dferbas + * + */ +public class SimpleIdFormatter implements IdFormatter { + private String algorithmId; + + public SimpleIdFormatter(String algorithmId) { + this.algorithmId = algorithmId; + } + + public String formatIds(String[] ids, String algorithmParams) { + // dferbas + if (algorithmParams != null && algorithmParams.length() > 0) { + return this.algorithmId + ":" + algorithmParams; + } else { + return this.algorithmId; + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java new file mode 100644 index 0000000..094880d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java @@ -0,0 +1,262 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.sigkz; + +import java.util.Iterator; +import java.util.Vector; +import java.util.regex.Pattern; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; + +/** + * @author wprinz + * + */ +public final class SigKZIDHelper +{ + + /** + * The Logger. + */ + protected static Log logger = LogFactory.getLog(SigKZIDHelper.class); + + public static boolean isTextual(PdfASID sig_kz) + { + if (sig_kz == null) + { + // Old signature -> must be textual. + + return true; + } + + // new signauture -> sig_kz decides + return sig_kz.getType().equals(SignatorFactory.TYPE_TEXTUAL); + } + + public static boolean isBinary(PdfASID sig_kz) + { + return ! isTextual(sig_kz); + } + + + public static boolean isMOASigned(PdfASID sig_kz, String sig_id) + { + if (sig_kz == null || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + // old signature - if sig_id is null this means MOA + + return sig_id == null; + } + + if(sig_id == null) + return true; + + // new signature - sig_id decides + String [] ids = sig_id.split("@"); + // dferbas + String prefix = (ids[0].split(":"))[0]; + + + if (prefix.equals(DetachedLocRefMOAIdFormatter.SIG_ID_PREFIX)) + { + return true; + } + return false; + } + + public static boolean isMOASigned(SignSignatureObject so) + { + String sig_kz = so.kz; + String sig_id = so.id; + PdfASID kz = null; + if (sig_kz != null) + { + try + { + kz = new PdfASID(sig_kz); + } + catch (InvalidIDException e) + { + logger.error(e.getMessage(), e); + } + } + + return isMOASigned(kz, sig_id); + } + + /** + * @author tknall + */ + public static boolean isMOCCASigned(SignSignatureObject so) { + String sig_id = so.id; + if (StringUtils.isEmpty(sig_id)) { + return false; + } + String[] ids = sig_id.split("@"); + if (ArrayUtils.isEmpty(ids)) { + return false; + } + String algorithmId = parseAlgorithmId(sig_id); + if (algorithmId == null) { + return false; + } else { + return algorithmId.startsWith("etsi-moc-1.0") || algorithmId.startsWith("etsi-moc-1.1"); + } + } + + /** + * @author tknall + */ + public static String parseAlgorithmId(String algorithmParameter) { + if (StringUtils.isEmpty(algorithmParameter)) { + return null; + } + // dferbas + String[] ids = algorithmParameter.split("@")[0].split(":"); + if (ArrayUtils.isEmpty(ids)) { + return null; + } + return ids[0]; + } + + public static boolean isOldBKU(PdfASID sig_kz, String sig_id) throws ConnectorException + { + if (sig_kz == null) + { + return true; + } + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + if (sig_id == null) + { + throw new ConnectorException(310, "The SIG_ID is null - so this isn't a BKU at all."); + } + + String[] sig_id_parts = sig_id.split("@"); + if (sig_id_parts.length == 2) + { + return true; + } + // dferbas + if (sig_id_parts[0].startsWith(HotfixIdFormatter.SIG_ID_PREFIX)) + { + + return false; + } + + throw new ConnectorException(310, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); + } + + return false; + } + + public static boolean isOldBKU(SignSignatureObject so) throws ConnectorException + { + String sig_kz = so.kz; + String sig_id = so.id; + PdfASID kz = null; + if (sig_kz != null) + { + try + { + kz = new PdfASID(sig_kz); + } + catch (InvalidIDException e) + { + logger.error(e.getMessage(), e); + } + } + + return isOldBKU(kz, sig_id); + } + + public static String getAlgorithmId(String bkuIdentifier) throws SettingsException, SettingNotFoundException, ConnectorException { + SettingsReader sr = SettingsReader.getInstance(); + + String base = "signaturelayout.pattern"; + Vector v = sr.getSettingKeys(base); + + Iterator it = v.iterator(); + while (it.hasNext()) { + String subKey = (String) it.next(); + String key = base + "." + subKey; + String value = sr.getSetting(key); + Pattern p = Pattern.compile(value); + if (p.matcher(bkuIdentifier).matches()) { + String algKey = "signaturelayout.algorithm.id." + subKey; + String algValue = sr.getSetting(algKey); + return algValue; + } + } + + if ("true".equalsIgnoreCase(sr.getSetting("signaturelayout.strict", "false"))) { + logger.debug("Enforcing bku support check."); + throw new ConnectorException(ErrorCode.BKU_NOT_SUPPORTED, "Unsupported BKU: " + bkuIdentifier); + } else { + logger.debug("bku support check disabled."); + return null; + } + + } + + public static boolean isATrustSigned(SignSignatureObject so) { + String sig_id = so.id; + if (sig_id == null && StringUtils.isEmpty(sig_id)) { + return false; + } + return sig_id.startsWith("etsi-bka-atrust-1.0"); + } + + /** + * Checks if signed with a known BKU method/param + * @param so + * @return + */ + public static boolean isBKUSigned(SignSignatureObject so) throws ConnectorException { + if (isOldBKU(so)) return true; + + if (so.id.startsWith("etsi-bka-1.0")) { + return true; + } + + return false; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java new file mode 100644 index 0000000..b58b2e4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java @@ -0,0 +1,45 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * Considers different signature layout characteristics among different versions of citizen card + * environments. + * @author tknall + */ +public interface SignatureLayoutHandler { + + /** + * This method parses the CreateXMLSignatureResponse given from a certain signature device. + * + * @param xmlResponse The response string. + * @return Returns the parsed signature object. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java new file mode 100644 index 0000000..07a7792 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java @@ -0,0 +1,147 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * Returns instances of signature layout handlers based on given bku + * identifiers. + * + * @author tknall + */ +public class SignatureLayoutHandlerFactory { + + /** + * Prefix of configuration keys defining bku identifiers for a signature layout. + */ + private final static String SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN = "signaturelayout.pattern"; + + /** + * Prefix of configuration keys defining implementations of signature layout handlers. + * @see SignatureLayoutHandler + */ + private final static String SIGNATURE_LAYOUT_CONFIG_KEY_IMPL = "signaturelayout.implementation"; + + /** + * A map holding instantiated signature layout implementations (for performance reasons). + */ + private final static Map instances = Collections.synchronizedMap(new HashMap()); + + /** + * The log. + */ + private static Log log = LogFactory.getLog(SignatureLayoutHandlerFactory.class); + + /** + * Returns an instance of a signature layout handler based on the given bku identifier. + * @param bkuIdentifier The bku identifier (e.g. citizen-card-environment/1.2 MOCCA/1.1.1). + * @return An implementation of a signature layout handler. + * @throws ConnectorException Thrown in case of an error finding a match within the configuration with the given bku identifier. + * @throws SettingsException Thrown in case of an error within the configuration. + */ + public static SignatureLayoutHandler getSignatureLayoutHandlerInstance(String bkuIdentifier) throws ConnectorException, SettingsException { + if (bkuIdentifier == null) { + throw new SettingsException(ErrorCode.MISSING_HEADER_SERVER_USER_AGENT, "Unable to determine type of citizen card environment. Response header \"Server\" resp. \"user-agent\" is missing. Refer to security layer specification 1.2.2, section 3.3.2."); + } + SignatureLayoutHandler signatureLayoutHandler = (SignatureLayoutHandler) instances.get(bkuIdentifier); + + if (signatureLayoutHandler == null) { + SettingsReader sr = SettingsReader.getInstance(); + + Vector v = sr.getSettingKeys(SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN); + String implValue = null; + + Iterator it = v.iterator(); + try { + while (it.hasNext()) { + String subKey = (String) it.next(); + String key = SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN + "." + subKey; + String value = sr.getSetting(key); + Pattern p = Pattern.compile(value); + if (p.matcher(bkuIdentifier).matches()) { + String implKey = SIGNATURE_LAYOUT_CONFIG_KEY_IMPL + "." + subKey; + implValue = sr.getSetting(implKey); + } + } + } catch (SettingNotFoundException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, e.getMessage()); + } + + if (implValue == null) { + throw new ConnectorException(ErrorCode.BKU_NOT_SUPPORTED, "Unsupported BKU: " + bkuIdentifier); + } + + log.debug("Trying to instantiate SignatureLayoutHandler \"" + implValue + "\"."); + + try { + Class clazz = Class.forName(implValue); + Object obj = clazz.newInstance(); + if (!(obj instanceof SignatureLayoutHandler)) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Invalid signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } + signatureLayoutHandler = (SignatureLayoutHandler) obj; + } catch (InstantiationException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Error instantiating signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } catch (IllegalAccessException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Illegal access instantiating signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } catch (ClassNotFoundException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Unable to find signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } + + log.debug("SignatureLayoutHandler successfully instantiated."); + instances.put(bkuIdentifier, signatureLayoutHandler); + } else { + log.trace("SignatureLayoutHandler has already been instantiated. Returning old instance."); + } + + return signatureLayoutHandler; + + } + + /** + * Verifies that the bku is supported trying to match the given bku identifier. + * @param bkuIdentifier The bku identifier (e.g. citizen-card-environment/1.2 MOCCA/1.1.1). + * @throws ConnectorException Thrown in case of an error (e.g. bku not supported). + * @throws SettingsException Thrown in case of an error within the configuration. + */ + public static void verifyBKUSupport(String bkuIdentifier) throws ConnectorException, SettingsException { + getSignatureLayoutHandlerInstance(bkuIdentifier); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java new file mode 100644 index 0000000..b7cf72b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java @@ -0,0 +1,47 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout.atrust; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.SimpleIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Layout handler for atrust bku + * + * @author dferbas + */ +public class ATrustSignatureLayoutHandler implements SignatureLayoutHandler { + + public static final String ETSI_BKA_ATRUST_1_0 = "etsi-bka-atrust-1.0"; + + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, + ConnectorEnvironment env) throws ConnectorException { + return MOAHelper.parseCreateXMLResponse(xmlResponse, new SimpleIdFormatter(ETSI_BKA_ATRUST_1_0), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java new file mode 100644 index 0000000..600b503 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout.mocca; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.MOCCAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Implementation of a signature layout handler for the first release of mocca. + * @author tknall + */ +public class MOCCASignatureLayout10Handler implements SignatureLayoutHandler { + + private final static String ALGORITHM_ID = "etsi-moc-1.1"; + + /** + * Parses the given xmlResponse with respect to the specific signature layout of mocca. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException { + return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java new file mode 100644 index 0000000..988a930 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout.mocca; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.MOCCAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Implementation of a signature layout handler for the beta version of mocca. + * @author tknall + */ +public class OldMOCCASignatureLayoutHandler implements SignatureLayoutHandler { + + private final static String ALGORITHM_ID = "etsi-moc-1.0"; + + /** + * Parses the given xmlResponse with respect to the specific signature layout of mocca. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException { + return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java new file mode 100644 index 0000000..a13ce52 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java @@ -0,0 +1,46 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signaturelayout.td; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Implementation of a signature layout handler for trustDesk basic. + * @author tknall + */ +public class TrustDeskSignatureLayoutHandler implements SignatureLayoutHandler { + + /** + * Parses the given xmlResponse with respect to the specific signature layout of trustDesk basic. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException { + return BKUHelper.parseCreateXMLResponse(xmlResponse, new DetachedIdFormatter(), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java new file mode 100644 index 0000000..7c86e62 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signatureobject; + +import java.security.cert.X509Certificate; + +/** + * @author wprinz + * + */ +public interface AdditionalSignatureInformation +{ + + public String getName(); + + public X509Certificate getX509Certificate(); + + // dferbas: baik + public String getSigAlgorithm(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java new file mode 100644 index 0000000..7d81758 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java @@ -0,0 +1,33 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signatureobject; + +/** + * @author wprinz + * + */ +public interface AlgorithmSignatureInformation +{ +public String getSigKZ(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java new file mode 100644 index 0000000..6b5ef18 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java @@ -0,0 +1,34 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signatureobject; + +/** + * + * @author wprinz + * + */ +public interface ConnectorSignatureInformation +{ + public String getSigID(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java new file mode 100644 index 0000000..2da1b02 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java @@ -0,0 +1,40 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signatureobject; + +/** + * Encapsulates all information required to define a signature. + * + * @author wprinz + */ +public interface MandatorySignatureInformation +{ + public String getDate(); + + public String getSignatureValue(); + + public String getIssuer(); + + public String getSerialNumber(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java new file mode 100644 index 0000000..6a8afc0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java @@ -0,0 +1,81 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.sig.signatureobject; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * Contains helper methods for dealing with signature objects. + * + * @author wprinz + * + */ +public final class SignatureObjectHelper +{ + + public static SignatureObject convertSignSignatureObjectToSignatureObject (SignSignatureObject sso, String signature_type) throws SignatureTypesException, SignatureException + { + SignatureObject so = new SignatureObject(); + so.setSigType(signature_type); + so.initByType(); + so.setSignationDate(sso.getDate()); + so.setSignationIssuer(sso.getIssuer()); + so.setSignationSerialNumber(sso.getSerialNumber()); + so.setSignationValue(sso.getSignatureValue()); + so.setSignationIDs(sso.getSigID()); + so.setKZ(new PdfASID(sso.getSigKZ())); + so.setSignationName(sso.getName()); + + so.setSigAlg(sso.getSigAlgorithm()); + + so.setX509Certificate(sso.getX509Certificate()); + + return so; + } + + public static SignSignatureObject convertSignatureObjectToSignSignatureObject (SignatureObject so) throws SignatureException + { + SignSignatureObject sso = new SignSignatureObject(); + sso.date = so.getSignationDate(); + sso.signatureValue = so.getSignationValue(); + sso.issuer = so.getSignationIssuer(); + X509Cert cert = so.getX509Cert(); + if (cert == null) + { + throw new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "so.getX509Cert returned null. No cert found."); + } + sso.x509Certificate = cert.getX509Certificate(); + sso.id = so.getSignationIds(); + sso.kz = so.getKZ() == null ? null : so.getKZ().toString(); + sso.sigAlgorithm = so.getSigAlg(); + + return sso; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java new file mode 100644 index 0000000..289a7f6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Entry.java @@ -0,0 +1,235 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Entry.java,v 1.3 2006/08/25 17:08:19 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.table; + +import java.io.Serializable; + +/** + * This class implements a table entry for different types. A table entry can be + * styled and setting there column dimensions. The default value for the column + * dimension is 1. To declare the type of the entry use the public + * TYPE_ definitions. + * + * @author wlackner + */ +public class Entry implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -7952755200668528348L; + + /** + * Type for a text entry. + */ + public final static int TYPE_CAPTION = 0; + + /** + * Type for a text entry. + */ + public final static int TYPE_VALUE = 1; + + /** + * Type for an image entry. + */ + public final static int TYPE_IMAGE = 2; + + /** + * Type for a table entry. + */ + public final static int TYPE_TABLE = 3; + + /** + * The type info holder, default value is 0! + */ + private int type_ = 0; + + /** + * The entry value. + */ + private Object value_ = null; + + /** + * The key value + */ + private String key_ = null; + + /** + * The entry style information. + */ + private Style style_ = null; + + /** + * The column dimension. + */ + private int colSpan_ = 1; + + /** + * Text wrap indicator, default is false. + */ + private boolean noWrap_ = false; + + /** + * The empty constructor. + */ + public Entry() + { + } + + /** + * A constructor setting the type and the value. + * + * @param type + * the entry type to set + * @param value + * the entry value to set + */ + public Entry(int type, Object value, String key) + { + type_ = type; + value_ = value; + key_ = key; + } + + /** + * @return Returns the entry style. + */ + public Style getStyle() + { + return style_; + } + + /** + * @param style + * The style to set. + */ + public void setStyle(Style style) + { + style_ = style; + } + + /** + * @return Returns the entry type. + */ + public int getType() + { + return type_; + } + + /** + * @param type + * The type to set. + */ + public void setType(int type) + { + type_ = type; + } + + /** + * @return Returns the entry value. + */ + public Object getValue() + { + return value_; + } + + /** + * @param value + * The value to set. + */ + public void setValue(Object value) + { + value_ = value; + } + + /** + * @return Returns the key. + */ + + public String getKey() + { + return key_; + } + + /** + * @param key + * The key to set. + */ + public void setKey(String key) + { + key_ = key; + } + + /** + * @return Returns the colSpan. + */ + public int getColSpan() + { + return colSpan_; + } + + /** + * @param colSpan + * The colSpan to set. + */ + public void setColSpan(int colSpan) + { + colSpan_ = colSpan; + } + + /** + * @return Returns the wrap indicator. + */ + public boolean isNoWrap() + { + return noWrap_; + } + + /** + * @param noWrap + * The wrap indicator to set. + */ + public void setNoWrap(boolean noWrap) + { + noWrap_ = noWrap; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() + { + Object obj = getValue(); + String value = null; + if (obj != null) + { + value = obj.toString(); + } + return "Type:" + getType() + " Value:" + value + " ColSpan:" + getColSpan(); + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java new file mode 100644 index 0000000..10686b6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Style.java @@ -0,0 +1,630 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Style.java,v 1.3 2006/08/25 17:08:19 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.table; + +import java.awt.Color; +import java.io.Serializable; + +/** + * This class implements an abstract style definiton used in tables or table entrys. Predefined + * values exists for valign and halign. Color definitions uses the native awt color declarations. + *
+ * The predefined keys are used in the setting definition file to style tables and table entries. + *
+ * It provides an static method to inherit style informations from a given style object. + * {@link at.knowcenter.wag.egov.egiz.table.Style#doInherit} + * + * + * @author wlackner + * @see java.awt.Color + */ +public class Style implements Serializable { + +// 03.11.2010 changed by exthex - added valuevalign and valuehalign to allow separate layout for value and non-value cells. +// Also the hardcoded default values for halign and valign were removed to allow proper inheritment. +// 04.11.2010 changed by exthex - added imagevalign and imagehalign analog to valuevalign/valuehalign + + /** + * SVUID. + */ + private static final long serialVersionUID = 5855722896712428387L; + + /** + * valign statement key top + */ + public final static String TOP = "top"; + /** + * valign statement key middle + */ + public final static String MIDDLE = "middle"; + /** + * valign statement key bottom + */ + public final static String BOTTOM = "bottom"; + /** + * halign statement key left + */ + public final static String LEFT = "left"; + /** + * halign statement key center + */ + public final static String CENTER = "center"; + /** + * halign statement key right + */ + public final static String RIGHT = "right"; + + /** + * bgcolor key + */ + public final static String BGCOLOR = "bgcolor"; + /** + * halign key + */ + public final static String HALIGN = "halign"; + /** + * valign key + */ + public final static String VALIGN = "valign"; + + /** + * value halign key + */ + public final static String VALUEHALIGN = "valuehalign"; + /** + * value valign key + */ + public final static String VALUEVALIGN = "valuevalign"; + + /** + * image halign key + */ + public final static String IMAGEHALIGN = "imagehalign"; + /** + * image valign key + */ + public final static String IMAGEVALIGN = "imagevalign"; + /** + * padding key, default padding = 1 + */ + public final static String PADDING = "padding"; + /** + * border key, default border = 1;
+ * The border value is one value for all border lines of an entry or table!
+ * No separte definitions for top, right, bottom or left are possible. + */ + public final static String BORDER = "border"; + + /** + * Font key + */ + public final static String FONT = "font"; + + /** + * The value font key. + */ + public final static String VALUEFONT = "valuefont"; + + /** + * The imageScaleToFit key. + */ + public final static String IMAGE_SCALE_TO_FIT = "imagescaletofit"; + + /** + * Font name HELVETICA + */ + public final static String HELVETICA = "HELVETICA"; + /** + * Font name TIMES_ROMAN + */ + public final static String TIMES_ROMAN = "TIMES_ROMAN"; + /** + * Font name COURIER + */ + public final static String COURIER = "COURIER"; + /** + * Font type NORMAL + */ + public final static String NORMAL = "NORMAL"; + /** + * Font type BOLD + */ + public final static String BOLD = "BOLD"; + /** + * Font type ITALIC + */ + public final static String ITALIC = "ITALIC"; + /** + * Font type BOLDITALIC + */ + public final static String BOLDITALIC = "BOLDITALIC"; + /** + * Font type UNDERLINE + */ + public final static String UNDERLINE = "UNDERLINE"; + /** + * Font type STRIKETHRU + */ + public final static String STRIKETHRU = "STRIKETHRU"; + + + /** + * all paddings initialized with the default padding value (1) + */ + private static final float DEFAULT_PADDING = 1; + /** + * all borders initialized with the default border value (1) + */ + private static final float DEFAULT_BORDER = 1; + /** + * The background color definition. + */ + private Color bgColor_ = null; + /** + * The current padding value -> initialized with the default padding value + */ + private float padding_ = DEFAULT_PADDING; + /** + * The current halign value + */ + private String hAlign_ = null; + /** + * The current valign value + */ + private String vAlign_ = null; + /** + * The current valuehalign value + */ + private String valueHAlign_ = null; + /** + * The current valuevalign value + */ + private String valueVAlign_ = null; + /** + * The current imagehalign value + */ + private String imageHAlign_ = null; + /** + * The current imagevalign value + */ + private String imageVAlign_ = null; + /** + * The current border value -> initialized with the default border value + */ + private float border_ = DEFAULT_BORDER; + /** + * The font string of the style definition + */ + private String font_ = null; + /** + * The font string of the value font. + */ + private String valuefont_ = null; + /** + * The scaleToFit dimensions to be applied for image-cells. + */ + private ImageScaleToFit imageScaleToFit_ = null; + + /** + * The empty constructor. + */ + public Style() { + } + + /** + * Set a style attribute. The style attribute must be one of the public definitions + * + * @param id the style attribute to set + * @param value the style value to set for the given attribute + */ + public void setStyle(String id, String value) { + if (BGCOLOR.equals(id)) { + String[] col_strg = value.split(" "); + if (col_strg.length == 3) { + int r = Integer.parseInt(col_strg[0]); + int g = Integer.parseInt(col_strg[1]); + int b = Integer.parseInt(col_strg[2]); + if (r < 256 && g < 256 && b < 256 && r >= 0 && g >= 0 && b >= 0) { + bgColor_ = new Color(r, g, b); + } + } + } + if (HALIGN.equals(id)) { + if (LEFT.equals(value) || CENTER.equals(value) || RIGHT.equals(value)) { + hAlign_ = value; + } + } + if (VALIGN.equals(id)) { + if (TOP.equals(value) || MIDDLE.equals(value) || BOTTOM.equals(value)) { + vAlign_ = value; + } + } + if (VALUEHALIGN.equals(id)) { + if (LEFT.equals(value) || CENTER.equals(value) || RIGHT.equals(value)) { + valueHAlign_ = value; + } + } + if (VALUEVALIGN.equals(id)) { + if (TOP.equals(value) || MIDDLE.equals(value) || BOTTOM.equals(value)) { + valueVAlign_ = value; + } + } + if (IMAGEHALIGN.equals(id)) { + if (LEFT.equals(value) || CENTER.equals(value) || RIGHT.equals(value)) { + imageHAlign_ = value; + } + } + if (IMAGEVALIGN.equals(id)) { + if (TOP.equals(value) || MIDDLE.equals(value) || BOTTOM.equals(value)) { + imageVAlign_ = value; + } + } + if (PADDING.equals(id)) { + padding_ = Float.parseFloat(value); + } + if (BORDER.equals(id)) { + border_ = Float.parseFloat(value); + } + if (FONT.equals(id)) { + font_ = value; + } + if (VALUEFONT.equals(id)) { + valuefont_ = value; + } + if (IMAGE_SCALE_TO_FIT.equals(id)) + { + imageScaleToFit_ = parseImageScaleToFit(value); + } + } + + /** + * @return Returns the bgColor. + */ + public Color getBgColor() { + return bgColor_; + } + + /** + * @param bgColor The bgColor to set. + */ + public void setBgColor(Color bgColor) { + bgColor_ = bgColor; + } + + /** + * @return Returns the hAlign. + */ + public String getHAlign() { + return hAlign_; + } + + /** + * @param align The hAlign to set. + */ + public void setHAlign(String align) { + hAlign_ = align; + } + + /** + * @return Returns the padding. + */ + public float getPadding() { + return padding_; + } + + /** + * @param padding The padding to set. + */ + public void setPadding(float padding) { + padding_ = padding; + } + + /** + * @return Returns the vAlign. + */ + public String getVAlign() { + return vAlign_; + } + + /** + * @param align The vAlign to set. + */ + public void setVAlign(String align) { + vAlign_ = align; + } + + /** + * @return Returns the border. + */ + public float getBorder() { + return border_; + } + + /** + * @param border The border to set. + */ + public void setBorder(float border) { + border_ = border; + } + + + /** + * @return Returns the font. + */ + public String getFont() { + return font_; + } + + /** + * @param font The font to set. + */ + public void setFont(String font) { + font_ = font; + } + + + /** + * Returns the value font. + * @return Returns the value font. + */ + public String getValueFont() + { + return valuefont_; + } + + /** + * Sets the value font. + * @param valuefont The value font to be set. + */ + public void setValueFont(String valuefont) + { + this.valuefont_ = valuefont; + } + + /** + * @param align The valueHAlign to set. + */ + public void setValueHAlign(String align) { + valueHAlign_ = align; + } + + /** + * Returns the value halign + * @return Returns the value halign + */ + public String getValueHAlign() { + return valueHAlign_; + } + + /** + * @param align The valueVAlign to set. + */ + public void setValueVAlign(String align) { + valueVAlign_ = align; + } + + /** + * Returns the value valign + * @return Returns the value valign + */ + public String getValueVAlign() { + return valueVAlign_; + } + + /** + * @param align The imageHAlign to set. + */ + public void setImageHAlign(String align) { + imageHAlign_ = align; + } + + /** + * Returns the image halign + * @return Returns the image halign + */ + public String getImageHAlign() { + return imageHAlign_; + } + + /** + * @param align The imageVAlign to set. + */ + public void setImageVAlign(String align) { + imageVAlign_ = align; + } + + /** + * Returns the image valign + * @return Returns the image valign + */ + public String getImageVAlign() { + return imageVAlign_; + } + + /** + * Returns the scaleToFit dimensions to be applied for image-cells. + * @return Returns the scaleToFit dimensions to be applied for image-cells. + */ + public ImageScaleToFit getImageScaleToFit() + { + return this.imageScaleToFit_; + } + + /** + * Sets the scaleToFit dimensions to be applied for image-cells. + * @param imageScaleToFit_ The scaleToFit dimensions to be applied for image-cells. + */ + public void setImageScaleToFit(ImageScaleToFit imageScaleToFit) + { + this.imageScaleToFit_ = imageScaleToFit; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + return "bgcolor:" + getBgColor() + " halign:" + getHAlign() + " valign:" + getVAlign() + " padding:" + getPadding() + " border:" + getBorder() + " font:" + getFont() + " valuefont:" + getValueFont() + " imageScaleToFit:" + getImageScaleToFit(); + } + + /** + * This method inherits all style attributes (values) from a given style object. + * + *

+ * A new style object is created that receives the properly inherited styles. + *

+ *

+ * If a value is not defined in the baseStyle object it would be inhert from the inheritStyle object. + *

+ * + * @param baseStyle the style object that serves as a primary style source. + * @param inheritStyle the style object that serves as a secondary style source in case a style attribute is not defined on the primary style source. + * @param isValue + * @return Returns a new Style object being fully equipped with styles. + */ + public static Style doInherit(Style baseStyle, Style inheritStyle) { + Style newStyle = new Style(); + + if (baseStyle != null) + { + newStyle.setBgColor(baseStyle.getBgColor()); + newStyle.setBorder(baseStyle.getBorder()); + newStyle.setFont(baseStyle.getFont()); + newStyle.setHAlign(baseStyle.getHAlign()); + newStyle.setImageHAlign(baseStyle.getImageHAlign()); + newStyle.setImageVAlign(baseStyle.getImageVAlign()); + newStyle.setPadding(baseStyle.getPadding()); + newStyle.setVAlign(baseStyle.getVAlign()); + newStyle.setValueFont(baseStyle.getValueFont()); + newStyle.setValueHAlign(baseStyle.getValueHAlign()); + newStyle.setValueVAlign(baseStyle.getValueVAlign()); + newStyle.setImageScaleToFit(baseStyle.getImageScaleToFit()); + } + + if (inheritStyle != null) + { + if (newStyle.getBgColor() == null) { newStyle.setBgColor(inheritStyle.getBgColor()); } + if (newStyle.getBorder() == DEFAULT_BORDER) { newStyle.setBorder(inheritStyle.getBorder()); } + if (newStyle.getFont() == null) { newStyle.setFont(inheritStyle.getFont()); } + if (newStyle.getHAlign() == null) { newStyle.setHAlign(inheritStyle.getHAlign()); } + if (newStyle.getImageHAlign() == null) { newStyle.setImageHAlign(inheritStyle.getImageHAlign()); } + if (newStyle.getImageVAlign() == null) { newStyle.setImageVAlign(inheritStyle.getImageVAlign()); } + if (newStyle.getPadding() == DEFAULT_PADDING) { newStyle.setPadding(inheritStyle.getPadding()); } + if (newStyle.getVAlign() == null) { newStyle.setVAlign(inheritStyle.getVAlign()); } + if (newStyle.getValueFont() == null) { newStyle.setValueFont(inheritStyle.getValueFont()); } + if (newStyle.getValueHAlign() == null) { newStyle.setValueHAlign(inheritStyle.getValueHAlign()); } + if (newStyle.getValueVAlign() == null) { newStyle.setValueVAlign(inheritStyle.getValueVAlign()); } + if (newStyle.getImageScaleToFit() == null) { newStyle.setImageScaleToFit(inheritStyle.getImageScaleToFit()); } + } + + return newStyle; + } + + protected static ImageScaleToFit parseImageScaleToFit (String imageScaleToFit) + { + if (imageScaleToFit == null || imageScaleToFit.length() == 0 || imageScaleToFit.trim().length() == 0) + { + return null; + } + + String [] dimensions = imageScaleToFit.split(";"); + if (dimensions.length != 2) + { + return null; + } + + float width = Float.parseFloat(dimensions[0]); + float height = Float.parseFloat(dimensions[0]); + + return new ImageScaleToFit(width, height); + } + + /** + * Holds the width and the height an image can be scaled to fit. + * + * @author wprinz + */ + public static class ImageScaleToFit + { + /** + * The width. + */ + protected float width; + + /** + * The height. + */ + protected float height; + + /** + * Constructor. + * + * @param width The width. + * @param height The height. + */ + public ImageScaleToFit(float width, float height) + { + this.width = width; + this.height = height; + } + + /** + * Returns the width. + * @return Returns the width. + */ + public float getWidth() + { + return this.width; + } + + /** + * Sets the width. + * @param width The width to set. + */ + public void setWidth(float width) + { + this.width = width; + } + + /** + * Returns the height. + * @return Returns the height. + */ + public float getHeight() + { + return this.height; + } + + /** + * Sets the height. + * @param height The height to set. + */ + public void setHeight(float height) + { + this.height = height; + } + + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java new file mode 100644 index 0000000..29d1c9c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java @@ -0,0 +1,223 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Table.java,v 1.2 2006/08/25 17:08:19 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.table; + +import java.io.Serializable; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; + +/** + * This class implements an abstract table definition. The table contains table + * rows and the table rows contains the table entries. A table can be styled and + * a relative column width can be set. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ +public class Table implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 8488947943674086618L; + + /** + * The table column settings. + */ + private float[] colsRelativeWith_ = null; + + /** + * The row definitions. + */ + private Map rows_ = new HashMap(); + + /** + * The table width. + */ + private float width_ = 100; + + /** + * The table style. + */ + private Style style_ = null; + + /** + * Number of columns that are defined for the current table. + */ + private int maxCols_ = 0; + + /** + * A table name. + */ + private String name_ = null; + + /** + * The table constructor init by a table name. + * + * @param name + * the name for the table. + */ + public Table(String name) + { + name_ = name; + } + + /** + * The width of the columns are relative to each other. This means the values + * are summarized and divided into portions of columns used.
+ * Example: [1,4] means the second column is four times wider + * than the first column. + * + * @return Returns the relative width of the columns + */ + public float[] getColsRelativeWith() + { + return colsRelativeWith_; + } + + /** + * The width of the columns are relative to each other. This means the values + * are summarized and divided into portions of columns used.
+ * Example: [10,90] means the first colum consumes 10% and the + * second column consumes 90% of the table width.
+ * The relative width of the columns to set. + */ + public void setColsRelativeWith(float[] cols) + { + colsRelativeWith_ = cols; + } + + /** + * @return Returns the style. + */ + public Style getStyle() + { + return style_; + } + + /** + * @param style + * The style to set. + */ + public void setStyle(Style style) + { + style_ = style; + } + + /** + * @return Returns the width. + */ + public float getWidth() + { + return width_; + } + + /** + * @param width + * The width to set. + */ + public void setWidth(float width) + { + width_ = width; + } + + /** + * @return Returns the maxCols. + */ + public int getMaxCols() + { + return maxCols_; + } + + /** + * @return Returns the name. + */ + public String getName() + { + return name_; + } + + /** + * This method returns a sorted row list beginning with the row number 1. The + * entrys in a row also stored in a {@link ArrayList}. + * + * @return Returns the sorted (by row number) table rows. + */ + public ArrayList getRows() + { + ArrayList rows = new ArrayList(); + for (int row_idx = 1; row_idx <= rows_.size(); row_idx++) + { + ArrayList row = (ArrayList) rows_.get("" + row_idx); + rows.add(row); + } + return rows; + } + + /** + * Add a comlete table row to the current table. Be carefull usding the + * correct row number because no check is done if a row with the given row + * number does exist! In that case the stored row would be replaced! + * + * @param rowNumber + * the row number to store the row entries + * @param row + * the entry list to store + */ + public void addRow(String rowNumber, ArrayList row) + { + rows_.put(rowNumber, row); + if (row.size() > maxCols_) + { + maxCols_ = row.size(); + } + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() + { + String the_string = "\n#### TABLE " + name_ + " BEGIN #####"; + the_string += " Width:" + width_ + " max cols:" + maxCols_ + " cols:" + colsRelativeWith_; + the_string += "\nStyle:" + style_; + ArrayList rows = getRows(); + for (int row_idx = 0; row_idx < rows.size(); row_idx++) + { + ArrayList row = (ArrayList) rows.get(row_idx); + String row_prefix = "\n ++ ROW " + row_idx + " ++ "; + for (int entry_idx = 0; entry_idx < row.size(); entry_idx++) + { + the_string += row_prefix + ((Entry) row.get(entry_idx)).toString(); + } + } + the_string += "\n#### TABLE " + name_ + " END #####"; + return the_string; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java new file mode 100644 index 0000000..5132021 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/CodingHelper.java @@ -0,0 +1,301 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: CodingHelper.java,v 1.6 2006/10/11 07:52:36 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.codec.binary.Base64; + +import at.gv.egiz.pdfas.framework.input.DataSource; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; + +/** + * This class provides encoding and decoding methods and other coding methods. + * All methods are static! + * + * @author wlackner + */ +public class CodingHelper +{ + + /** + * Static Base64 object + */ + private static Base64 b64 = new Base64(); + + /** + * This method encodes a given Unicode (Java) String to UTF-8 bytes and then + * encodes these UTF-8 bytes to a Base64 US-ASCII (Java) String. + * + * @param plain_string + * to be encoded + * @return the UTF-8 and Base64 encoded string + */ + public static String encodeUTF8AsBase64(String plain_string) + { + try + { + byte[] utf8_bytes = plain_string.getBytes("UTF-8"); + byte[] base64_bytes = b64.encode(utf8_bytes); + String encoded_string = new String(base64_bytes, "US-ASCII"); + return encoded_string; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * This method decodes the UTF-8 bytes from a Base64 US-ASCII (Java) String + * and decodes the UTF-8 bytes to a unicode (Java) String. + * + * @param encoded_string + * to be decoded + * @return the Base64 and UTF-8 decoded string + */ + public static String decodeUTF8FromBase64(String encoded_string) + { + try + { + byte[] base64_bytes = encoded_string.getBytes("US-ASCII"); + byte[] utf8_bytes = b64.decode(base64_bytes); + String plain_string = new String(utf8_bytes, "UTF-8"); + return plain_string; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + // /** + // * This method encodes a given string UTF-8 + // * + // * @param theString to be encoded + // * @return the UTF-8 encoded string + // */ + // public static byte[] encodeUTF8(String theString) { + // byte[] utf8 = null; + // try { + // utf8 = theString.getBytes("UTF-8"); + // } catch (UnsupportedEncodingException e) { + // e.printStackTrace(); + // } + // return utf8; + // } + + // /** + // * This method decodes a given UTF-8 string + // * + // * @param theString to be decoded + // * @return the decoded UTF-8 string + // */ + // public static String decodeUTF8(String theString) { + // byte[] ba = theString.getBytes(); + // String the_string = decodeUTF8(ba); + // if (the_string != null) { + // return the_string; + // } + // return theString; + // } + + // /** + // * This method decodes a given UTF-8 byte array + // * + // * @param ba the byte array to be decoded + // * @return the decoded UTF-8 string + // */ + // public static String decodeUTF8(byte[] ba) { + // String the_string = null; + // try { + // the_string = new String(ba, "UTF-8"); + // } catch (UnsupportedEncodingException e) { + // e.printStackTrace(); + // } + // return the_string; + // } + + /** + * This method decodes a given Base64 string. + * + *

+ * Note that the given String must only contain Base64 characters. (The string + * will be converted to a byte array of "US-ASCII" (7 bit) bytes and then this + * byte array will be decoded using the Base64 algorithm. + *

+ * + * @param theString + * to be decoded + * @return a Base64 decoded byte array + */ + public static byte[] decodeBase64(String theString) + { + try + { + byte[] base64_bytes = theString.getBytes("US-ASCII"); + return b64.decode(base64_bytes); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); + } + } + + /** + * This method decodes a given Base64 byte array + * + * @param ba + * the byte array to be decoded + * @return a Base64 decoded byte array + */ + public static byte[] decodeBase64(byte[] ba) + { + return b64.decode(ba); + } + + /** + * This method encodes a given byte array Base64 + * + * @param plainString + * the byte array to be encoded + * @return the Base64 encoded string + */ + public static String encodeBase64(byte[] plainString) + { + try + { + byte[] base64_bytes = b64.encode(plainString); + return new String(base64_bytes, "US-ASCII"); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); + } + } + + // dferbas + /** + * This method builds an hash value of a given byte array. + * + * @param data + * the byte array to build the hash value for + * @param hashAlg hash algorithm for {@link MessageDigest} e.g. "SHA-1" + * @return the calculated hash value as a byte array + * @see MessageDigest + */ + public static byte[] buildDigest(byte[] data, String hashAlg) + { + MessageDigest digester = null; + try + { + digester = MessageDigest.getInstance(hashAlg); + digester.update(data); + return digester.digest(); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + } + + // dferbas + /** + * This method builds an hash value of a given byte array. + * @param input + * @param hashAlg hashAlg hash algorithm for {@link MessageDigest} e.g. "SHA-1" + * @return the calculated hash value as a byte array + * @throws IOException + */ + public static byte[] buildDigest(DataSource input, String hashAlg) throws IOException + { + // PERF: digesting needs data source. + byte [] data = DataSourceHelper.convertDataSourceToByteArray(input); + return buildDigest(data, hashAlg); + } + + /** + * This method escapes a given string with HTML entities. + * + * @param rawString + * the string to escaped + * @return the HTML escaped string + */ + public static String htmlEscape(String rawString) + { + rawString = rawString.replaceAll("\\&", "&"); + rawString = rawString.replaceAll("\\<", "<"); + rawString = rawString.replaceAll("\\>", ">"); + rawString = rawString.replaceAll("\">", """); + return rawString; + } + + /** + * This method checks, if a byte array contains chars that are not base64 + * conform. + * + * @param byteArray + * the array to test + * @return boolean, if a byte array is base64 conform, false otherwise + */ + public static boolean isB64(byte[] byteArray) + { + try + { + return Base64.isArrayByteBase64(byteArray); + } + catch (ArrayIndexOutOfBoundsException e) + { + return false; + } + } + + /** + * This method checks, if a string contains chars that are not base64 conform. + * + * @param string + * the chars to test + * @return boolean, if the given string is base64 conform, false otherwise + */ + public static boolean isB64(String string) + { + try + { + return Base64.isArrayByteBase64(string.getBytes()); + } + catch (ArrayIndexOutOfBoundsException e) + { + return false; + } + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/DebugHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/DebugHelper.java new file mode 100644 index 0000000..762cb71 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/DebugHelper.java @@ -0,0 +1,90 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector; + +/** + * Contains useful helper methods for debugging. + * + * @author wprinz + */ +public final class DebugHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(DebugHelper.class); + + /** + * Tells, if Strings should be debugged to a file. + * + *

+ * If set to false, the corresponding methods will simply do nothing. + *

+ */ + public static boolean debug_to_file = true; + + /** + * The directory under which the debug files are to be stored. + */ + public static File debug_dir = new File("C:\\wprinz\\Filer\\egiz2"); //$NON-NLS-1$ + + /** + * Writes the given String to a file with the given file name in UTF-8 + * encoding. + * + * @param str + * The String to be written. + * @param file_name + * The file the String will be written to. + */ + public static void debugStringToFile(String str, String file_name) + { + if (!debug_to_file) + { + return; + } + + try + { + File file = new File(debug_dir, file_name); + FileOutputStream fos = new FileOutputStream(file); + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); //$NON-NLS-1$ + osw.write(str); + osw.close(); + } + catch (Exception e) + { + log.error(e.getMessage(), e); + } + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java new file mode 100644 index 0000000..17b98d7 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java @@ -0,0 +1,125 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: FileHelper.java,v 1.2 2006/05/15 12:05:21 wlackner Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * This class provides file reader and writer methods. All methods are static! + * + * @author wlackner + */ +public class FileHelper { + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(FileHelper.class); + + /** + * This method reads a file by reading line by line. + * + * @param fileName the file to be read + * @return the content string of the file + */ + public static String readFromFile(String fileName) { + String file_string = null; + logger_.trace("Looking for file: " + fileName); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8")); + logger_.trace("Reading file: " + fileName); + String line = null; + file_string = ""; + while ((line = reader.readLine()) != null) { + file_string += line; + } + reader.close(); + logger_.debug("File successfully read: " + fileName); + } catch (FileNotFoundException e) { + logger_.debug("File not found: " + fileName); + } catch (IOException e) { + logger_.debug("Error reading file: " + fileName); + } + return file_string; + } + + /** + * This method reads a file by reading line by line. + * + * @param fileName the file to be read + * @return the content string of the file + */ + public static String readFromInputStream(InputStream inputStream) { + String file_string = null; + if (inputStream == null) { + return null; + } + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + String line = null; + file_string = ""; + while ((line = reader.readLine()) != null) { + file_string += line; + } + reader.close(); + } catch (IOException e) { + logger_.debug("Error reading inputstream."); + } + return file_string; + } + + /** + * This method writes a file line by line. + * + * @param fileName the file to be written + * @param fileString the content to be written + * @return true if the file could be written sucessfully, false otherwise + */ + public static boolean writeToFile(String fileName, String fileString) { + BufferedWriter writer; + try { + FileWriter fwriter = new FileWriter(fileName); + writer = new BufferedWriter(fwriter); + writer.write(fileString); + writer.close(); + } catch (IOException e) { + logger_.info("File:" + fileName + " can not be written. Cause:" + e.getMessage()); + return false; + } + return true; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java new file mode 100644 index 0000000..2b0b8c2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalize.java @@ -0,0 +1,55 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Normalize.java,v 1.2 2006/05/15 12:05:21 wlackner Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + + +/** + * Defines an interface to get access to different normalizer implementations. + * + * @author wlackner + */ +public interface Normalize { + + /** + * Normalize a given text. + * @param rawText the raw text to normalize + * @param keepMultipleLineBreaks if true multiple line breaks in a row will not be normalized to a single line break + * @return the normalized string + */ + public String normalize(String rawText, boolean keepMultipleLineBreaks); + /** + * Return the current normalizer version string. + * @return the version string + */ + public String getVersion(); + + /** + * Returns the normalizer line separator string. + * @return the line separator string + */ + public String getNormCR(); + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java new file mode 100644 index 0000000..57b8e6f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/NormalizeV01.java @@ -0,0 +1,184 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: NormalizeV01.java,v 1.5 2006/10/31 08:20:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.Serializable; + +/** + * This ist the first version implementing a normalizer method. The normalize statements are + * performed by using regular expressions. + * + * @author wlackner + */ +public class NormalizeV01 implements Normalize, Serializable { +// 04.11.2010 change by exthex - added keepMultipleLineBreaks parameter to normalize method +// to allow multiple line breaks to not be normalized to a single one + /** + * SVUID. + */ + private static final long serialVersionUID = 2302956630639871601L; + + /** + * The space string + */ + private final static String NORM_SP = " "; //\u0020 + /** + * The line break string --> use only \n because XML-Parser ignores \r\n + */ + private final static String NORM_CR = "\n"; // + /** + * The apostrophe string + */ + private final static String NORM_AP = "'"; //\u0027 + /** + * The quotation mark string + */ + private final static String NORM_QU = "\""; //\u0022 + /** + * The hypens string + */ + private final static String NORM_HY = "-"; //\u002D + /** + * The current version string + */ + protected static final String VERSION = "V01"; + + /** + * The empty constructor. + */ + public NormalizeV01() { + } + + /** + * The normalizer implementation.
+ * Normalizer algorithums: + *
    + *
  1. code all multiple line breaks as \n\n
  2. + *
  3. replace all Tabs and form feeds with spaces
  4. + *
  5. code line breaks as \n
  6. + *
  7. reduce all multiple line breaks into one line break (only if keepMultipleLineBreaks == false), code line break as \r
  8. + *
  9. replace all single line breaks with space
  10. + *
  11. normalize spaces
  12. + *
  13. remove spaces before and after a line break
  14. + *
  15. remove leading and trailing space or line break in the string
  16. + *
  17. normalize line breaks
  18. + *
  19. normalize apostrophes
  20. + *
  21. normalize quotations
  22. + *
  23. normalize hypens
  24. + *
+ * + * @param rawText the text to normalize + * @param keepMultipleLineBreaks if true, multiple newlines in a row will not be normalized to a single line break + * @see at.knowcenter.wag.egov.egiz.tools.Normalize#normalize(java.lang.String) + */ + public String normalize(String rawText, boolean keepMultipleLineBreaks) { + if (rawText == null || rawText.equals("null") || rawText.length() == 0) { + return ""; + } + String normText = rawText; + + // replace all null values + normText = normText.replaceAll("\u0000+", ""); + + // replace all Tabs and form feeds with spaces + normText = normText.replaceAll("[\t\f]", NORM_SP); + + // replace all non breaking spaces with normal spaces + normText = normText.replaceAll("\u00a0+", NORM_SP); + + // code all windows line breaks as \n + normText = normText.replaceAll("\r\n", "\n"); + + // code all mac line breaks as \n + normText = normText.replace('\r', '\n'); + + if (!keepMultipleLineBreaks) + { + // reduce all multiple line breaks into two line breaks, code muliple line break as \r\r + normText = normText.replaceAll("\n[\\s\n]*\n", "\r\r"); + } + + // replace all single line breaks with one line break + normText = normText.replace('\n', '\r'); + + // normalize spaces + normText = normText.replaceAll(" +", NORM_SP); + + // remove spaces before and after a single line break + normText = normText.replaceAll(" ?\r ?", "\r"); + + if (keepMultipleLineBreaks) + { + // remove spaces before and after a multiple line breaks + normText = normText.replaceAll(" ?\r\r ?", "\r\r"); + } else + { + normText = normText.replaceAll(" ?\r\r ?", "\r"); + } + + // remove leading and trailing space or line break in the string + int start_idx = (normText.charAt(0) == ' ' || normText.charAt(0) == '\r' ? 1 : 0); + int end_idx = (normText.charAt(normText.length() - 1) == ' ' || normText.charAt(normText.length() - 1) == '\r' ? normText.length() - 1 : normText.length()); + if (end_idx < start_idx) { + end_idx = start_idx; + } + + // System.err.println("Start idx:" + start_idx + " End idx:" + end_idx + " Text length:" + + // normText_.length()); + normText = normText.substring(start_idx, end_idx); + + // normalize line breaks + normText = normText.replaceAll("\r", NORM_CR); + + // normalize apostrophes + normText = normText.replaceAll("[\u0060\u00B4\u2018\u2019\u201A\u201B]", NORM_AP); + + // normalize quotations + normText = normText.replaceAll("[\u201C\u201D\u201E\u201F]", NORM_QU); + + // normalize hypens + normText = normText.replaceAll("[\u00AD\u2013\u2014]", NORM_HY); + + return normText; + } + + /** + * Return the version string. + * + * @see at.knowcenter.wag.egov.egiz.tools.Normalize#getVersion() + */ + public String getVersion() { + return VERSION; + } + + /** + * Returns the normalizer line separator string. + * @return the line separator string + */ + public String getNormCR() { + return NORM_CR; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java new file mode 100644 index 0000000..a08c12e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/Normalizer.java @@ -0,0 +1,280 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: Normalizer.java,v 1.5 2006/10/31 08:20:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.tools; + +import java.io.Serializable; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * This class provides wrapper methods to get an access to different normalizer implementations. + *
+ * This class is to load the corresponding implementation of a normalizer class. Therefor it seams + * to be a factory. The factory settings are read from the configuration file calling the + * SettingsReader. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.tools.Normalizer + * @see at.knowcenter.wag.egov.egiz.tools.NormalizeV01 + * @see at.knowcenter.wag.egov.egiz.cfg.SettingsReader + */ +public class Normalizer implements Serializable { +// 04.11.2010 changed by exthex - normalize methods use and propagate the keepMultipleNewlines parameter + + /** + * SVUID. + */ + private static final long serialVersionUID = 4201772508393848555L; + + /** + * The current raw string to normalize + */ + private String rawString_ = null; + /** + * The current normalisation version string + */ + private String normVersion_ = null; + /** + * The normalized string cache + */ + private String normString_ = null; + /** + * The reference to the normalizer implementation + */ + private Normalize normalize_ = null; +// /** +// * A given Encoding, not used now +// */ +// private String encoding_ = null; + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + /** + * The factory class prefix + */ + private final static String CLASS_PREFIX = ".Normalize"; + /** + * The default version string + */ + protected final static String DEFAULT_VERSION = "V01"; + /** + * The settings key defined in the settings file + * + * @see SettingsReader + */ + protected final static String SETTINGS_VERSION_KEY = "normalizer.version"; + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(Normalizer.class); + + /** + * New Normalizer init by the raw string and a normalizer version. + * + * @param rawString the raw string to normalize + * @param normVersion the nomalizer version that should be used + * @throws NormalizeException ErrorCode:400 + */ + public Normalizer(String rawString, String normVersion) throws NormalizeException { + rawString_ = rawString; + normVersion_ = normVersion; + init(); + } + + /** + * New Normalizer init by the raw string. + * + * @param rawString the raw string to normalize + * @throws NormalizeException ErrorCode:400 + */ + public Normalizer(String rawString) throws NormalizeException { + rawString_ = rawString; + init(); + } + + /** + * The empty constructor. + * + * @throws NormalizeException ErrorCode:400 + */ + public Normalizer() throws NormalizeException { + init(); + } + + /** + * Load the factory implementation. This method trys to load the configured normalizer library. + * + * @throws NormalizeException + */ + public void init() throws NormalizeException { + loadSettings(); + String class_name = this.getClass().getPackage().getName() + getClassName(); + Class normalize_class = null; + try { + normalize_class = Class.forName(class_name); + } catch (ClassNotFoundException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Class not found:" + class_name); + } + throw new NormalizeException("Can not load normalizer library", e); + } + try { + normalize_ = (Normalize) normalize_class.newInstance(); + } catch (InstantiationException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not instantiate:" + class_name); + } + throw new NormalizeException("Can not load normalizer library", e); + } catch (IllegalAccessException e) { + if (logger_.isEnabledFor(Level.FATAL)) { + logger_.fatal("Can not access:" + class_name); + } + throw new NormalizeException("Can not load normalizer library", e); + } + } + + /** + * Returns the underlying normalizer instance. + * @author tknall + */ + public Normalize getInstance() { + return this.normalize_; + } + + /** + * Read the class postfix from the configuration file + * + * @return the full qualified class name + */ + private String getClassName() { + if (normVersion_ == null) { + normVersion_ = settings_.getSetting(SETTINGS_VERSION_KEY, DEFAULT_VERSION); + } + return CLASS_PREFIX + normVersion_; + } + + /* + * public void setEncoding(String encoding) { encoding_ = encoding; } + */ + + /** + * Set the raw string to normalize + */ + public void setRawString(String rawString) { + rawString_ = rawString; + } + +// /** +// * Return the normalized string. If the chached value does not exist the normalize method from the +// * current normalizer implementation is called. +// * +// * @return the normalized string +// */ +// public String getNormalizedString() { +// if (normString_ == null) { +// normalize(); +// } +// return normString_; +// } + + /** + * Set a normalizer version. This activity load the new requested normalizer implementation. + * + * @param normVersion the normalizer version to be use + * @throws NormalizeException ErrorCode:400 + */ + public void setVersion(String normVersion) throws NormalizeException { + normVersion_ = normVersion; + init(); + } + + /** + * Return the current version string. + * + * @return the normaliser version string + */ + public String getVersion() { + return normVersion_; + } + + /** + * Wrapper method. Call the normalizer implementation method. + * + * @param rawString the raw string to normalize + * @param keepMultipleNewlines + * @return the normalized string + * @see NormalizeV01 + */ + public String normalize(String rawString, boolean keepMultipleNewlines) { + return normalize_.normalize(rawString, keepMultipleNewlines); + } + + /** + * Wrapper method. Call the normalizer implementation method. Normalize the current raw string. + * + * @return the normalized string + * @see NormalizeV01 + */ + public String normalize(boolean keepMultipleNewlines) { + if (normString_ == null) { + normString_ = normalize(rawString_, keepMultipleNewlines); + } + return normString_; + } + + /** + * Returns the normalizer line separator string. + * @return the line separator string + */ + public String getNormCR() { + return normalize_.getNormCR(); + } + + /** + * load the class settings + * + * @throws NormalizeException + * @see SettingsReader + */ + private void loadSettings() throws NormalizeException { + if (settings_ == null) { + try { + settings_ = SettingsReader.getInstance(); + } catch (SettingsException e) { + String log_message = "Can not load normalizer settings. Cause:\n" + e.getMessage(); + logger_.error(log_message, e); + throw new NormalizeException(log_message, e); + } + } + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java new file mode 100644 index 0000000..4442650 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ByteArrayUtils.java @@ -0,0 +1,148 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ByteArrayUtils.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser; + +import java.io.UnsupportedEncodingException; + +/** + * Abstract class that contains utility methods for handling byte arrays. + * + * @author wprinz + */ +public abstract class ByteArrayUtils { + + public static final String BYTE_ARRAY_ENCODING = "ISO-8859-1"; + + /** + * Converts the byte array to a String. + * + * @param data + * The byte array. + * @return Returns the String. + * @throws UnsupportedEncodingException + * Forwarded exception + */ + public static String convertByteArrayToString(final byte[] data) throws UnsupportedEncodingException { + return new String(data, BYTE_ARRAY_ENCODING); + } + + /** + * Finds the first occurance of search in data starting to search from the + * given index. + * + * @param data + * The big array. + * @param index + * The index to start searching from. + * @param search + * The sought array. + * @return Returns the index of the found occurence or -1 if nothing was + * found. + */ + public static int indexOf(final byte[] data, final int index, final byte[] search) { + for (int i = index; i <= data.length - search.length; i++) { + if (compareByteArrays(data, i, search)) { + return i; + } + } + return -1; + } + + /** + * Finds the last occurance of the array. + * + * @param data + * The source array to be searched. + * @param search + * The sought array. + * @return Returns the index of the last occurance - or -1 if nothing was + * found. + */ + public static int lastIndexOf(final byte[] data, byte[] search) { + for (int index = data.length - search.length; index >= 0; index--) { + if (compareByteArrays(data, index, search)) { + return index; + } + } + return -1; + } + + /** + * Compares the two byte arrays for equality. + * + * @param data + * The source array. + * @param index + * In index into the source array marking where the comparison should + * start. + * @param search + * The sought array. + * @return Returns true if the first search.length bytes of data+index and + * search match exactly. Returns false otherwise. + */ + public static boolean compareByteArrays(final byte[] data, final int index, byte[] search) { + if (index < 0 || index >= data.length) { + throw new IndexOutOfBoundsException("The index " + index + " is out of bounds"); + } + + if (search.length > data.length) { + return false; + } + + if (search.length > data.length - index) { + return false; + } + + for (int i = 0; i < search.length; i++) { + if (data[index + i] != search[i]) { + return false; + } + } + + return true; + } + + /** + * Checks, if the sought data byte is contained within the byte array. + * + * @param byte_array + * The byte array. + * @param data + * A data byte sought within the byte array. + * @return Returns true, if the data byte was found (at least once) in the + * byte array, false otherwise. + */ + public static boolean contains(final byte[] byte_array, final byte data) { + for (int i = 0; i < byte_array.length; i++) { + byte b = byte_array[i]; + if (b == data) { + return true; + } + } + return false; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java new file mode 100644 index 0000000..fbaa4de --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/ParseDocument.java @@ -0,0 +1,272 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ParseDocument.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import at.knowcenter.wag.exactparser.parsing.PDFUtils; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NameParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; +import at.knowcenter.wag.exactparser.parsing.results.StartXRefParseResult; +import at.knowcenter.wag.exactparser.parsing.results.TrailerParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefSectionParseResult; + + +/** + * Test class. + * @author wprinz + */ +public class ParseDocument +{ + + public static final String DOCUMENT = "C:/wprinz/temp.pdf"; + + public static final byte[] EGIZ_DICT_NAME = { 'E', 'G', 'I', 'Z', 'S', 'i', + 'g', 'D', 'i', 'c', 't' }; + + public static final byte[] EGIZ_ODS_NAME = { 'O', 'D', 'S' }; + + public static final byte[] EGIZ_XOBJ_NAME = { 'S', 'i', 'g', 'X', 'O', 'b', + 'j', 'e', 'c', 't' }; + + /** + * @param args + */ + public static void main(String[] args) + { + + try + { + File in = new File(DOCUMENT); + FileInputStream fis = new FileInputStream(in); + byte[] pdf = new byte[(int) in.length()]; + fis.read(pdf); + fis.close(); + fis = null; + + List blocks = parseDocument(pdf); + + Iterator it = blocks.iterator(); + while (it.hasNext()) + { + FooterParseResult bpr = (FooterParseResult) it.next(); + + System.out.print("block from " + bpr.start_index + " to " + bpr.next_index); + + if (bpr.tpr.root != null) + { + int root_index = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(bpr.xpr, bpr.tpr.root.ior); + ObjectParseResult root_opr = PDFUtils.parseObject(pdf, root_index); + DictionaryParseResult root_dpr = (DictionaryParseResult) root_opr.object; + + int egiz_index = PDFUtils.indexOfName(pdf, root_dpr.names, EGIZ_DICT_NAME); + if (egiz_index >= 0) + { + System.out.print(" == EGIZDict"); + } + } + + System.out.println(); + } + + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public static List parseDocument(final byte[] pdf) throws IOException + { + //HeaderParseResult hpr = PDFUtils.parseHeader(pdf, 0); + //System.out.println("PDF-version = " + hpr.major + "." + hpr.minor); + + List blocks = new ArrayList(); + + int last_start_xref = PDFUtils.findLastStartXRef(pdf); + StartXRefParseResult last_sxpr = PDFUtils.parseStartXRef(pdf, last_start_xref); + int xref_index = last_sxpr.xref_index; + + for (;;) + { + FooterParseResult fpr = PDFUtils.parseFooter(pdf, xref_index); + blocks.add(0, fpr); + + //System.out.println("tpr.has_predecessor = " + fpr.tpr.has_predecessor); + if (!fpr.tpr.has_predecessor) + { + // eventually parse the PDF header here. + break; + } + + //System.out.println("tpr.prev = " + fpr.tpr.getPrev()); + + xref_index = fpr.tpr.getPrev(); + } + + return blocks; + } + + // public static void parseEGIZ() + // { + // + // int root_index = + // PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(bpr.xpr, + // bpr.tpr.root.ior); + // ObjectParseResult root_opr = PDFUtils.parseObject(pdf, root_index); + // DictionaryParseResult root_dpr = (DictionaryParseResult) root_opr.object; + // + // int egiz_index = PDFUtils.indexOfName(pdf, root_dpr.names, EGIZ_DICT_NAME); + // if (egiz_index >= 0) + // { + // IndirectObjectReferenceParseResult egiz_iorpr = + // (IndirectObjectReferenceParseResult) root_dpr.values.get(egiz_index); + // System.out.println("EGIZ signature info at = " + egiz_iorpr); + // + // int egiz_dict_index = + // PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(bpr.xpr, + // egiz_iorpr.ior); + // ObjectParseResult opr = PDFUtils.parseObject(pdf, egiz_dict_index); + // DictionaryParseResult egiz_dict = (DictionaryParseResult) opr.object; + // + // for (int i = 0; i < egiz_dict.names.size(); i++) + // { + // NameParseResult npr = egiz_dict.names.get(i); + // int len = npr.next_index - npr.name_start_index; + // byte[] name = new byte[len]; + // System.arraycopy(pdf, npr.name_start_index, name, 0, len); + // System.out.print(" " + new String(name, "US-ASCII") + " = "); + // + // System.out.println(egiz_dict.values.get(i)); + // } + // + // // int key = PDFUtils.indexOfName(pdf, egiz_dict.names, new byte [] { 'K', + // // 'e', 'y'}); + // // IndirectObjectReferenceParseResult key_iorpr = + // // (IndirectObjectReferenceParseResult) egiz_dict.values.get(key); + // // int key_offset = + // // PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(xpr, + // // key_iorpr.ior); + // // ObjectParseResult key_opr = PDFUtils.parseObject(pdf, key_offset); + // // StreamParseResult spr = (StreamParseResult) key_opr.object; + // // System.out.println(" key stream from " + spr.content_start_index + " to + // // " + spr.content_end_index); + // // + // // int data_len = spr.content_end_index - spr.content_start_index; + // // byte [] data = new byte[data_len]; + // // System.arraycopy(pdf, spr.content_start_index, data, 0, data_len); + // // System.out.println(new String(data, "US-ASCII")); + // + // } + // else + // { + // System.out.println("No EGIZ block found."); + // } + // + // } + + public static byte[] getOriginalDocument(final File file_name) throws IOException + { + FileInputStream fis = new FileInputStream(file_name); + byte[] pdf = new byte[(int) file_name.length()]; + fis.read(pdf); + fis.close(); + fis = null; + + int last_start_xref = PDFUtils.findLastStartXRef(pdf); + + StartXRefParseResult sxpr = PDFUtils.parseStartXRef(pdf, last_start_xref); + + XRefSectionParseResult xpr = PDFUtils.parseXRefSection(pdf, sxpr.xref_index); + + TrailerParseResult tpr = PDFUtils.parseTrailer(pdf, xpr.next_index); + + System.out.println("tpr.info = " + tpr.info); + System.out.println("tpr.root = " + tpr.root); + System.out.println("tpr.size = " + tpr.size); + + System.out.println("tpr.has_predecessor = " + tpr.has_predecessor); + if (tpr.has_predecessor) + { + System.out.println("tpr.prev = " + tpr.getPrev()); + } + + int root_index = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(xpr, tpr.root.ior); + ObjectParseResult root_opr = PDFUtils.parseObject(pdf, root_index); + DictionaryParseResult root_dpr = (DictionaryParseResult) root_opr.object; + + byte[] EGIZ_TYPE = new String("EGIZSigDict").getBytes("US-ASCII"); + int egiz_index = PDFUtils.indexOfName(pdf, root_dpr.names, EGIZ_TYPE); + if (egiz_index >= 0) + { + System.out.println("The document is EGIZ-signed. ==> extract original document"); + + IndirectObjectReferenceParseResult egiz_iorpr = (IndirectObjectReferenceParseResult) root_dpr.values.get(egiz_index); + System.out.println("EGIZ signature info at = " + egiz_iorpr); + + int egiz_dict_index = PDFUtils.getObjectOffsetFromXRefByIndirectObjectReference(xpr, egiz_iorpr.ior); + ObjectParseResult opr = PDFUtils.parseObject(pdf, egiz_dict_index); + DictionaryParseResult egiz_dict = (DictionaryParseResult) opr.object; + + for (int i = 0; i < egiz_dict.names.size(); i++) + { + NameParseResult npr = (NameParseResult) egiz_dict.names.get(i); + int len = npr.next_index - npr.name_start_index; + byte[] name = new byte[len]; + System.arraycopy(pdf, npr.name_start_index, name, 0, len); + System.out.print(" " + new String(name, "US-ASCII") + " = "); + + System.out.println(egiz_dict.values.get(i)); + } + + // Original document size + int key = PDFUtils.indexOfName(pdf, egiz_dict.names, new byte[] { 'O', + 'D', 'S' }); + NumberParseResult ods = (NumberParseResult) egiz_dict.values.get(key); + + int original_document_size = ods.number; + System.out.println("Original Document Size = " + original_document_size); + + byte[] original = new byte[original_document_size]; + System.arraycopy(pdf, 0, original, 0, original_document_size); + + return original; + } + + System.out.println("No EGIZ block found. ==> the whold document is the original document"); + return pdf; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java new file mode 100644 index 0000000..2bfdf56 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/IndirectObjectReference.java @@ -0,0 +1,57 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: IndirectObjectReference.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing; + +/** + * The IndirectObjectReference class completely holds a so called object + * identifier of an indirect object. + * + *

+ * An indirect object is an object not contained within another object. In + * accordance, a direct object is structurally part of another object. For + * example, a direct String object that is the value of some key in a dictionary + * object. + *

+ *

+ * An object identifier uniquely identifies a specific indirect object by the + * object number and the generation number. In PDF such an object identifier may + * be used to reference to the object. + *

+ * + * @author wprinz + */ +public class IndirectObjectReference { + + public int object_number; + + public int generation_number; + + //@Override + public String toString() { + return object_number + " " + generation_number; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java new file mode 100644 index 0000000..0ee5863 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFNames.java @@ -0,0 +1,184 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFNames.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing; + +/** + * Abstract class that contains several frequently used PDF constants. + * + *

+ * The PDF specification partitions the character set (ASCII) into three groups: + *

+ *
    + *
  • Whitespace characters (space, tab, etc., but also newline and carriage + * return) used to separate tokens. Unless otherwise specified a group of + * consecutive whitespace characters behaves like a single whitespace character.
  • + *
  • Delimiter characters ('(', '<', etc., but also '/', which precedes the + * PDF Key Names in dictionaries) that are used to encircle semantic groups. + *
  • Regular characters are per definition the rest characters that are + * neither whitespaces nor delimiters.
  • + *
+ *

+ * Newlines consist per default of CR and LF, but also LF and even CR alone are + * allowed. It seems that all variations of newlines may exist within a single + * document. + *

+ * + * @author wprinz + */ +public abstract class PDFNames +{ + + /** + * The standard encoding of PDF tokens and names. + * + *

+ * PDF is usually an 8 bit format. Binary data etc. can be saves just as it + * is. Nevertheless all PDF tokens ('xref', 'obj', etc.) and PDF Names + * ('/Size', '/Pages', '/Type', etc.) must be in 7 bit ASCII US encoding. + *

+ *

+ * Therefor, whenever using Java Strings to convert e.g. numbers to such PDF + * tokens use this encoding constant. + *

+ *

+ * The same applies for PDF token/name byte arrays that are retransfromed to + * Java Strings. + *

+ */ + public static final String PDF_STANDARD_ENCODING = "US-ASCII"; + + // Whitespace characters + + // TABLE 3.1 White-space characters + // DECIMAL HEXADECIMAL OCTAL NAME + // 0 00 000 Null (NUL) + // 9 09 011 Tab (HT) + // 10 0A 012 Line feed (LF) + // 12 0C 014 Form feed (FF) + // 13 0D 015 Carriage return + // 32 20 040 Space (SP) + + public static final byte WHITESPACE_NUL = 0x00; + + public static final byte WHITESPACE_HT = 0x09; + + public static final byte WHITESPACE_LF = 0x0A; + + public static final byte WHITESPACE_FF = 0x0C; + + public static final byte WHITESPACE_CR = 0x0D; + + public static final byte WHITESPACE_SP = 0x20; + + public static final byte[] WHITESPACE_CHARACTERS = { WHITESPACE_NUL, + WHITESPACE_HT, WHITESPACE_LF, WHITESPACE_FF, WHITESPACE_CR, WHITESPACE_SP }; + + // comment character + + public static final byte COMMENT = '%'; + + // PDF-version + + public static final byte[] PDF_VERSION_STR = { 'P', 'D', 'F', '-' }; + + public static final byte PDF_VERSION_SEPARATOR = '.'; + + // delimiter characters + + public static final byte DELIMITER_STRING_OPEN = '('; + + public static final byte DELIMITER_STRING_CLOSE = ')'; + + public static final byte DELIMITER_HEXSTRING_OPEN = '<'; + + public static final byte DELIMITER_HEXSTRING_CLOSE = '>'; + + public static final byte DELIMITER_ARRAY_OPEN = '['; + + public static final byte DELIMITER_ARRAY_CLOSE = ']'; + + public static final byte DELIMITER_CURLY_OPEN = '{'; + + public static final byte DELIMITER_CURLY_CLOSE = '}'; + + public static final byte DELIMITER_NAME = '/'; + + public static final byte[] DELIMITER_CHARACTERS = { DELIMITER_STRING_OPEN, + DELIMITER_STRING_CLOSE, DELIMITER_HEXSTRING_OPEN, + DELIMITER_HEXSTRING_CLOSE, DELIMITER_ARRAY_OPEN, DELIMITER_ARRAY_CLOSE, + DELIMITER_CURLY_OPEN, DELIMITER_CURLY_CLOSE, DELIMITER_NAME }; + + // Footer + + public static final byte[] XREF_STR = { 'x', 'r', 'e', 'f' }; + + public static final byte[] TRAILER_STR = { 't', 'r', 'a', 'i', 'l', 'e', 'r' }; + + public static final byte[] STARTXREF_STR = { 's', 't', 'a', 'r', 't', 'x', + 'r', 'e', 'f' }; + + public static final byte[] EOF_STR = { '%', '%', 'E', 'O', 'F' }; + + // objects + + public static final byte[] OBJ_STR = { 'o', 'b', 'j' }; + + public static final byte[] ENDOBJ_STR = { 'e', 'n', 'd', 'o', 'b', 'j' }; + + public static final byte[] DICT_START_STR = { DELIMITER_HEXSTRING_OPEN, + DELIMITER_HEXSTRING_OPEN }; + + public static final byte[] DICT_END_STR = { DELIMITER_HEXSTRING_CLOSE, + DELIMITER_HEXSTRING_CLOSE }; + + public static final byte[] STREAM_STR = { 's', 't', 'r', 'e', 'a', 'm' }; + + public static final byte[] ENDSTREAM_STR = { 'e', 'n', 'd', 's', 't', 'r', + 'e', 'a', 'm' }; + + public static final byte[] NULL_STR = { 'n', 'u', 'l', 'l' }; + + public static final byte[] TRUE_STR = { 't', 'r', 'u', 'e' }; + + public static final byte[] FALSE_STR = { 'f', 'a', 'l', 's', 'e' }; + + // indirect object references + + public static final byte[] REFERENCE_STR = { 'R' }; + + // Dictionary keys + + public static final byte[] SIZE_STR = { 'S', 'i', 'z', 'e' }; + + public static final byte[] PREV_STR = { 'P', 'r', 'e', 'v' }; + + public static final byte[] ROOT_STR = { 'R', 'o', 'o', 't' }; + + public static final byte[] INFO_STR = { 'I', 'n', 'f', 'o' }; + + public static final byte[] LENGTH_STR = { 'L', 'e', 'n', 'g', 't', 'h' }; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java new file mode 100644 index 0000000..de356c9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/PDFUtils.java @@ -0,0 +1,1405 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: PDFUtils.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.exactparser.ByteArrayUtils; +import at.knowcenter.wag.exactparser.parsing.results.ArrayParseResult; +import at.knowcenter.wag.exactparser.parsing.results.BooleanParseResult; +import at.knowcenter.wag.exactparser.parsing.results.DictionaryParseResult; +import at.knowcenter.wag.exactparser.parsing.results.EOFParseResult; +import at.knowcenter.wag.exactparser.parsing.results.FooterParseResult; +import at.knowcenter.wag.exactparser.parsing.results.HeaderParseResult; +import at.knowcenter.wag.exactparser.parsing.results.HexStringParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IndirectObjectReferenceParseResult; +import at.knowcenter.wag.exactparser.parsing.results.IntegerParseResult; +import at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NameParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NullParseResult; +import at.knowcenter.wag.exactparser.parsing.results.NumberParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectHeaderParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ObjectParseResult; +import at.knowcenter.wag.exactparser.parsing.results.ParseResult; +import at.knowcenter.wag.exactparser.parsing.results.StartXRefParseResult; +import at.knowcenter.wag.exactparser.parsing.results.StreamParseResult; +import at.knowcenter.wag.exactparser.parsing.results.TrailerParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefLineParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefSectionParseResult; +import at.knowcenter.wag.exactparser.parsing.results.XRefSubSectionParseResult; + + + +/** + * Abstract class that contains several static utility methods for parsing and + * analyzing PDF documents on the lowest level. + * + *

+ * Most operations require random access to the PDF data (mostly to verify the + * synthax). So the whole PDF document has to be provided as a byte array. The + * term "pdf+index" states a specific position index within this byte array. + *

+ * + * @author wprinz + * + */ +public abstract class PDFUtils +{ + private static Logger log = Logger.getLogger(PDFUtils.class); + + public static boolean isWhitespace(final byte data) + { + return ByteArrayUtils.contains(PDFNames.WHITESPACE_CHARACTERS, data); + } + + public static boolean isDelimiter(final byte data) + { + return ByteArrayUtils.contains(PDFNames.DELIMITER_CHARACTERS, data); + } + + protected static boolean isRegular(final byte data) + { + return !(isWhitespace(data) || isDelimiter(data)); + } + + /** + * Skips whitespace. + * + *

+ * Skips all whitespace, which may be none, one or multiple whitespace + * characters. + *

+ *

+ * Note that this also skips newline characters (which belong to whitespace as + * well). + *

+ * + * @param data + * The PDF data. + * @param index + * The index. + * @return Returns the index of the first non whitespace character. This may + * be equal to index if no whitespaces were skipped at all. + */ + public static int skipWhitespace(final byte[] data, final int index) + { + int non_whitespace_index = index; + while (isWhitespace(data[non_whitespace_index])) + { + non_whitespace_index++; + } + return non_whitespace_index; + } + + /** + * Skips bytes until whitespace is reached. + * + *

+ * Skips all non whitespace characters, which may be none at all. + *

+ * + * @param data + * The PDF data. + * @param index + * The index. + * @return Returns the index of the first whitespace character. This may be + * equal to index if no non whitespaces were skipped at all. + */ + public static int skipToWhitespace(final byte[] data, final int index) + { + int whitespace_index = index; + while (!isWhitespace(data[whitespace_index])) + { + whitespace_index++; + } + return whitespace_index; + } + + protected static final byte[] LINE_TERMINATOR_CRLF = { + PDFNames.WHITESPACE_CR, PDFNames.WHITESPACE_LF }; + + protected static final byte[] LINE_TERMINATOR_CRALONE = { PDFNames.WHITESPACE_CR }; + + protected static final byte[] LINE_TERMINATOR_LF = { PDFNames.WHITESPACE_LF }; + + public static boolean isNewline(final byte[] data, final int index) + { + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_LF)) + { + return true; + } + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRLF)) + { + return true; + } + // although not specified by PDF, some applications use the CR alone as line + // terminator + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRALONE)) + { + return true; + } + return false; + } + + public static int skipNewline(final byte[] data, final int index) + { + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_LF)) + { + return index + LINE_TERMINATOR_LF.length; + } + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRLF)) + { + return index + LINE_TERMINATOR_CRLF.length; + } + // although not specified by PDF, some applications use the CR alone as line + // terminator + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRALONE)) + { + return index + LINE_TERMINATOR_CRALONE.length; + } + + assert false : "don't call this if you don't expect a newline - call skipWhitespace instead"; + return index; + } + + public static int skipToNewline(final byte[] data, final int index) + { + int current_index = index; + for (;;) + { + if (ByteArrayUtils.compareByteArrays(data, current_index, LINE_TERMINATOR_LF)) + { + return current_index + LINE_TERMINATOR_LF.length; + } + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRLF)) + { + return index + LINE_TERMINATOR_CRLF.length; + } + // although not specified by PDF, some applications use the CR alone as + // line terminator + if (ByteArrayUtils.compareByteArrays(data, index, LINE_TERMINATOR_CRALONE)) + { + return index + LINE_TERMINATOR_CRALONE.length; + } + current_index++; + } + } + + /** + * Parses a boolean value. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static BooleanParseResult parseBoolean(final byte[] pdf, + final int index) + { + BooleanParseResult bpr = new BooleanParseResult(); + bpr.start_index = index; + + if (ByteArrayUtils.compareByteArrays(pdf, bpr.start_index, PDFNames.TRUE_STR)) + { + bpr.value = true; + bpr.next_index = bpr.start_index + PDFNames.TRUE_STR.length; + + return bpr; + } + if (ByteArrayUtils.compareByteArrays(pdf, bpr.start_index, PDFNames.FALSE_STR)) + { + bpr.value = false; + bpr.next_index = bpr.start_index + PDFNames.FALSE_STR.length; + + return bpr; + } + + throw new RuntimeException("Boolean couldn't be parsed at index " + index); + } + + public static boolean isSign(final byte data) + { + return data == '+' || data == '-'; + } + + public static boolean isNumeric(final byte data) + { + return '0' <= data && data <= '9'; + } + + /** + * Reads the (positive integer) number from the data. The number must be + * terminated by the end of line. + * + * @param data + * The data. + * @param index + * The index. + * @return Returns the read number. + */ + public static int readNumberFromByteArray(final byte[] data, final int index) + { + NumberParseResult npr = parseNumberFromByteArray(data, index); + + assert npr.number >= 0; + return npr.number; + } + + /** + * Parses an unsigned integer. + * + *

+ * The integer must be a block of successive number characters. It must not be + * preceded by a sign (not even '+'). + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static IntegerParseResult parseUnsignedInteger(final byte[] pdf, + final int index) + { + assert isNumeric(pdf[index]); + + String number = ""; + + int cur_index = index; + while (isNumeric(pdf[cur_index])) + { + + number += (char) pdf[cur_index]; + + cur_index++; + } + + // TODO: make better + int int_value = Integer.parseInt(number); + + assert int_value >= 0; + + IntegerParseResult ipr = new IntegerParseResult(); + ipr.start_index = index; + ipr.next_index = cur_index; + ipr.number = int_value; + return ipr; + } + + /** + * Parses a (potentially) signed integer. + * + *

+ * The integer must be a block of successive number characters. It may be + * preceded by a sign character ('+' or '-'). + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static IntegerParseResult parseInteger(final byte[] pdf, + final int index) + { + assert isSign(pdf[index]) || isNumeric(pdf[index]); + + int sign = +1; + int number_start = index; + if (pdf[index] == '+') + { + sign = +1; + number_start++; + } + else + { + if (pdf[index] == '-') + { + sign = -1; + number_start++; + } + else + { + assert isNumeric(pdf[index]); + } + } + + IntegerParseResult ipr = parseUnsignedInteger(pdf, number_start); + ipr.start_index = index; + ipr.number *= sign; + return ipr; + } + + /** + * Parses an arbitrary number; + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static NumberParseResult parseNumberFromByteArray(final byte[] pdf, + int index) + { + String number = ""; + + assert isSign(pdf[index]) || isNumeric(pdf[index]); + + int sign = +1; + if (pdf[index] == '+') + { + sign = +1; + index++; + } + else + { + if (pdf[index] == '-') + { + sign = -1; + index++; + } + else + { + assert isNumeric(pdf[index]); + } + } + + while (isNumeric(pdf[index]) || pdf[index] == '.') + { + + char digit = (char) pdf[index]; + number += digit; + + index++; + } + + NumberParseResult npr = new NumberParseResult(); + npr.next_index = index; + // TODO: make better + try + { + npr.number = Integer.parseInt(number) * sign; + } + catch (NumberFormatException e) + { + npr.floating = Float.parseFloat(number) * sign; + } + + return npr; + } + + /** + * Searches the last occurrence of the "startxref" entry ... in other words + * starts the search from the end of the document and works reversely. + * + * @param pdf + * The complete PDF file data. + * @return Returns the offset (byte index) of the "startxref" entry. + */ + public static int findLastStartXRef(final byte[] pdf) + { + return ByteArrayUtils.lastIndexOf(pdf, PDFNames.STARTXREF_STR); + } + + /** + * Parses the xref section at pdf+index. + * + *

+ * An xref section starts with 'xref' and contains one or more xref + * sub-sections. + *

+ * + * @param pdf + * The PDF data. + * @param index + * The start index of the xref table. + * @return Returns the result of the parsing operation. + */ + public static XRefSectionParseResult parseXRefSection(final byte[] pdf, + final int index) + { + at.knowcenter.wag.exactparser.parsing.results.XRefSectionParseResult xpr = new XRefSectionParseResult(); + xpr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, xpr.start_index, PDFNames.XREF_STR); + assert isNewline(pdf, xpr.start_index + PDFNames.XREF_STR.length); + + int cur_index = skipWhitespace(pdf, xpr.start_index + PDFNames.XREF_STR.length); + // skipNewline(pdf, xpr.start_index + PDFNames.XREF_STR.length); + + for (;;) + { + // trailer ends the xref section. + if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.TRAILER_STR)) + { + break; + } + + // no trailer ==> another xref section + + XRefSubSectionParseResult sspr = parseXRefSubSection(pdf, cur_index); + xpr.appendXRefSubSection(sspr); + + cur_index = sspr.next_index; + } + + xpr.next_index = cur_index; + assert ByteArrayUtils.compareByteArrays(pdf, xpr.next_index, PDFNames.TRAILER_STR); + + return xpr; + } + + /** + * Parses a xref sub-section. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static XRefSubSectionParseResult parseXRefSubSection(final byte[] pdf, + final int index) + { + XRefSubSectionParseResult sspr = new XRefSubSectionParseResult(); + sspr.start_index = index; + + NumberParseResult start_obj_num_npr = parseNumberFromByteArray(pdf, sspr.start_index); + sspr.start_obj_number = start_obj_num_npr.number; + assert sspr.start_obj_number >= 0; + + assert isWhitespace(pdf[start_obj_num_npr.next_index]); + int num_obj_index = skipWhitespace(pdf, start_obj_num_npr.next_index); + + NumberParseResult num_obj_npr = parseNumberFromByteArray(pdf, num_obj_index); + sspr.num_objects = num_obj_npr.number; + + // assert isNewline(pdf, num_obj_npr.next_index); + assert isWhitespace(pdf[num_obj_npr.next_index]); + int start_of_line = skipWhitespace(pdf, num_obj_npr.next_index); + // skipNewline(pdf, num_obj_npr.next_index); + + for (int i = 0; i < sspr.num_objects; i++) + { + final int cur_object_number = sspr.start_obj_number + i; + + XRefLineParseResult lpr = parseXrefLine(pdf, start_of_line); + sspr.appendXRefLine(lpr); + + // System.out.println("xref line of object " + (oc.start_obj_number + i) + + // " at " + lpr.start_index + ": " + lpr.object_offset + " " + + // lpr.generation_number + " " + (char) lpr.object_usage); + + if (lpr.object_usage == 'n') + { + // check the line - this simple check may make problems with object + // streams and xref streams + ObjectHeaderParseResult ohpr = parseObjectHeader(pdf, lpr.object_offset); + assert ohpr.object_number == cur_object_number; + assert ohpr.generation_number == lpr.generation_number; + } + + start_of_line = lpr.next_index; + } + + sspr.next_index = start_of_line; + return sspr; + } + + /** + * Parses a single 20 bytes xref line at pdf+index. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static XRefLineParseResult parseXrefLine(final byte[] pdf, + final int index) + { + XRefLineParseResult lpr = new XRefLineParseResult(); + + lpr.start_index = index; + + IntegerParseResult object_offset_ipr = parseUnsignedInteger(pdf, lpr.start_index); + lpr.object_offset = object_offset_ipr.number; + assert lpr.object_offset >= 0; + assert lpr.object_offset < pdf.length; + assert object_offset_ipr.next_index == lpr.start_index + 10; + + assert pdf[object_offset_ipr.next_index] == PDFNames.WHITESPACE_SP; // Standard + // explicitely + // says 1 + // single + // SPACE + int generation_number_index = object_offset_ipr.next_index + 1; + + IntegerParseResult generation_number_ipr = parseUnsignedInteger(pdf, generation_number_index); + lpr.generation_number = generation_number_ipr.number; + assert generation_number_ipr.next_index == lpr.start_index + 16; + + assert pdf[generation_number_ipr.next_index] == PDFNames.WHITESPACE_SP; + int usage_index = generation_number_ipr.next_index + 1; + + lpr.object_usage = pdf[usage_index]; + assert lpr.object_usage == 'n' || lpr.object_usage == 'f'; + + if (pdf[usage_index + 1] == PDFNames.WHITESPACE_SP) + { + assert pdf[usage_index + 2] == PDFNames.WHITESPACE_CR || pdf[usage_index + 2] == PDFNames.WHITESPACE_LF; + } + else + { + assert pdf[usage_index + 1] == PDFNames.WHITESPACE_CR; + assert pdf[usage_index + 2] == PDFNames.WHITESPACE_LF; + } + + lpr.next_index = usage_index + 3; + + assert lpr.next_index == lpr.start_index + 20; + + return lpr; + } + + public static int indexOfName(final byte[] pdf, List names, + byte[] sought) + { + for (int i = 0; i < names.size(); i++) + { + NameParseResult name = (NameParseResult) names.get(i); + if (ByteArrayUtils.compareByteArrays(pdf, name.name_start_index, sought)) + { + return i; + } + } + return -1; + } + + public static TrailerParseResult parseTrailer(final byte[] pdf, + final int index) + { + TrailerParseResult tpr = new TrailerParseResult(); + tpr.start_index = index; + tpr.has_predecessor = false; + + assert ByteArrayUtils.compareByteArrays(pdf, tpr.start_index, PDFNames.TRAILER_STR); + + // assert isWhitespace(pdf[tpr.start_index + PDFNames.TRAILER_STR.length]); + tpr.contents_index = skipWhitespace(pdf, tpr.start_index + PDFNames.TRAILER_STR.length); + + int trailer_dict_index = skipWhitespace(pdf, tpr.contents_index); + + assert ByteArrayUtils.compareByteArrays(pdf, trailer_dict_index, PDFNames.DICT_START_STR); + + tpr.dpr = parseDictionary(pdf, trailer_dict_index); + + int cur_index = tpr.dpr.next_index; + + int info_index = indexOfName(pdf, tpr.dpr.names, PDFNames.INFO_STR); + if (info_index >= 0) + { + tpr.info = (IndirectObjectReferenceParseResult) tpr.dpr.values.get(info_index); + } + + int root_index = indexOfName(pdf, tpr.dpr.names, PDFNames.ROOT_STR); + if (root_index >= 0) + { + tpr.root = (IndirectObjectReferenceParseResult) tpr.dpr.values.get(root_index); + } + + tpr.size = ((NumberParseResult) tpr.dpr.values.get(indexOfName(pdf, tpr.dpr.names, PDFNames.SIZE_STR))).number; + + int prev_index = indexOfName(pdf, tpr.dpr.names, PDFNames.PREV_STR); + if (prev_index >= 0) + { + tpr.has_predecessor = true; + tpr.setPrev(((NumberParseResult) tpr.dpr.values.get(prev_index)).number); + } + + // + // int cur_index = skipWhitespace(pdf, trailer_dict_index + + // PDFNames.DICT_START_STR.length); + // for (;;) { + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, + // PDFNames.DICT_END_STR)) { + // cur_index += PDFNames.DICT_END_STR.length; + // break; + // } + // + // assert pdf[cur_index] == PDFNames.DELIMITER_NAME; + // cur_index++; + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.INFO_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.INFO_STR.length]); + // int ir_index = skipWhitespace(pdf, cur_index + PDFNames.INFO_STR.length); + // + // IndirectObjectReferenceParseResult iorpr = + // parseIndirectObjectReference(pdf, ir_index); + // tpr.info = iorpr; + // + // cur_index = skipWhitespace(pdf, iorpr.next_index); + // continue; + // } + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.ROOT_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.ROOT_STR.length]); + // int ir_index = skipWhitespace(pdf, cur_index + PDFNames.ROOT_STR.length); + // + // IndirectObjectReferenceParseResult iorpr = + // parseIndirectObjectReference(pdf, ir_index); + // tpr.root = iorpr; + // + // cur_index = skipWhitespace(pdf, iorpr.next_index); + // continue; + // } + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.SIZE_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.SIZE_STR.length]); + // int size_index = skipWhitespace(pdf, cur_index + + // PDFNames.SIZE_STR.length); + // + // NumberParseResult npr = parseNumberFromByteArray(pdf, size_index); + // tpr.size = npr.number; + // assert tpr.size > 0; + // + // cur_index = skipWhitespace(pdf, npr.next_index); + // continue; + // } + // + // if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.PREV_STR)) + // { + // assert isWhitespace(pdf[cur_index + PDFNames.PREV_STR.length]); + // int prev_index = skipWhitespace(pdf, cur_index + + // PDFNames.PREV_STR.length); + // + // NumberParseResult npr = parseNumberFromByteArray(pdf, prev_index); + // tpr.has_predecessor = true; + // tpr.setPrev(npr.number); + // assert tpr.getPrev() >= 0; + // assert tpr.getPrev() < pdf.length; + // + // assert ByteArrayUtils.compareByteArrays(pdf, tpr.getPrev(), + // PDFNames.XREF_STR); + // + // cur_index = skipWhitespace(pdf, npr.next_index); + // continue; + // } + // + // // unrecognized type + // // skip to next delimiter + // // TODO: this will not work with nested dicts. - already deprecated + // while (pdf[cur_index] != PDFNames.DELIMITER_NAME) { + // cur_index++; + // } + // } + + tpr.contents_end_index = cur_index; + tpr.next_index = skipWhitespace(pdf, tpr.contents_end_index); + + assert ByteArrayUtils.compareByteArrays(pdf, tpr.next_index, PDFNames.STARTXREF_STR); + return tpr; + } + + /** + * Parses the startxref section at pdf+index. + * + * @param pdf + * The complete PDF file data. + * @param index + * The index of the startxref section. + * @return Returns the retsult of the parsing operation. + */ + public static StartXRefParseResult parseStartXRef(final byte[] pdf, + final int index) + { + StartXRefParseResult spr = new StartXRefParseResult(); + spr.next_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.STARTXREF_STR); + assert isNewline(pdf, index + PDFNames.STARTXREF_STR.length); + + int index_of_number = skipWhitespace(pdf, index + PDFNames.STARTXREF_STR.length); + // skipNewline(pdf, index + PDFNames.STARTXREF_STR.length); + NumberParseResult npr = parseNumberFromByteArray(pdf, index_of_number); + spr.xref_index = npr.number; + + assert isNewline(pdf, npr.next_index); + spr.next_index = skipWhitespace(pdf, npr.next_index); + // skipNewline(pdf, npr.next_index); + + assert ByteArrayUtils.compareByteArrays(pdf, spr.next_index, PDFNames.EOF_STR); + + assert spr.xref_index >= 0; + assert spr.xref_index < pdf.length; + + // A linearized document sets the startxref value of the first page's footer + // to 0. + if (spr.xref_index != 0) + { + assert ByteArrayUtils.compareByteArrays(pdf, spr.xref_index, PDFNames.XREF_STR); + } + + return spr; + } + + /** + * Parses the End Of File (EOF) marker at pdf+index. + * + * @param pdf + * The PDF data. + * @param index + * The index where to start the parsing. + * @return Returns the result of the parsing operation. + */ + public static EOFParseResult parseEOF(final byte[] pdf, final int index) + { + EOFParseResult eofpr = new EOFParseResult(); + eofpr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, eofpr.start_index, PDFNames.EOF_STR); + + eofpr.eof_end_index = eofpr.start_index + PDFNames.EOF_STR.length; + + // Note: The EOF marker is not necessarily terminated with a + // newline. + + // perhaps explicitely determine a newline. + + eofpr.next_index = eofpr.eof_end_index; + + return eofpr; + } + + public static boolean isIndirectObjectReference(final byte[] pdf, + final int index) + { + IndirectObjectReferenceParseResult iorpr = new IndirectObjectReferenceParseResult(); + iorpr.ior = new IndirectObjectReference(); + iorpr.start_index = index; + + if (!PDFUtils.isNumeric(pdf[iorpr.start_index])) + { + return false; + } + NumberParseResult object_number_npr = parseNumberFromByteArray(pdf, iorpr.start_index); + iorpr.ior.object_number = object_number_npr.number; + if (iorpr.ior.object_number <= 0) + { + return false; + } + + if (!isWhitespace(pdf[object_number_npr.next_index])) + { + return false; + } + int generation_number_index = skipWhitespace(pdf, object_number_npr.next_index); + + if (!PDFUtils.isNumeric(pdf[generation_number_index])) + { + return false; + } + NumberParseResult generation_number_npr = parseNumberFromByteArray(pdf, generation_number_index); + iorpr.ior.generation_number = generation_number_npr.number; + if (iorpr.ior.generation_number < 0) + { + return false; + } + + if (!isWhitespace(pdf[generation_number_npr.next_index])) + { + return false; + } + int R_index = skipWhitespace(pdf, generation_number_npr.next_index); + + if (!ByteArrayUtils.compareByteArrays(pdf, R_index, PDFNames.REFERENCE_STR)) + { + return false; + } + + iorpr.next_index = R_index + PDFNames.REFERENCE_STR.length; + + return true; + } + + /** + * Parses an indirect object reference. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static IndirectObjectReferenceParseResult parseIndirectObjectReference( + final byte[] pdf, final int index) + { + + assert isIndirectObjectReference(pdf, index); + + IndirectObjectReferenceParseResult iorpr = new IndirectObjectReferenceParseResult(); + iorpr.ior = new IndirectObjectReference(); + iorpr.start_index = index; + + NumberParseResult object_number_npr = parseNumberFromByteArray(pdf, iorpr.start_index); + iorpr.ior.object_number = object_number_npr.number; + assert iorpr.ior.object_number > 0; + + assert isWhitespace(pdf[object_number_npr.next_index]); + int generation_number_index = skipWhitespace(pdf, object_number_npr.next_index); + + NumberParseResult generation_number_npr = parseNumberFromByteArray(pdf, generation_number_index); + iorpr.ior.generation_number = generation_number_npr.number; + assert iorpr.ior.generation_number >= 0; + + assert isWhitespace(pdf[generation_number_npr.next_index]); + int R_index = skipWhitespace(pdf, generation_number_npr.next_index); + + assert ByteArrayUtils.compareByteArrays(pdf, R_index, PDFNames.REFERENCE_STR); + + iorpr.next_index = R_index + PDFNames.REFERENCE_STR.length; + + return iorpr; + } + + /** + * Parses the object header at pdf+index. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static ObjectHeaderParseResult parseObjectHeader(final byte[] pdf, + final int index) + { + ObjectHeaderParseResult ohpr = new ObjectHeaderParseResult(); + + ohpr.start_index = index; + + NumberParseResult object_number_npr = parseNumberFromByteArray(pdf, ohpr.start_index); + ohpr.object_number = object_number_npr.number; + assert ohpr.object_number > 0; + + assert isWhitespace(pdf[object_number_npr.next_index]); + int generation_number_index = skipWhitespace(pdf, object_number_npr.next_index); + + NumberParseResult generation_number_npr = parseNumberFromByteArray(pdf, generation_number_index); + ohpr.generation_number = generation_number_npr.number; + assert ohpr.generation_number >= 0; + + assert isWhitespace(pdf[generation_number_npr.next_index]); + int obj_index = skipWhitespace(pdf, generation_number_npr.next_index); + + assert ByteArrayUtils.compareByteArrays(pdf, obj_index, PDFNames.OBJ_STR); + + // not all pdfwriters make a newline after obj... + // assert isNewline(pdf, obj_index + PDFNames.OBJ_STR.length); + // ohpr.next_index = skipNewline(pdf, obj_index + PDFNames.OBJ_STR.length); + ohpr.next_index = skipWhitespace(pdf, obj_index + PDFNames.OBJ_STR.length); + + return ohpr; + } + + public static ObjectParseResult parseObject(final byte[] pdf, final int index) + { + ObjectParseResult opr = new ObjectParseResult(); + opr.start_index = index; + + opr.header = parseObjectHeader(pdf, opr.start_index); + opr.content_index = opr.header.next_index; + + int cur_index = skipWhitespace(pdf, opr.content_index); + + opr.object = parseUnknownObject(pdf, cur_index); + + cur_index = skipWhitespace(pdf, opr.object.next_index); + + opr.end_of_content_index = cur_index; + assert ByteArrayUtils.compareByteArrays(pdf, opr.end_of_content_index, PDFNames.ENDOBJ_STR); + + cur_index = opr.end_of_content_index + PDFNames.ENDOBJ_STR.length; + + opr.next_index = cur_index; + //assert isNewline(pdf, cur_index); + //opr.next_index = skipNewline(pdf, cur_index); + + return opr; + } + + public static ParseResult parseUnknownObject(final byte[] pdf, final int index) + { + if (ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.DICT_START_STR)) + { + DictionaryParseResult dpr = parseDictionary(pdf, index); + + int possible_stream_index = skipWhitespace(pdf, dpr.next_index); + if (ByteArrayUtils.compareByteArrays(pdf, possible_stream_index, PDFNames.STREAM_STR)) + { + return parseStream(pdf, possible_stream_index, dpr); + } + + return dpr; + } + + if (ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.NULL_STR)) + { + return parseNull(pdf, index); + } + + if (ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.TRUE_STR) || ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.FALSE_STR)) + { + return parseBoolean(pdf, index); + } + + final byte first_byte = pdf[index]; + + if (isNumeric(first_byte) || isSign(first_byte)) + { + + // try to parse a Indirect reference first - if this fails, parse a number + if (isIndirectObjectReference(pdf, index)) + { + return parseIndirectObjectReference(pdf, index); + } + + return parseNumberFromByteArray(pdf, index); + } + + ParseResult pr = null; + + switch (first_byte) + { + case PDFNames.DELIMITER_STRING_OPEN: + pr = parseLiteralString(pdf, index); + break; + case PDFNames.DELIMITER_HEXSTRING_OPEN: + pr = parseHexString(pdf, index); + break; + case PDFNames.DELIMITER_ARRAY_OPEN: + pr = parseArray(pdf, index); + break; + case PDFNames.DELIMITER_NAME: + pr = parseName(pdf, index); + break; + default: + throw new RuntimeException("Unknown first_byte " + first_byte + "' when parsing an unknown object at index=" + index + "."); + // assert false : "nyi or invalid char"; + } + assert pr != null; + + return pr; + } + + /** + * Parses a literal string. + * + *

+ * A literal string is a string of ASCII characters enclosed by '(' and ')'. + * Balanced pairs of '(' and ')' are allowed within the string. Unbalanced '(' + * or ')' must be escaped as '\(' or '\)'. + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static LiteralStringParseResult parseLiteralString(final byte[] pdf, + final int index) + { + LiteralStringParseResult lspr = new LiteralStringParseResult(); + lspr.start_index = index; + + assert pdf[lspr.start_index] == PDFNames.DELIMITER_STRING_OPEN; + + lspr.content_start_index = lspr.start_index + 1; + + int cur_index = lspr.content_start_index; + int parenthesis_stack = 0; + for (;;) + { + if (pdf[cur_index] == '\\' && (pdf[cur_index + 1] == PDFNames.DELIMITER_STRING_CLOSE || pdf[cur_index + 1] == PDFNames.DELIMITER_STRING_OPEN)) + { + cur_index += 2; + continue; + } + if (pdf[cur_index] == PDFNames.DELIMITER_STRING_OPEN) + { + parenthesis_stack++; + } + if (pdf[cur_index] == PDFNames.DELIMITER_STRING_CLOSE) + { + assert parenthesis_stack >= 0; + + if (parenthesis_stack == 0) + { + break; + } + + assert parenthesis_stack > 0; + parenthesis_stack--; + + } + + cur_index++; + } + + lspr.content_end_index = cur_index; + assert pdf[lspr.content_end_index] == PDFNames.DELIMITER_STRING_CLOSE; + + lspr.next_index = lspr.content_end_index + 1; + + return lspr; + } + + protected static boolean isHex(final byte data) + { + return isNumeric(data) || ('a' <= data && data <= 'f') || ('A' <= data && data <= 'f'); + } + + /** + * Parses a hexadecimal string. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + */ + public static HexStringParseResult parseHexString(final byte[] pdf, + final int index) + { + HexStringParseResult hspr = new HexStringParseResult(); + hspr.start_index = index; + + assert pdf[hspr.start_index] == PDFNames.DELIMITER_HEXSTRING_OPEN; + + hspr.content_start_index = hspr.start_index + 1; + + int cur_index = hspr.content_start_index; + while (isHex(pdf[cur_index]) || isWhitespace(pdf[cur_index])) + { + cur_index++; + } + + hspr.content_end_index = cur_index; + assert pdf[hspr.content_end_index] == PDFNames.DELIMITER_HEXSTRING_CLOSE; + + hspr.next_index = hspr.content_end_index + 1; + + return hspr; + } + + public static ArrayParseResult parseArray(final byte[] pdf, final int index) + { + ArrayParseResult apr = new ArrayParseResult(); + apr.start_index = index; + assert pdf[apr.start_index] == PDFNames.DELIMITER_ARRAY_OPEN; + + apr.content_start_index = apr.start_index + 1; + + apr.elements = new ArrayList(); + + int cur_index = skipWhitespace(pdf, apr.content_start_index); + for (;;) + { + if (pdf[cur_index] == PDFNames.DELIMITER_ARRAY_CLOSE) + { + break; + } + + ParseResult pr = parseUnknownObject(pdf, cur_index); + apr.elements.add(pr); + + cur_index = skipWhitespace(pdf, pr.next_index); + } + assert pdf[cur_index] == PDFNames.DELIMITER_ARRAY_CLOSE; + + apr.content_end_index = cur_index; + assert pdf[apr.content_end_index] == PDFNames.DELIMITER_ARRAY_CLOSE; + + apr.next_index = apr.content_end_index + 1; + return apr; + } + + /** + * Parses a PDF Name. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of this parsing operation. + */ + public static NameParseResult parseName(final byte[] pdf, final int index) + { + NameParseResult npr = new NameParseResult(); + npr.start_index = index; + + assert pdf[npr.start_index] == PDFNames.DELIMITER_NAME; + + npr.name_start_index = npr.start_index + 1; + + assert isRegular(pdf[npr.name_start_index]); + + int cur_index = npr.name_start_index; + while (isRegular(pdf[cur_index])) + { + cur_index++; + } + assert !isRegular(pdf[cur_index]); + + npr.next_index = cur_index; + + return npr; + } + + public static DictionaryParseResult parseDictionary(final byte[] pdf, + final int index) + { + DictionaryParseResult dpr = new DictionaryParseResult(); + dpr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.DICT_START_STR); + + dpr.content_start_index = dpr.start_index + PDFNames.DICT_START_STR.length; + + dpr.names = new ArrayList(); + dpr.values = new ArrayList(); + + int cur_index = skipWhitespace(pdf, dpr.content_start_index); + for (;;) + { + if (ByteArrayUtils.compareByteArrays(pdf, cur_index, PDFNames.DICT_END_STR)) + { + break; + } + + NameParseResult npr = parseName(pdf, cur_index); + dpr.names.add(npr); + + cur_index = npr.next_index; + cur_index = skipWhitespace(pdf, cur_index); + + ParseResult pr = parseUnknownObject(pdf, cur_index); + dpr.values.add(pr); + + cur_index = pr.next_index; + cur_index = skipWhitespace(pdf, cur_index); + } + + dpr.content_end_index = cur_index; + assert ByteArrayUtils.compareByteArrays(pdf, dpr.content_end_index, PDFNames.DICT_END_STR); + dpr.next_index = dpr.content_end_index + PDFNames.DICT_END_STR.length; + + return dpr; + } + + /** + * Parses a stream. + * + * @param pdf + * The PDF data. + * @param index + * The index. + * @param dpr + * The DictionaryParseResult of the stream's dictionary. This + * dictionary must precede the stream keyword. Usually this is + * provided in the stream object's dictionary via the /Length field. + * @return Returns the result of this parsing operation. + */ + public static StreamParseResult parseStream(final byte[] pdf, + final int index, final DictionaryParseResult dpr) + { + StreamParseResult spr = new StreamParseResult(); + spr.stream_dictionary = dpr; + spr.start_index = spr.stream_dictionary.start_index; + spr.stream_start_index = index; + assert ByteArrayUtils.compareByteArrays(pdf, index, PDFNames.STREAM_STR); + + // assert that the provided dictionary really belongs to this stream + assert spr.stream_start_index == skipWhitespace(pdf, spr.stream_dictionary.next_index); + + // see PDF Spec 1.4 chapter 3.2.7 + assert pdf[spr.stream_start_index + PDFNames.STREAM_STR.length] == PDFNames.WHITESPACE_LF || (pdf[spr.stream_start_index + PDFNames.STREAM_STR.length] == PDFNames.WHITESPACE_CR && pdf[spr.stream_start_index + PDFNames.STREAM_STR.length + 1] == PDFNames.WHITESPACE_LF); + spr.content_start_index = skipNewline(pdf, spr.stream_start_index + PDFNames.STREAM_STR.length); + + int length = -1; + for (int i = 0; i < spr.stream_dictionary.names.size(); i++) + { + NameParseResult name = (NameParseResult) spr.stream_dictionary.names.get(i); + if (ByteArrayUtils.compareByteArrays(pdf, name.name_start_index, PDFNames.LENGTH_STR)) + { + ParseResult pr = (ParseResult) spr.stream_dictionary.values.get(i); + NumberParseResult npr = null; + if (pr instanceof IndirectObjectReferenceParseResult) + { + log.debug("An object stream with indirect length - cannot parse this instantly - parse later again."); + spr.content_end_index = -1; + spr.next_index = -1; + return spr; + + } + else + { + npr = (NumberParseResult) pr; + } + assert npr != null; + + length = npr.number; + break; + } + + } + assert length >= 0; + + spr.content_end_index = spr.content_start_index + length; + + int endstr_index = spr.content_end_index; + if (isNewline(pdf, endstr_index)) + { + endstr_index = skipWhitespace(pdf, endstr_index); + } + assert ByteArrayUtils.compareByteArrays(pdf, endstr_index, PDFNames.ENDSTREAM_STR); + + spr.next_index = endstr_index + PDFNames.ENDSTREAM_STR.length; + + return spr; + } + + public static NullParseResult parseNull(final byte[] pdf, final int index) + { + NullParseResult npr = new NullParseResult(); + npr.start_index = index; + + assert ByteArrayUtils.compareByteArrays(pdf, npr.start_index, PDFNames.NULL_STR); + + npr.next_index = npr.start_index + PDFNames.NULL_STR.length; + + return npr; + } + + public static int getObjectOffsetFromXRefByIndirectObjectReference( + XRefSectionParseResult xpr, IndirectObjectReference ior) + { + Iterator it = xpr.xref_subsections.iterator(); + while (it.hasNext()) + { + XRefSubSectionParseResult section = (XRefSubSectionParseResult) it.next(); + + for (int i = 0; i < section.xref_lines.size(); i++) + { + if (section.start_obj_number + i == ior.object_number) + { + XRefLineParseResult lpr = (XRefLineParseResult) section.xref_lines.get(i); + return lpr.object_offset; + } + } + } + + return -1; + } + + public static HeaderParseResult parseHeader(final byte[] pdf, final int index) + { + HeaderParseResult hpr = new HeaderParseResult(); + hpr.start_index = index; + + assert pdf[hpr.start_index] == PDFNames.COMMENT; + + assert ByteArrayUtils.compareByteArrays(pdf, hpr.start_index + 1, PDFNames.PDF_VERSION_STR); + + hpr.major_index = hpr.start_index + 1 + PDFNames.PDF_VERSION_STR.length; + + IntegerParseResult major_ipr = parseUnsignedInteger(pdf, hpr.major_index); + hpr.major = major_ipr.number; + assert hpr.major >= 1; + + assert pdf[major_ipr.next_index] == PDFNames.PDF_VERSION_SEPARATOR; + + hpr.minor_index = major_ipr.next_index + 1; + + IntegerParseResult minor_ipr = parseUnsignedInteger(pdf, hpr.minor_index); + hpr.minor = minor_ipr.number; + assert hpr.minor >= 0; + + assert isWhitespace(pdf[minor_ipr.next_index]); + hpr.binary_characters_index = skipWhitespace(pdf, minor_ipr.next_index); + + assert pdf[hpr.binary_characters_index] == PDFNames.COMMENT; + + hpr.next_index = skipToNewline(pdf, hpr.binary_characters_index); + return hpr; + } + + /** + * Parses a PDF footer. + * + *

+ * A PDF footer starts with the xref, followed by the trailer, the startxref + * and the EOF marker. + *

+ * + * @param pdf + * The PDF data. + * @param index + * The index. + * @return Returns the result of the parsing operation. + * + * @see FooterParseResult + */ + public static FooterParseResult parseFooter(final byte[] pdf, final int index) + { + FooterParseResult fpr = new FooterParseResult(); + fpr.start_index = index; + + fpr.xpr = PDFUtils.parseXRefSection(pdf, fpr.start_index); + + fpr.tpr = PDFUtils.parseTrailer(pdf, fpr.xpr.next_index); + + fpr.sxpr = PDFUtils.parseStartXRef(pdf, fpr.tpr.next_index); + + fpr.eofpr = PDFUtils.parseEOF(pdf, fpr.sxpr.next_index); + + fpr.next_index = fpr.eofpr.next_index; + return fpr; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java new file mode 100644 index 0000000..9d0a745 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ArrayParseResult.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ArrayParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.List; + +/** + * The result of parsing a hex string. + * + * @see at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult + * + * @author wprinz + */ +public class ArrayParseResult extends ContainerParseResult { + + public List elements = null; + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java new file mode 100644 index 0000000..e0bc276 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/BooleanParseResult.java @@ -0,0 +1,38 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: BooleanParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * Parse result of parsing a boolean value. + * + * @author wprinz + */ +public class BooleanParseResult extends ParseResult +{ + + public boolean value = false; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java new file mode 100644 index 0000000..1974ade --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ContainerParseResult.java @@ -0,0 +1,45 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ContainerParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * Base class of container parse results. + * + *

+ * Containers are types that include some content. + * E.g. literal strings include string data as content, + * arrays include elements as content etc. + *

+ * + * @author wprinz + */ +public class ContainerParseResult extends ParseResult { + + public int content_start_index = -1; + public int content_end_index = -1; + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java new file mode 100644 index 0000000..47101e0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/DictionaryParseResult.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: DictionaryParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.List; + +/** + * The result of parsing a dictionary. + * + * @author wprinz + */ +public class DictionaryParseResult extends ContainerParseResult +{ + + public List names = null; + + public List values = null; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java new file mode 100644 index 0000000..dea1d22 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/EOFParseResult.java @@ -0,0 +1,47 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: EOFParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing the End Of File marker. + * + * @author wprinz + */ +public class EOFParseResult extends ParseResult +{ + + /** + * The index of the byte after the EOF marker. + * + *

+ * A newline is not necessary after the EOF marker, but if it is present it will be considered + * as part of it. + * So eof_end_index marks this newline. + * If eof_end_index == next_index, then no new line is present. + *

+ */ + public int eof_end_index = -1; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java new file mode 100644 index 0000000..2a52aa6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/FooterParseResult.java @@ -0,0 +1,53 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: FooterParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The result of parsing a PDF footer block. + * + *

+ * A PDF footer block starts with the xref table followed by the trailer, the + * startxref and finally the EOF marker. Usually the footer should be at the end + * of the file. All object offsets in the footer's xref table should be before + * the footer itself. Nevertheless, there are PDF Writers (e.g. Microsoft Word) + * that put the footer at the beginning of the document so that all indirect + * objects are after the EOF marker. + *

+ * + * @author wprinz + */ +public class FooterParseResult extends ParseResult +{ + + public StartXRefParseResult sxpr = null; + + public EOFParseResult eofpr = null; + + public XRefSectionParseResult xpr = null; + + public TrailerParseResult tpr = null; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java new file mode 100644 index 0000000..3befda3 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HeaderParseResult.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: HeaderParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing the PDF header. + * + *

+ * The header contains the PDF version and is usually followed by some binary + * characers. + *

+ * + * @author wprinz + */ +public class HeaderParseResult extends ParseResult +{ + public int major_index = -1; + public int minor_index = -1; + + public int major = -1; + public int minor = -1; + + public int binary_characters_index = -1; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java new file mode 100644 index 0000000..27dbf70 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/HexStringParseResult.java @@ -0,0 +1,36 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: HexStringParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing a hex string. + * + * @see at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult + * + * @author wprinz + */ +public class HexStringParseResult extends ContainerParseResult { +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java new file mode 100644 index 0000000..797678e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IndirectObjectReferenceParseResult.java @@ -0,0 +1,44 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: IndirectObjectReferenceParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import at.knowcenter.wag.exactparser.parsing.IndirectObjectReference; + +/** + * The ParseResult of parsing an indirect object reference. + * + * @author wprinz + */ +public class IndirectObjectReferenceParseResult extends ParseResult { + + public IndirectObjectReference ior; + + //@Override + public String toString() + { + return ior.toString() + " R"; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java new file mode 100644 index 0000000..48ea7d2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/IntegerParseResult.java @@ -0,0 +1,36 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: IntegerParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * @author wprinz + */ +public class IntegerParseResult extends ParseResult +{ + + public int number; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java new file mode 100644 index 0000000..60fc277 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/LiteralStringParseResult.java @@ -0,0 +1,37 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: LiteralStringParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing a simple string (ASCII string). + * + * @see at.knowcenter.wag.exactparser.parsing.results.HexStringParseResult + * + * @author wprinz + */ +public class LiteralStringParseResult extends ContainerParseResult { + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java new file mode 100644 index 0000000..e564285 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NameParseResult.java @@ -0,0 +1,35 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: NameParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * @author wprinz + */ +public class NameParseResult extends ParseResult { + + public int name_start_index = -1; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java new file mode 100644 index 0000000..49d9dfb --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NullParseResult.java @@ -0,0 +1,34 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: NullParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The result of parsing a "null". + * + * @author wprinz + */ +public class NullParseResult extends ParseResult { +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java new file mode 100644 index 0000000..e88596c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/NumberParseResult.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: NumberParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of parsing an integer number. + * + * @author wprinz + */ +public class NumberParseResult extends ParseResult { + /** + * The (signed) integer number. + */ + public int number; + + // TODO: make better + public float floating; +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java new file mode 100644 index 0000000..0729108 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectHeaderParseResult.java @@ -0,0 +1,51 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ObjectHeaderParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of a parsing an object header. + * + *

+ * Note that this information regards only the object header and not the + * contents of the object itself. (meaning: next points to the contents and not + * to the end of the whole object) + *

+ * + * @author Administrator + */ +public class ObjectHeaderParseResult extends ParseResult { + + /** + * The object's object number. + */ + public int object_number = -1; + + /** + * The object's generation number. + */ + public int generation_number = -1; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java new file mode 100644 index 0000000..2fdde34 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ObjectParseResult.java @@ -0,0 +1,50 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ObjectParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The ParseResult of parsing an indirect object. + * @author wprinz + */ +public class ObjectParseResult extends ParseResult { + + public int content_index = -1; + public int end_of_content_index = -1; + + public ObjectHeaderParseResult header = null; + +/* enum ObjectType + { + UNKNOWN_TO_PARSER, + OBJ_DICTIONARY + }; + + public ObjectType object_type = ObjectType.UNKNOWN_TO_PARSER; + */ + public ParseResult object = null; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java new file mode 100644 index 0000000..12c4b19 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/ParseResult.java @@ -0,0 +1,50 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: ParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * Base class of all parse results. + * + * @author wprinz + */ +public class ParseResult { + + /** + * The start index, where the parser started its work and where the parsed + * entity begins. + */ + public int start_index = -1; + + /** + * The index of the next entity following the currently parsed entity. + * + *

+ * This is the index of the first byte not belonging to this entity anymore. + *

+ */ + public int next_index = -1; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java new file mode 100644 index 0000000..a1f6792 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StartXRefParseResult.java @@ -0,0 +1,36 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: StartXRefParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The ParseResult of parsing a startxref entry. + * @author wprinz + */ +public class StartXRefParseResult extends ParseResult { + + public int xref_index; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java new file mode 100644 index 0000000..16da12a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/StreamParseResult.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: StreamParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + + +/** + * The result of parsing a hex string. + * + * @see at.knowcenter.wag.exactparser.parsing.results.LiteralStringParseResult + * + * @author wprinz + */ +public class StreamParseResult extends ContainerParseResult { + + public DictionaryParseResult stream_dictionary = null; + + public int stream_start_index = -1; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java new file mode 100644 index 0000000..4589ee8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/TrailerParseResult.java @@ -0,0 +1,84 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: TrailerParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of parsing the trailer. + * + * @author wprinz + */ +public class TrailerParseResult extends ParseResult { + + public int contents_index = -1; + public int contents_end_index = -1; + + public DictionaryParseResult dpr = null; + + public IndirectObjectReferenceParseResult info; + + public IndirectObjectReferenceParseResult root; + + /** + * The content of the "/Size" entry. + */ + public int size; + + /** + * Tells, if this PDF footer has a predecessor (as specified by + * the /Prev entry). + */ + public boolean has_predecessor = false; + + /** + * The index of the predecessor. + * + *

+ * Only valid if has_predecessor is true. + *

+ *

+ * Use getPrev and setPrev to access this member variable. + *

+ * + * @see #getPrev() + * @see #setPrev(int) + */ + private int prev = -1; + + public int getPrev() { + assert has_predecessor; + return prev; + } + + public void setPrev(int prev) { + assert has_predecessor : "Set has_predecessor to true first."; + this.prev = prev; + } + + + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java new file mode 100644 index 0000000..8039153 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefLineParseResult.java @@ -0,0 +1,40 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: XRefLineParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +/** + * The ParseResult of parsing a single xref line. + * + * @author wprinz + */ +public class XRefLineParseResult extends ParseResult { + + public int object_offset; + + public int generation_number; + + public byte object_usage; +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java new file mode 100644 index 0000000..eedea81 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSectionParseResult.java @@ -0,0 +1,66 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: XRefSectionParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.ArrayList; +import java.util.List; + +/** + * The ParseResult of an xref parsing operation. + * + *

+ * This contains one whole xref table section. An xref section starts with the + * word xref and contains one or more xref sub-sections. + *

+ *

+ * Due to Incremental Updates, there may be more than one xref section in a + * document. All xref section together are called the xref table. Using this + * aggregated xref table, an application has the full access to all indirect + * objects in the document. + *

+ *

+ * In many PDF libraries and applications one xref section is also informally + * called xref table. + *

+ * + * @author wprinz + */ +public class XRefSectionParseResult extends ParseResult +{ + + public List xref_subsections = new ArrayList(); + + /** + * Appends another cross-reference (xref) sub-section to the xref table. + * + * @param xref_section + * The xref section to be appended. + */ + public void appendXRefSubSection(XRefSubSectionParseResult xref_section) + { + xref_subsections.add(xref_section); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java new file mode 100644 index 0000000..ec19004 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/exactparser/parsing/results/XRefSubSectionParseResult.java @@ -0,0 +1,59 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: XRefSubSectionParseResult.java,v 1.1 2006/08/25 17:00:59 wprinz Exp $ + */ +package at.knowcenter.wag.exactparser.parsing.results; + +import java.util.ArrayList; +import java.util.List; + +/** + * Contains an xref sub-section. + * + *

+ * An xref sub-section is an ordered list of xref lines. The object numbers of the + * corresponding objects are numbered incrementally. + *

+ *

+ * xref sections are important in Incremental Updates because they allow to + * specify explicitely which objects (object numbers) are contained in the xref. + *

+ * + * @author wprinz + */ +public class XRefSubSectionParseResult extends ParseResult { + + public int start_obj_number; + + public int num_objects; + + public List xref_lines = new ArrayList(); + + public void appendXRefLine(XRefLineParseResult xref_line) { + assert xref_lines.size() < num_objects; + + xref_lines.add(xref_line); + } + +} -- cgit v1.2.3