/** * Copyright 2006 by Know-Center, Graz, Austria * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a * joint initiative of the Federal Chancellery Austria and Graz University of * Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "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 demo; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.Iterator; import java.util.List; import at.gv.egiz.pdfas.PdfAsFactory; 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.analyze.NonTextObjectInfo; 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.io.DataSource; import at.gv.egiz.pdfas.api.verify.VerifyAfterAnalysisParameters; import at.gv.egiz.pdfas.api.verify.VerifyAfterReconstructXMLDsigParameters; 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.ReconstructXMLDsigResult; import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; import at.gv.egiz.pdfas.commandline.Main; 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.FileBasedDataSource; public class SignatureVerificationDemo { /** * Starts a demo that verifies a document. * * @param args * The parameter(s). */ public static void main(String[] args) { if (args == null || args.length == 0) { System.err.println("Please provide path of file to be verified."); System.exit(1); } File configdir = new File("./work"); File signedFile = new File(args[0]); AnalyzeResult analyzeResult = null; try { // instantiate api PdfAs pdfasAPI = PdfAsFactory.createPdfAs(configdir); // set source DataSource dataSource = new FileBasedDataSource(signedFile, "application/pdf"); // evaluate settings VerificationFilterParameters parameters = SettingsHelper.readVerificationFilterParametersFromSettings(); String verifyMode = Constants.VERIFY_MODE_FULL_CONSERVATIVE; 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; } // configure analyze parameters AnalyzeParameters analyzeParameters = new AnalyzeParameters(); analyzeParameters.setDocument(dataSource); analyzeParameters.setVerifyMode(verifyMode); analyzeParameters.setReturnNonTextualObjects(true); // analyze System.out.println("Analyzing..."); analyzeResult = pdfasAPI.analyze(analyzeParameters); System.out.println("Successfully analyzed."); // information on non-textual objects can be used after analysis step and/or after verification List signatures = analyzeResult.getSignatures(); if (signatures != null && !signatures.isEmpty()) { int counter = 0; Iterator sigIterator = signatures.iterator(); while (sigIterator.hasNext()) { counter++; SignatureInformation sigInfo = (SignatureInformation) sigIterator.next(); System.out.println("\n------------------------ SIGNATURE #" + counter + " ------------------------"); if (sigInfo.hasNonTextualObjects()) { System.out.println("\nWARNING: " + sigInfo.getNonTextualObjects().size() + " non textual object(s) detected for this signature."); Iterator noit = sigInfo.getNonTextualObjects().iterator(); while (noit.hasNext()) { NonTextObjectInfo info = (NonTextObjectInfo) noit.next(); System.out.println(" -> " + info.toString()); } System.out.println(); } else { System.out.println("\nNo non-textual objects detected for this signature."); } } } else { if (analyzeResult != null && analyzeResult.hasBeenCorrected()) { System.err.println("The document could not been processed, maybe due to modification by third party tools. An attempt to correct the document was successful but no verifiable signatures could be found. This/these signature(s) - if any - might got lost."); } else { System.err.println("No signatures found."); } System.exit(1); } // retrieve reconstructed signature ReconstructXMLDsigAfterAnalysisParameters recstrParams = new ReconstructXMLDsigAfterAnalysisParameters(); recstrParams.setAnalyzeResult(analyzeResult); recstrParams.setSignatureDevice(Constants.SIGNATURE_DEVICE_MOA); ReconstructXMLDsigResult recstrResult = pdfasAPI.reconstructXMLDSIG(recstrParams); // it is now possible to retrieve the reconstructed XMLDSig and the underlying signed // data without invoking signature verification. Just enable the following block /* List extSigInfoList = recstrResult.getExtendedSignatures(); if (extSigInfoList != null && !extSigInfoList.isEmpty()) { Iterator it = extSigInfoList.iterator(); while (it.hasNext()) { ExtendedSignatureInformation extSigInfo = (ExtendedSignatureInformation) it.next(); SignatureInformation sigInfo = extSigInfo.getSignatureInformation(); XMLDsigData xmlDSigData = extSigInfo.getXmlDsigData(); // output XMLDSIG somewhere: xmlDSigData.getXmlDsig() if (xmlDSigData.isDetached()) { DataSource signedDataSource = sigInfo.getSignedData(); // output signed data somewhere: signedDataSource.getAsByteArray() } } } */ // setup verification // verification without intermediate step of reconstruction /* VerifyAfterAnalysisParameters vaap = new VerifyAfterAnalysisParameters(); vaap.setAnalyzeResult(analyzeResult); vaap.setReturnHashInputData(true); vaap.setSignatureDevice(Constants.SIGNATURE_DEVICE_MOA); vaap.setVerificationTime(null); // try to validate all signatures (do not throw exceptions while validating single signatures) // use result.isVerificationDone() in order to find out if a signatures was successfully verified vaap.setSuppressVerifyExceptions(true); */ // verification with intermediate step of reconstruction VerifyAfterReconstructXMLDsigParameters varp = new VerifyAfterReconstructXMLDsigParameters(); varp.setReconstructXMLDsigResult(recstrResult); varp.setReturnHashInputData(true); // not needed since already set in recstrParams (the reconstruction step) // varp.setSignatureDevice(Constants.SIGNATURE_DEVICE_MOA); varp.setVerificationTime(null); // try to validate all signatures (do not throw exceptions while validating single signatures) // use result.isVerificationDone() in order to find out if a signatures was successfully verified varp.setSuppressVerifyExceptions(true); // invoke verification System.out.println("Verifying..."); // without intermediate step of reconstruction /* VerifyResults verifyResults = pdfasAPI.verify(vaap); */ // with intermediate step of reconstruction VerifyResults verifyResults = pdfasAPI.verify(varp); // retrieve results List verifyResultList = verifyResults.getResults(); System.out.println("Verification complete.\n"); // iterate over results PrintWriter out = new PrintWriter(System.out); Iterator it = verifyResultList.iterator(); int counter = 0; while (it.hasNext()) { counter++; VerifyResult result = (VerifyResult) it.next(); out.println("\n------------------------ SIGNATURE #" + counter + " ------------------------\n"); // check if signature verification of the current signature was successfully completed (independent from result) if (!result.isVerificationDone()) { PdfAsException ex = result.getVerificationException(); out.println(ErrorCodeHelper.formErrorMessage(ex)); continue; } Main.formatVerifyResult(result, out); XMLDsigData xmlDSigData = result.getReconstructedXMLDsig(); if (xmlDSigData != null) { out.println("\n --- XMLDSIG start ---"); out.println(" " + xmlDSigData.getXmlDsig()); out.println(" --- XMLDSIG end ---"); // fetch data // either use result.getHashInputData() (provided varp.setReturnHashInputData(...) has been set true // or use byte[] data = result.getSignedData().getAsByteArray(); out.println("\n Signed Data: " + data.length + " bytes (" + result.getSignatureType() + ")"); } // check if there are timestamps if (result.getTimeStampValue() != null) { out.println("\n TimeStamp value available for this signature"); } // check if non textual elements have been detected for this signature if (result.hasNonTextualObjects()) { out.println("\n WARNING: " + result.getNonTextualObjects().size() + " non textual object(s) detected for this signature"); Iterator noit = result.getNonTextualObjects().iterator(); while (noit.hasNext()) { NonTextObjectInfo info = (NonTextObjectInfo) noit.next(); out.println(" -> " + info.toString()); } out.println(); } else { out.println("\n No non-textual objects detected for this signature."); } } out.flush(); } catch (PdfAsException e) { if (ErrorCode.DOCUMENT_NOT_SIGNED == e.getErrorCode() && analyzeResult != null && analyzeResult.hasBeenCorrected()) { System.err.println("\nThe document could not been processed, maybe due to modification by third party tools. An attempt to correct the document was successful but no verifiable signatures could be found. This/these signature(s) - if any - might got lost."); } else { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } }