diff options
11 files changed, 454 insertions, 262 deletions
diff --git a/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java b/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java index eee47888..e36883ab 100644 --- a/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java +++ b/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java @@ -49,6 +49,7 @@ import at.gv.egiz.pdfas.lib.api.sign.IPlainSigner; import at.gv.egiz.pdfas.lib.api.sign.SignParameter; import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter; import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; +import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter.SignatureVerificationLevel; import at.gv.egiz.pdfas.sigs.pades.PAdESSigner; import at.gv.egiz.pdfas.sigs.pades.PAdESSignerKeystore; import at.gv.egiz.sl.util.BKUSLConnector; @@ -82,6 +83,11 @@ public class Main { public static final String CLI_ARG_VERIFY_WHICH_SHORT = "vw"; public static final String CLI_ARG_VERIFY_WHICH = "verify_which"; + + public static final String CLI_ARG_VERIFY_LEVEL_SHORT = "vl"; + public static final String CLI_ARG_VERIFY_LEVEL = "verify_level"; + public static final String CLI_ARG_VERIFY_LEVEL_OPTION_FULL = "full"; + public static final String CLI_ARG_VERIFY_LEVEL_OPTION_INT_ONLY = "intOnly"; public static final String CLI_ARG_KEYSTORE_FILE_SHORT = "ksf"; public static final String CLI_ARG_KEYSTORE_FILE = "ks_file"; @@ -169,6 +175,13 @@ public class Main { true, "[optional] zero based number of the signature to be verified. If omitted, all signatures are verified."); cliOptions.addOption(verifywhichOption); + + Option verifyLevelOption = new Option( + CLI_ARG_VERIFY_LEVEL_SHORT, + CLI_ARG_VERIFY_LEVEL, + true, + "[optional] Verification Level Full certificate verification, or only integrity Verification (" + CLI_ARG_VERIFY_LEVEL_OPTION_FULL + " | " + CLI_ARG_VERIFY_LEVEL_OPTION_INT_ONLY + ")"); + cliOptions.addOption(verifyLevelOption); Option outputOption = new Option(CLI_ARG_OUTPUT_SHORT, CLI_ARG_OUTPUT, true, "The output file"); @@ -423,6 +436,22 @@ public class Main { String whichValue = cli.getOptionValue(CLI_ARG_VERIFY_WHICH_SHORT); which = Integer.parseInt(whichValue); } + + SignatureVerificationLevel lvl = SignatureVerificationLevel.FULL_VERIFICATION; + + if (cli.hasOption(CLI_ARG_VERIFY_LEVEL_SHORT)) { + String levelValue = cli.getOptionValue(CLI_ARG_VERIFY_LEVEL_SHORT); + if(levelValue.equals(CLI_ARG_VERIFY_LEVEL_OPTION_FULL)) { + lvl = SignatureVerificationLevel.FULL_VERIFICATION; + } else if(levelValue.equals(CLI_ARG_VERIFY_LEVEL_OPTION_INT_ONLY)) { + lvl = SignatureVerificationLevel.INTEGRITY_ONLY_VERIFICATION; + } else { + System.out.println("Invalid value for verification Level: " + levelValue); + System.out.println("Allowed values are: " + CLI_ARG_VERIFY_LEVEL_OPTION_FULL + + ", " + CLI_ARG_VERIFY_LEVEL_OPTION_INT_ONLY); + throw new Exception("Invalid value for verification Level: " + levelValue); + } + } String confOutputFile = null; @@ -452,7 +481,7 @@ public class Main { VerifyParameter verifyParameter = PdfAsFactory.createVerifyParameter( configuration, dataSource); - + verifyParameter.setSignatureVerificationLevel(lvl); verifyParameter.setDataSource(dataSource); verifyParameter.setConfiguration(configuration); verifyParameter.setWhichSignature(which); diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/verify/VerifyParameter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/verify/VerifyParameter.java index 3523c268..223e3e61 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/verify/VerifyParameter.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/verify/VerifyParameter.java @@ -30,6 +30,25 @@ import at.gv.egiz.pdfas.lib.api.PdfAsParameter; public interface VerifyParameter extends PdfAsParameter { /** + * The signature Verification Level defines what should be verified + */ + public enum SignatureVerificationLevel { + /** + * Only verifies the the Signatures integrity + * + * This option does not perform a verification of the signing Certificate + * and does not requires MOA-SP + */ + INTEGRITY_ONLY_VERIFICATION, + /** + * Uses MOA-SP to verify the Signature and verifies the Certification Path + * + * This is the default value + */ + FULL_VERIFICATION + } + + /** * Gets which signature should be verified * * This is a 0 based index of the signatures @@ -58,4 +77,18 @@ public interface VerifyParameter extends PdfAsParameter { * @param verificationTime */ public void setVerificationTime(Date verificationTime); + + /** + * Sets the verification Level + * + * @param signatureVerificationLevel + */ + public void setSignatureVerificationLevel(SignatureVerificationLevel signatureVerificationLevel); + + /** + * Gets the verification level + * + * @return + */ + public SignatureVerificationLevel getSignatureVerificationLevel(); } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java index 7dcdca2b..40e7faf5 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java @@ -81,6 +81,7 @@ import at.gv.egiz.pdfas.lib.impl.stamping.pdfbox.PdfBoxVisualObject; import at.gv.egiz.pdfas.lib.impl.status.OperationStatus; import at.gv.egiz.pdfas.lib.impl.status.PDFObject; import at.gv.egiz.pdfas.lib.impl.status.RequestedSignature; +import at.gv.egiz.pdfas.lib.impl.verify.IVerifier; import at.gv.egiz.pdfas.lib.impl.verify.IVerifyFilter; import at.gv.egiz.pdfas.lib.impl.verify.VerifierDispatcher; import at.gv.egiz.pdfas.lib.util.SignatureUtils; @@ -281,11 +282,13 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants { dict.getNameAsString("Filter"), dict.getNameAsString("SubFilter")); + IVerifier lvlVerifier = verifier.getVerifierByLevel(parameter.getSignatureVerificationLevel()); + lvlVerifier.setConfiguration(parameter.getConfiguration()); if (verifyFilter != null) { List<VerifyResult> results = verifyFilter.verify( contentData.toByteArray(), content.getBytes(), - parameter.getVerificationTime(), bytes); + parameter.getVerificationTime(), bytes, lvlVerifier); if (results != null && !results.isEmpty()) { result.addAll(results); } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/VerifyParameterImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/VerifyParameterImpl.java index b7b81761..166c17e0 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/VerifyParameterImpl.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/VerifyParameterImpl.java @@ -35,6 +35,9 @@ public class VerifyParameterImpl extends PdfAsParameterImpl implements VerifyPar protected Date verificationTime = null; + protected SignatureVerificationLevel signatureVerificationLevel = + SignatureVerificationLevel.FULL_VERIFICATION; + public VerifyParameterImpl(Configuration configuration, DataSource dataSource) { super(configuration, dataSource); @@ -55,4 +58,13 @@ public class VerifyParameterImpl extends PdfAsParameterImpl implements VerifyPar public void setVerificationTime(Date verificationTime) { this.verificationTime = verificationTime; } + + public void setSignatureVerificationLevel( + SignatureVerificationLevel signatureVerificationLevel) { + this.signatureVerificationLevel = signatureVerificationLevel; + } + + public SignatureVerificationLevel getSignatureVerificationLevel() { + return this.signatureVerificationLevel; + } } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/FullVerifier.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/FullVerifier.java new file mode 100644 index 00000000..7b40707c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/FullVerifier.java @@ -0,0 +1,211 @@ +package at.gv.egiz.pdfas.lib.impl.verify; + +import iaik.x509.X509Certificate; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import javax.activation.DataHandler; +import javax.xml.bind.JAXBElement; + +import org.apache.axis2.databinding.types.Token; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.dsig.X509DataType; +import at.gv.egiz.dsig.util.DsigMarschaller; +import at.gv.egiz.moa.ByteArrayDataSource; +import at.gv.egiz.moa.SignatureVerificationServiceStub; +import at.gv.egiz.moa.SignatureVerificationServiceStub.CMSContentBaseType; +import at.gv.egiz.moa.SignatureVerificationServiceStub.CMSDataObjectOptionalMetaType; +import at.gv.egiz.moa.SignatureVerificationServiceStub.KeyInfoTypeChoice; +import at.gv.egiz.moa.SignatureVerificationServiceStub.VerifyCMSSignatureRequest; +import at.gv.egiz.moa.SignatureVerificationServiceStub.VerifyCMSSignatureResponse; +import at.gv.egiz.moa.SignatureVerificationServiceStub.VerifyCMSSignatureResponseTypeSequence; +import at.gv.egiz.moa.SignatureVerificationServiceStub.X509DataTypeSequence; +import at.gv.egiz.pdfas.common.exceptions.PdfAsException; +import at.gv.egiz.pdfas.common.messages.CodesResolver; +import at.gv.egiz.pdfas.common.utils.StreamUtils; +import at.gv.egiz.pdfas.lib.api.Configuration; +import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; + +public class FullVerifier implements IVerifier { + + private static final Logger logger = LoggerFactory + .getLogger(FullVerifier.class); + + private static final String MOA_VERIFY_URL = "moa.verify.url"; + private static final String MOA_VERIFY_TRUSTPROFILE = "moa.verify.TrustProfileID"; + + private String moaEndpoint; + private String moaTrustProfile; + + + public List<VerifyResult> verify(byte[] signature, byte[] signatureContent, + Date verificationTime) throws PdfAsException { + List<VerifyResult> resultList = new ArrayList<VerifyResult>(); + try { + logger.info("verification with MOA @ " + this.moaEndpoint); + + SignatureVerificationServiceStub service = new SignatureVerificationServiceStub( + this.moaEndpoint); + VerifyCMSSignatureRequest verifyCMSSignatureRequest = new VerifyCMSSignatureRequest(); + Token token = new Token(); + token.setValue(this.moaTrustProfile); + verifyCMSSignatureRequest.setTrustProfileID(token); + + CMSDataObjectOptionalMetaType cmsDataObjectOptionalMetaType = new CMSDataObjectOptionalMetaType(); + CMSContentBaseType cmsDataContent = new CMSContentBaseType(); + cmsDataContent.setBase64Content(new DataHandler( + new ByteArrayDataSource(signatureContent, "application/pdf"))); + DataHandler cmsSignature = new DataHandler(new ByteArrayDataSource( + signature, "application/pdf")); + cmsDataObjectOptionalMetaType.setContent(cmsDataContent); + verifyCMSSignatureRequest.setCMSSignature(cmsSignature); + verifyCMSSignatureRequest + .setDataObject(cmsDataObjectOptionalMetaType); + if (verificationTime != null) { + Calendar cal = Calendar.getInstance(); + cal.setTime(verificationTime); + verifyCMSSignatureRequest.setDateTime(cal); + } + // cmsDataObjectOptionalMetaType. + VerifyCMSSignatureResponse response = service + .verifyCMSSignature(verifyCMSSignatureRequest); + + logger.debug("Got Verify Response from MOA"); + + VerifyCMSSignatureResponseTypeSequence[] verifySequence = response + .getVerifyCMSSignatureResponse() + .getVerifyCMSSignatureResponseTypeSequence(); + for (int i = 0; i < verifySequence.length; i++) { + VerifyResultImpl result = new VerifyResultImpl(); + logger.debug(" ---------------------- "); + logger.debug("Signature: " + i); + + SignatureCheckImpl certificateCheck; + + verifySequence[i].getSignerInfo().getKeyInfoTypeChoice()[0] + .getExtraElement(); + if (verifySequence[i].getCertificateCheck() != null) { + certificateCheck = new SignatureCheckImpl(verifySequence[i] + .getCertificateCheck().getCode().intValue(), + verifySequence[i].getCertificateCheck() + .isInfoSpecified() ? verifySequence[i] + .getCertificateCheck().getInfo().toString() + : ""); + } else { + certificateCheck = new SignatureCheckImpl( + 1, + ""); + } + + if(certificateCheck.getMessage() == null || certificateCheck.getMessage().trim().length() == 0) { + String resourceString = "verify.cert." + certificateCheck.getCode(); + String message = CodesResolver.resolveMessage(resourceString); + certificateCheck.setMessage(message); + } + + logger.debug("Certificate Check: " + certificateCheck.getCode() + " [" + certificateCheck.getMessage() + "]"); + + SignatureCheckImpl signatureCheck = new SignatureCheckImpl( + verifySequence[i].getSignatureCheck().getCode() + .intValue(), + verifySequence[i].getSignatureCheck().isInfoSpecified() ? verifySequence[i] + .getSignatureCheck().getInfo().toString() + : ""); + + if(signatureCheck.getMessage() == null || signatureCheck.getMessage().trim().length() == 0) { + String resourceString = "verify.value." + signatureCheck.getCode(); + String message = CodesResolver.resolveMessage(resourceString); + signatureCheck.setMessage(message); + } + + logger.debug("Signature Check: " + signatureCheck.getCode() + " [" + signatureCheck.getMessage() + "]"); + + result.setCertificateCheck(certificateCheck); + result.setValueCheckCode(signatureCheck); + result.setVerificationDone(true); + + KeyInfoTypeChoice[] keyInfo = verifySequence[i].getSignerInfo() + .getKeyInfoTypeChoice(); + KeyInfoTypeChoice choice = keyInfo[0]; + + // extract certificate + if (choice.isX509DataSpecified()) { + byte[] certData = null; + X509DataTypeSequence[] x509Sequence = choice.getX509Data() + .getX509DataTypeSequence(); + for (int k = 0; k < x509Sequence.length; k++) { + X509DataTypeSequence x509Data = x509Sequence[k]; + if (x509Data.getX509DataTypeChoice_type0() + .isX509CertificateSpecified()) { + DataHandler handler = x509Data + .getX509DataTypeChoice_type0() + .getX509Certificate(); + certData = StreamUtils + .inputStreamToByteArray(handler + .getInputStream()); + } else if (x509Data.getX509DataTypeChoice_type0() + .isExtraElementSpecified()) { + if (x509Data + .getX509DataTypeChoice_type0() + .getExtraElement() + .getLocalName() + .equals(SignatureVerificationServiceStub.QualifiedCertificate.MY_QNAME + .getLocalPart())) { + result.setQualifiedCertificate(true); + } + } + } + X509Certificate certificate = new X509Certificate(certData); + result.setSignerCertificate(certificate); + } else if (choice.isExtraElementSpecified()) { + String xmldisg = choice.getExtraElement().toString(); + JAXBElement jaxbElement = (JAXBElement) DsigMarschaller + .unmarshalFromString(xmldisg); + if (jaxbElement.getValue() instanceof X509DataType) { + X509DataType x509Data = (X509DataType) jaxbElement + .getValue(); + List<Object> dsigElements = x509Data + .getX509IssuerSerialOrX509SKIOrX509SubjectName(); + for (int j = 0; j < dsigElements.size(); j++) { + Object jaxElement = dsigElements.get(j); + if (jaxElement instanceof JAXBElement) { + JAXBElement jaxbElementMember = (JAXBElement) jaxElement; + if (jaxbElementMember + .getName() + .equals(DsigMarschaller.X509DataTypeX509Certificate_QNAME)) { + if (jaxbElementMember.getValue() instanceof byte[]) { + byte[] certData = (byte[]) jaxbElementMember + .getValue(); + X509Certificate certificate = new X509Certificate( + certData); + result.setSignerCertificate(certificate); + break; + } + } + } + } + } + } + + resultList.add(result); + + logger.debug(" ---------------------- "); + } + } catch (Throwable e) { + logger.error("Verification failed", e); + throw new PdfAsException("error.pdf.verify.02", e); + } + return resultList; + } + + public void setConfiguration(Configuration config) { + this.moaEndpoint = config.getValue(MOA_VERIFY_URL); + this.moaTrustProfile = config.getValue(MOA_VERIFY_TRUSTPROFILE); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifier.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifier.java new file mode 100644 index 00000000..7badb9be --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifier.java @@ -0,0 +1,15 @@ +package at.gv.egiz.pdfas.lib.impl.verify; + +import java.util.Date; +import java.util.List; + +import at.gv.egiz.pdfas.common.exceptions.PdfAsException; +import at.gv.egiz.pdfas.lib.api.Configuration; +import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; + +public interface IVerifier { + public List<VerifyResult> verify(byte[] signature, + byte[] signatureContent, Date verificationTime) throws PdfAsException; + + public void setConfiguration(Configuration config); +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java index 6f6a58b0..1bc56162 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java @@ -32,6 +32,8 @@ import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; public interface IVerifyFilter { public void setConfiguration(Configuration config); - public List<VerifyResult> verify(byte[] contentData, byte[] signatureContent, Date verificationTime, int[] byteRange) throws PdfAsException; + public List<VerifyResult> verify(byte[] contentData, + byte[] signatureContent, Date verificationTime, + int[] byteRange, IVerifier verifier) throws PdfAsException; public List<FilterEntry> getFiters(); } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IntegrityVerifier.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IntegrityVerifier.java new file mode 100644 index 00000000..01604a6b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IntegrityVerifier.java @@ -0,0 +1,95 @@ +package at.gv.egiz.pdfas.lib.impl.verify; + +import iaik.asn1.ObjectID; +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.ContentInfo; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.x509.X509Certificate; + +import java.io.ByteArrayInputStream; +import java.security.SignatureException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.pdfas.common.exceptions.PdfAsException; +import at.gv.egiz.pdfas.common.exceptions.PdfAsSignatureException; +import at.gv.egiz.pdfas.lib.api.Configuration; +import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; + +public class IntegrityVerifier implements IVerifier { + + private static final Logger logger = LoggerFactory + .getLogger(FullVerifier.class); + + public List<VerifyResult> verify(byte[] signature, byte[] signatureContent, + Date verificationTime) throws PdfAsException { + try { + List<VerifyResult> result = new ArrayList<VerifyResult>(); + + SignedData signedData = new SignedData(signatureContent, new AlgorithmID[] { + AlgorithmID.sha256, AlgorithmID.sha1, AlgorithmID.ripeMd160, AlgorithmID.ripeMd160_ISO + }); + ContentInfo ci = new ContentInfo(new ByteArrayInputStream(signature + )); + if (!ci.getContentType().equals(ObjectID.cms_signedData)) { + throw new PdfAsException("error.pdf.verify.01"); + } + //SignedData signedData = (SignedData)ci.getContent(); + //signedData.setContent(contentData); + + signedData.decode(ci.getContentInputStream()); + + // get the signer infos + SignerInfo[] signerInfos = signedData.getSignerInfos(); + // verify the signatures + for (int i = 0; i < signerInfos.length; i++) { + VerifyResultImpl verifyResult = new VerifyResultImpl(); + try { + // verify the signature for SignerInfo at index i + X509Certificate signer_cert = signedData.verify(i); + logger.info("Signature Algo: {}, Digest {}", + signedData.getSignerInfos()[i].getSignatureAlgorithm(), + signedData.getSignerInfos()[i].getDigestAlgorithm()); + // if the signature is OK the certificate of the + // signer is returned + logger.info("Signature OK from signer: " + + signer_cert.getSubjectDN()); + verifyResult.setSignerCertificate(signer_cert); + verifyResult.setValueCheckCode(new SignatureCheckImpl(0, "OK")); + verifyResult.setManifestCheckCode(new SignatureCheckImpl(99, "not checked")); + verifyResult.setCertificateCheck(new SignatureCheckImpl(99, "not checked")); + verifyResult.setVerificationDone(true); + } catch (SignatureException ex) { + // if the signature is not OK a SignatureException + // is thrown + logger.info("Signature ERROR from signer: " + + signedData.getCertificate( + signerInfos[i].getSignerIdentifier()) + .getSubjectDN(), ex); + + verifyResult.setSignerCertificate( + signedData.getCertificate(signerInfos[i].getSignerIdentifier())); + verifyResult.setValueCheckCode(new SignatureCheckImpl(1, "failed to check signature")); + verifyResult.setManifestCheckCode(new SignatureCheckImpl(99, "not checked")); + verifyResult.setCertificateCheck(new SignatureCheckImpl(99, "not checked")); + verifyResult.setVerificationDone(false); + verifyResult.setVerificationException(new PdfAsSignatureException("failed to check signature", ex)); + } + result.add(verifyResult); + } + + return result; + } catch (Throwable e) { + throw new PdfAsException("error.pdf.verify.02", e); + } + } + + public void setConfiguration(Configuration config) { + + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/VerifierDispatcher.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/VerifierDispatcher.java index 0c37e637..6851865b 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/VerifierDispatcher.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/VerifierDispatcher.java @@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory; import at.gv.egiz.pdfas.common.exceptions.PdfAsException; import at.gv.egiz.pdfas.common.settings.ISettings; import at.gv.egiz.pdfas.lib.api.Configuration; +import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter.SignatureVerificationLevel; public class VerifierDispatcher { @@ -60,7 +61,7 @@ public class VerifierDispatcher { } else { classes = defaultClasses; } - + List<String> filteredClasses = new ArrayList<String>(); for (int i = 0; i < classes.length; i++) { @@ -72,17 +73,17 @@ public class VerifierDispatcher { logger.error("Cannot find Verifier class: " + clsName, e); } } - + String[] clsNames = new String[filteredClasses.size()]; for (int i = 0; i < filteredClasses.size(); i++) { clsNames[i] = filteredClasses.get(i); } - + dumpVerifierClasses(clsNames); - + return clsNames; } - + private void dumpVerifierClasses(String[] clsNames) { for (int i = 0; i < clsNames.length; i++) { String clsName = clsNames[i]; @@ -93,21 +94,18 @@ public class VerifierDispatcher { public VerifierDispatcher(ISettings settings) { // TODO: add configuration parameter to set verifier - //Map<String, String> verifierClasses = settings - // .getValuesPrefix(CONF_VERIFIER); + // Map<String, String> verifierClasses = settings + // .getValuesPrefix(CONF_VERIFIER); String[] currentClasses = null; - //if (verifierClasses == null || verifierClasses.isEmpty()) { + // if (verifierClasses == null || verifierClasses.isEmpty()) { logger.info("Getting Verifier classes"); currentClasses = getClasses(settings); - /*} else { - currentClasses = new String[verifierClasses.values().size()]; - Iterator<String> classIt = verifierClasses.values().iterator(); - int j = 0; - while (classIt.hasNext()) { - currentClasses[j] = classIt.next(); - j++; - } - }*/ + /* + * } else { currentClasses = new + * String[verifierClasses.values().size()]; Iterator<String> classIt = + * verifierClasses.values().iterator(); int j = 0; while + * (classIt.hasNext()) { currentClasses[j] = classIt.next(); j++; } } + */ try { for (int i = 0; i < currentClasses.length; i++) { String clsName = currentClasses[i]; @@ -155,4 +153,13 @@ public class VerifierDispatcher { return filters.get(subfilter); } + + public IVerifier getVerifierByLevel(SignatureVerificationLevel level) { + switch (level) { + case INTEGRITY_ONLY_VERIFICATION: + return new IntegrityVerifier(); + default: + return new FullVerifier(); + } + } } diff --git a/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESVerifier.java b/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESVerifier.java index 2df2368e..d1e185ab 100644 --- a/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESVerifier.java +++ b/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESVerifier.java @@ -23,41 +23,21 @@ ******************************************************************************/ package at.gv.egiz.pdfas.sigs.pades; -import iaik.x509.X509Certificate; - import java.util.ArrayList; -import java.util.Calendar; import java.util.Date; import java.util.List; -import javax.activation.DataHandler; -import javax.xml.bind.JAXBElement; - -import org.apache.axis2.databinding.types.Token; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.dsig.X509DataType; -import at.gv.egiz.dsig.util.DsigMarschaller; -import at.gv.egiz.moa.ByteArrayDataSource; -import at.gv.egiz.moa.SignatureVerificationServiceStub; -import at.gv.egiz.moa.SignatureVerificationServiceStub.CMSContentBaseType; -import at.gv.egiz.moa.SignatureVerificationServiceStub.CMSDataObjectOptionalMetaType; -import at.gv.egiz.moa.SignatureVerificationServiceStub.KeyInfoTypeChoice; -import at.gv.egiz.moa.SignatureVerificationServiceStub.VerifyCMSSignatureRequest; -import at.gv.egiz.moa.SignatureVerificationServiceStub.VerifyCMSSignatureResponse; -import at.gv.egiz.moa.SignatureVerificationServiceStub.VerifyCMSSignatureResponseTypeSequence; -import at.gv.egiz.moa.SignatureVerificationServiceStub.X509DataTypeSequence; import at.gv.egiz.pdfas.common.exceptions.PdfAsException; -import at.gv.egiz.pdfas.common.messages.CodesResolver; import at.gv.egiz.pdfas.common.utils.PDFUtils; -import at.gv.egiz.pdfas.common.utils.StreamUtils; import at.gv.egiz.pdfas.lib.api.Configuration; import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; import at.gv.egiz.pdfas.lib.impl.verify.FilterEntry; +import at.gv.egiz.pdfas.lib.impl.verify.IVerifier; import at.gv.egiz.pdfas.lib.impl.verify.IVerifyFilter; -import at.gv.egiz.pdfas.lib.impl.verify.SignatureCheckImpl; import at.gv.egiz.pdfas.lib.impl.verify.VerifyResultImpl; public class PAdESVerifier implements IVerifyFilter { @@ -76,169 +56,19 @@ public class PAdESVerifier implements IVerifyFilter { @SuppressWarnings("rawtypes") public List<VerifyResult> verify(byte[] contentData, - byte[] signatureContent, Date verificationTime, int[] byteRange) + byte[] signatureContent, Date verificationTime, int[] byteRange, IVerifier verifier) throws PdfAsException { - - List<VerifyResult> resultList = new ArrayList<VerifyResult>(); - try { - logger.info("verification with MOA @ " + this.moaEndpoint); - - SignatureVerificationServiceStub service = new SignatureVerificationServiceStub( - this.moaEndpoint); - VerifyCMSSignatureRequest verifyCMSSignatureRequest = new VerifyCMSSignatureRequest(); - Token token = new Token(); - token.setValue(this.moaTrustProfile); - verifyCMSSignatureRequest.setTrustProfileID(token); - - byte[] data = contentData; - byte[] signature = signatureContent; - - CMSDataObjectOptionalMetaType cmsDataObjectOptionalMetaType = new CMSDataObjectOptionalMetaType(); - CMSContentBaseType cmsDataContent = new CMSContentBaseType(); - cmsDataContent.setBase64Content(new DataHandler( - new ByteArrayDataSource(data, "application/pdf"))); - DataHandler cmsSignature = new DataHandler(new ByteArrayDataSource( - signature, "application/pdf")); - cmsDataObjectOptionalMetaType.setContent(cmsDataContent); - verifyCMSSignatureRequest.setCMSSignature(cmsSignature); - verifyCMSSignatureRequest - .setDataObject(cmsDataObjectOptionalMetaType); - if (verificationTime != null) { - Calendar cal = Calendar.getInstance(); - cal.setTime(verificationTime); - verifyCMSSignatureRequest.setDateTime(cal); - } - // cmsDataObjectOptionalMetaType. - VerifyCMSSignatureResponse response = service - .verifyCMSSignature(verifyCMSSignatureRequest); - - logger.debug("Got Verify Response from MOA"); - - VerifyCMSSignatureResponseTypeSequence[] verifySequence = response - .getVerifyCMSSignatureResponse() - .getVerifyCMSSignatureResponseTypeSequence(); - for (int i = 0; i < verifySequence.length; i++) { - VerifyResultImpl result = new VerifyResultImpl(); - logger.debug(" ---------------------- "); - logger.debug("Signature: " + i); - - SignatureCheckImpl certificateCheck; - - verifySequence[i].getSignerInfo().getKeyInfoTypeChoice()[0] - .getExtraElement(); - if (verifySequence[i].getCertificateCheck() != null) { - certificateCheck = new SignatureCheckImpl(verifySequence[i] - .getCertificateCheck().getCode().intValue(), - verifySequence[i].getCertificateCheck() - .isInfoSpecified() ? verifySequence[i] - .getCertificateCheck().getInfo().toString() - : ""); - } else { - certificateCheck = new SignatureCheckImpl( - 1, - ""); - } - - if(certificateCheck.getMessage() == null || certificateCheck.getMessage().trim().length() == 0) { - String resourceString = "verify.cert." + certificateCheck.getCode(); - String message = CodesResolver.resolveMessage(resourceString); - certificateCheck.setMessage(message); - } - - logger.debug("Certificate Check: " + certificateCheck.getCode() + " [" + certificateCheck.getMessage() + "]"); - - SignatureCheckImpl signatureCheck = new SignatureCheckImpl( - verifySequence[i].getSignatureCheck().getCode() - .intValue(), - verifySequence[i].getSignatureCheck().isInfoSpecified() ? verifySequence[i] - .getSignatureCheck().getInfo().toString() - : ""); - - if(signatureCheck.getMessage() == null || signatureCheck.getMessage().trim().length() == 0) { - String resourceString = "verify.value." + signatureCheck.getCode(); - String message = CodesResolver.resolveMessage(resourceString); - signatureCheck.setMessage(message); - } - - logger.debug("Signature Check: " + signatureCheck.getCode() + " [" + signatureCheck.getMessage() + "]"); - - result.setCertificateCheck(certificateCheck); - result.setValueCheckCode(signatureCheck); - result.setVerificationDone(true); - - KeyInfoTypeChoice[] keyInfo = verifySequence[i].getSignerInfo() - .getKeyInfoTypeChoice(); - KeyInfoTypeChoice choice = keyInfo[0]; - result.setSignatureData(PDFUtils.blackOutSignature(data, byteRange)); - - // extract certificate - if (choice.isX509DataSpecified()) { - byte[] certData = null; - X509DataTypeSequence[] x509Sequence = choice.getX509Data() - .getX509DataTypeSequence(); - for (int k = 0; k < x509Sequence.length; k++) { - X509DataTypeSequence x509Data = x509Sequence[k]; - if (x509Data.getX509DataTypeChoice_type0() - .isX509CertificateSpecified()) { - DataHandler handler = x509Data - .getX509DataTypeChoice_type0() - .getX509Certificate(); - certData = StreamUtils - .inputStreamToByteArray(handler - .getInputStream()); - } else if (x509Data.getX509DataTypeChoice_type0() - .isExtraElementSpecified()) { - if (x509Data - .getX509DataTypeChoice_type0() - .getExtraElement() - .getLocalName() - .equals(SignatureVerificationServiceStub.QualifiedCertificate.MY_QNAME - .getLocalPart())) { - result.setQualifiedCertificate(true); - } - } - } - X509Certificate certificate = new X509Certificate(certData); - result.setSignerCertificate(certificate); - } else if (choice.isExtraElementSpecified()) { - String xmldisg = choice.getExtraElement().toString(); - JAXBElement jaxbElement = (JAXBElement) DsigMarschaller - .unmarshalFromString(xmldisg); - if (jaxbElement.getValue() instanceof X509DataType) { - X509DataType x509Data = (X509DataType) jaxbElement - .getValue(); - List<Object> dsigElements = x509Data - .getX509IssuerSerialOrX509SKIOrX509SubjectName(); - for (int j = 0; j < dsigElements.size(); j++) { - Object jaxElement = dsigElements.get(j); - if (jaxElement instanceof JAXBElement) { - JAXBElement jaxbElementMember = (JAXBElement) jaxElement; - if (jaxbElementMember - .getName() - .equals(DsigMarschaller.X509DataTypeX509Certificate_QNAME)) { - if (jaxbElementMember.getValue() instanceof byte[]) { - byte[] certData = (byte[]) jaxbElementMember - .getValue(); - X509Certificate certificate = new X509Certificate( - certData); - result.setSignerCertificate(certificate); - break; - } - } - } - } - } - } - - resultList.add(result); - - logger.debug(" ---------------------- "); - } - } catch (Throwable e) { - logger.error("Verification failed", e); - throw new PdfAsException("error.pdf.verify.02", e); + + byte[] data = contentData; + byte[] signature = signatureContent; + + List<VerifyResult> verifieResults = verifier.verify(signature, data, verificationTime); + for(int i =0; i < verifieResults.size();i++) { + VerifyResultImpl result = (VerifyResultImpl)verifieResults.get(i); + result.setSignatureData(PDFUtils.blackOutSignature(data, byteRange)); } - return resultList; + + return verifieResults; } public List<FilterEntry> getFiters() { diff --git a/signature-standards/sigs-pkcs7detached/src/main/java/at/gv/egiz/pdfas/sigs/pkcs7detached/PKCS7DetachedVerifier.java b/signature-standards/sigs-pkcs7detached/src/main/java/at/gv/egiz/pdfas/sigs/pkcs7detached/PKCS7DetachedVerifier.java index bef034b1..fb7fa5ab 100644 --- a/signature-standards/sigs-pkcs7detached/src/main/java/at/gv/egiz/pdfas/sigs/pkcs7detached/PKCS7DetachedVerifier.java +++ b/signature-standards/sigs-pkcs7detached/src/main/java/at/gv/egiz/pdfas/sigs/pkcs7detached/PKCS7DetachedVerifier.java @@ -46,6 +46,7 @@ import at.gv.egiz.pdfas.common.utils.PDFUtils; import at.gv.egiz.pdfas.lib.api.Configuration; import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; import at.gv.egiz.pdfas.lib.impl.verify.FilterEntry; +import at.gv.egiz.pdfas.lib.impl.verify.IVerifier; import at.gv.egiz.pdfas.lib.impl.verify.IVerifyFilter; import at.gv.egiz.pdfas.lib.impl.verify.SignatureCheckImpl; import at.gv.egiz.pdfas.lib.impl.verify.VerifyResultImpl; @@ -57,68 +58,22 @@ public class PKCS7DetachedVerifier implements IVerifyFilter { public PKCS7DetachedVerifier() { } - public List<VerifyResult> verify(byte[] contentData, byte[] signatureContent, Date verificationTime, int[] byteRange) + public List<VerifyResult> verify(byte[] contentData, byte[] signatureContent, + Date verificationTime, int[] byteRange, IVerifier verifier) throws PdfAsException { - try { - List<VerifyResult> result = new ArrayList<VerifyResult>(); - - SignedData signedData = new SignedData(contentData, new AlgorithmID[] { - AlgorithmID.sha256, AlgorithmID.sha1, AlgorithmID.ripeMd160, AlgorithmID.ripeMd160_ISO - }); - ContentInfo ci = new ContentInfo(new ByteArrayInputStream( - signatureContent)); - if (!ci.getContentType().equals(ObjectID.cms_signedData)) { - throw new PdfAsException("error.pdf.verify.01"); - } - //SignedData signedData = (SignedData)ci.getContent(); - //signedData.setContent(contentData); - - signedData.decode(ci.getContentInputStream()); - - // get the signer infos - SignerInfo[] signerInfos = signedData.getSignerInfos(); - // verify the signatures - for (int i = 0; i < signerInfos.length; i++) { - VerifyResultImpl verifyResult = new VerifyResultImpl(); - verifyResult.setSignatureData(PDFUtils.blackOutSignature(contentData, byteRange)); - try { - // verify the signature for SignerInfo at index i - X509Certificate signer_cert = signedData.verify(i); - logger.info("Signature Algo: {}, Digest {}", - signedData.getSignerInfos()[i].getSignatureAlgorithm(), - signedData.getSignerInfos()[i].getDigestAlgorithm()); - // if the signature is OK the certificate of the - // signer is returned - logger.info("Signature OK from signer: " - + signer_cert.getSubjectDN()); - verifyResult.setSignerCertificate(signer_cert); - verifyResult.setValueCheckCode(new SignatureCheckImpl(0, "OK")); - verifyResult.setManifestCheckCode(new SignatureCheckImpl(99, "not checked")); - verifyResult.setCertificateCheck(new SignatureCheckImpl(99, "not checked")); - verifyResult.setVerificationDone(true); - } catch (SignatureException ex) { - // if the signature is not OK a SignatureException - // is thrown - logger.info("Signature ERROR from signer: " - + signedData.getCertificate( - signerInfos[i].getSignerIdentifier()) - .getSubjectDN(), ex); - - verifyResult.setSignerCertificate( - signedData.getCertificate(signerInfos[i].getSignerIdentifier())); - verifyResult.setValueCheckCode(new SignatureCheckImpl(1, "failed to check signature")); - verifyResult.setManifestCheckCode(new SignatureCheckImpl(99, "not checked")); - verifyResult.setCertificateCheck(new SignatureCheckImpl(99, "not checked")); - verifyResult.setVerificationDone(false); - verifyResult.setVerificationException(new PdfAsSignatureException("failed to check signature", ex)); - } - result.add(verifyResult); - } - - return result; - } catch (Throwable e) { - throw new PdfAsException("error.pdf.verify.02", e); + + byte[] data = contentData; + byte[] signature = signatureContent; + + List<VerifyResult> verifieResults = verifier.verify(signature, data, verificationTime); + for(int i =0; i < verifieResults.size();i++) { + VerifyResultImpl result = (VerifyResultImpl)verifieResults.get(i); + result.setSignatureData(PDFUtils.blackOutSignature(data, byteRange)); } + + return verifieResults; + + } public List<FilterEntry> getFiters() { |