diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl')
10 files changed, 1283 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java new file mode 100644 index 00000000..942cd35c --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/AbstractSignatureService.java @@ -0,0 +1,97 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; + +import java.security.Provider; +import java.security.Security; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.spss.server.config.ConfigurationException; +import at.gv.egovernment.moa.spss.server.iaik.config.IaikConfigurator; +import at.gv.egovernment.moa.spss.server.transaction.TransactionContext; +import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager; +import at.gv.egovernment.moaspss.logging.LoggingContext; +import at.gv.egovernment.moaspss.logging.LoggingContextManager; + +public abstract class AbstractSignatureService { + private static final Logger log = LoggerFactory.getLogger(AbstractSignatureService.class); + + @Autowired(required = true) + MoaSigInitializer moaSigConfig; + + /** + * Get a new {@link Document} from {@link DocumentBuilder} in synchronized form, + * because {@link DocumentBuilderFactory} and {@link DocumentBuilder} are not + * thread-safe. + * + * @return {@link Document} + * @throws ParserConfigurationException In case of an error + */ + protected synchronized Document getNewDocumentBuilder() throws ParserConfigurationException { + final DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + return docBuilder.newDocument(); + + } + + /** + * Set up the thread-local context information needed for calling the various + * <code>Invoker</code> classes. + * + * @throws ConfigurationException An error occurred setting up the configuration + * in the <code>TransactionContext</code>. + */ + protected final void setUpContexts(final String transactionID) throws ConfigurationException { + final TransactionContextManager txMgr = TransactionContextManager.getInstance(); + final LoggingContextManager logMgr = LoggingContextManager.getInstance(); + + if (txMgr.getTransactionContext() == null) { + log.debug("Set not MOA-Sig transaction context"); + final TransactionContext ctx = + new TransactionContext(transactionID, null, moaSigConfig.getConfigHolder().getMoaSpssConfig()); + txMgr.setTransactionContext(ctx); + + } + + //set Logging context into MOA-Sig + if (logMgr.getLoggingContext() == null) { + final LoggingContext ctx = new LoggingContext(transactionID); + logMgr.setLoggingContext(ctx); + + } + + //dump Java Security-Providers + if (log.isTraceEnabled()) { + log.trace("Set-Up verifier Bean: {}", this); + dumpSecProviders("MOA-Sig Context-Set-Up"); + + } + + new IaikConfigurator().configure(moaSigConfig.getConfigHolder().getMoaSpssConfig()); + + } + + private static void dumpSecProviders(String message) { + log.trace("Security Providers: {}", message); + for (final Provider provider : Security.getProviders()) { + log.trace(" - {} - {}", provider.getName(), provider.getVersion()); + + } + } + + /** + * Tear down thread-local context information. + */ + protected void tearDownContexts() { + TransactionContextManager.getInstance().setTransactionContext(null); + LoggingContextManager.getInstance().setLoggingContext(null); + log.debug("Closing MOA-Sig transaction context"); + + } + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/MoaSigInitializer.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/MoaSigInitializer.java new file mode 100644 index 00000000..dc4aa4c0 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/MoaSigInitializer.java @@ -0,0 +1,113 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.security.Provider; +import java.security.Security; +import java.util.Iterator; +import java.util.Map.Entry; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.ISchemaRessourceProvider; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceConfigurationException; +import at.gv.egovernment.moa.spss.server.init.StartupConfigurationHolder; +import at.gv.egovernment.moa.spss.server.init.SystemInitializer; +import at.gv.egovernment.moaspss.logging.LoggingContext; +import at.gv.egovernment.moaspss.logging.LoggingContextManager; +import at.gv.egovernment.moaspss.util.DOMUtils; +import iaik.asn1.structures.AlgorithmID; +import iaik.security.ec.provider.ECCelerate; +import iaik.security.provider.IAIK; +import lombok.Getter; + +public class MoaSigInitializer { + private static final Logger log = LoggerFactory.getLogger(MoaSigInitializer.class); + + @Autowired(required = false) + ISchemaRessourceProvider[] schemas; + + /** + * Get MOA-Sig configuration object. + */ + @Getter + private StartupConfigurationHolder configHolder; + + + @PostConstruct + private synchronized void initialize() throws MoaSigServiceConfigurationException { + log.info("Initializing MOA-Sig signature-verification service ... "); + + log.info("Loading Java security providers."); + IAIK.addAsProvider(); + ECCelerate.addAsProvider(); + + try { + LoggingContextManager.getInstance().setLoggingContext(new LoggingContext("startup")); + log.debug("MOA-Sig library initialization process ... "); + configHolder = SystemInitializer.init(); + log.info("MOA-Sig library initialization complete "); + + fixJava8_141ProblemWithSslAlgorithms(); + + if (log.isDebugEnabled()) { + log.debug("Loaded Security Provider:"); + final Provider[] providerList = Security.getProviders(); + for (int i = 0; i < providerList.length; i++) { + log.debug("{}: {} Version {}", i, providerList[i].getName(), providerList[i].getVersion()); + + } + } + + // Inject additional XML schemes + if (schemas != null && schemas.length > 0) { + log.debug("Infjecting additional XML schemes ... "); + for (final ISchemaRessourceProvider el : schemas) { + final Iterator<Entry<String, InputStream>> xmlSchemeIt = + el.getSchemas().entrySet().iterator(); + while (xmlSchemeIt.hasNext()) { + final Entry<String, InputStream> xmlDef = xmlSchemeIt.next(); + try { + DOMUtils.addSchemaToPool(xmlDef.getValue(), xmlDef.getKey()); + log.info("Inject XML scheme: {}", xmlDef.getKey()); + + } catch (final IOException e) { + log.warn("Can NOT inject XML scheme: " + xmlDef.getKey(), e); + + } + + } + } + } + + } catch (final RuntimeException e) { + log.error("MOA-SP initialization FAILED!", e); + throw new MoaSigServiceConfigurationException("service.moasig.04", + new Object[] { e.toString() }, e); + } + + } + + private static void fixJava8_141ProblemWithSslAlgorithms() { + log.info("Change AlgorithmIDs to fix problems with Java8 >= 141 ..."); + // new AlgorithmID("1.2.840.113549.1.1.4", "md5WithRSAEncryption", new String[] + // { "MD5withRSA", + // "MD5/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.5", "sha1WithRSAEncryption", + new String[] { "SHA1withRSA", "SHA1/RSA", "SHA-1/RSA", "SHA/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.14", "sha224WithRSAEncryption", + new String[] { "SHA224withRSA", "SHA224/RSA", "SHA-224/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.11", "sha256WithRSAEncryption", + new String[] { "SHA256withRSA", "SHA256/RSA", "SHA-256/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.12", "sha384WithRSAEncryption", + new String[] { "SHA384withRSA", "SHA384/RSA", "SHA-384/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.13", "sha512WithRSAEncryption", + new String[] { "SHA512withRSA", "SHA512/RSA", "SHA-512/RSA" }, null, true); + + log.info("Change AlgorithmIDs finished"); + } +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/MoaSigSpringResourceProvider.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/MoaSigSpringResourceProvider.java new file mode 100644 index 00000000..b5e190d8 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/MoaSigSpringResourceProvider.java @@ -0,0 +1,28 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class MoaSigSpringResourceProvider implements SpringResourceProvider { + + @Override + public Resource[] getResourcesToLoad() { + final ClassPathResource moaSigConfig = + new ClassPathResource("/moa-sig-service.beans.xml", MoaSigSpringResourceProvider.class); + return new Resource[] { moaSigConfig }; + } + + @Override + public String[] getPackagesToScan() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getName() { + return "Signature-verification service based on MOA-Sig (MOA-SPSS)"; + } + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureCreationService.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureCreationService.java new file mode 100644 index 00000000..0d8b7975 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureCreationService.java @@ -0,0 +1,32 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.ISignatureCreationService; +import at.gv.egovernment.moa.spss.server.invoke.CMSSignatureCreationInvoker; +import at.gv.egovernment.moa.spss.server.invoke.XMLSignatureCreationInvoker; + +@Service(value = "moaSigCreateService") +public class SignatureCreationService extends AbstractSignatureService + implements ISignatureCreationService { + private static final Logger log = LoggerFactory.getLogger(SignatureCreationService.class); + + private XMLSignatureCreationInvoker xadesInvoker; + private CMSSignatureCreationInvoker cadesInvoker; + + @PostConstruct + protected void internalInitializer() { + log.debug("Instanzing SignatureCreationService implementation ... "); + xadesInvoker = XMLSignatureCreationInvoker.getInstance(); + cadesInvoker = CMSSignatureCreationInvoker.getInstance(); + log.trace("XML_impl: {} , CMS_imp: {}", + xadesInvoker.getClass().getName(), cadesInvoker.getClass().getName()); + log.info("MOA-Sig signature-creation service initialized"); + + } + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureVerificationService.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureVerificationService.java new file mode 100644 index 00000000..79f39e65 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureVerificationService.java @@ -0,0 +1,517 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; + +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.time.DateFormatUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Service; +import org.springframework.util.Base64Utils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.ISignatureVerificationService; +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.ICmsSignatureVerificationResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.IPdfSignatureVerificationResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.IXmlSignatureVerificationResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceBuilderException; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceException; +import at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data.GenericSignatureVerificationResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data.VerifyPdfSignatureResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data.VerifyPdfSignatureResponse.CoversFullDocument; +import at.gv.egiz.eaaf.modules.sigverify.moasig.impl.parser.VerifyXmlSignatureResponseParser; +import at.gv.egovernment.moa.spss.MOAException; +import at.gv.egovernment.moa.spss.api.cmsverify.VerifyCMSSignatureRequest; +import at.gv.egovernment.moa.spss.api.cmsverify.VerifyCMSSignatureResponse; +import at.gv.egovernment.moa.spss.api.cmsverify.VerifyCMSSignatureResponseElement; +import at.gv.egovernment.moa.spss.api.impl.VerifyCMSSignatureRequestImpl; +import at.gv.egovernment.moa.spss.api.xmlbind.VerifyXMLSignatureRequestParser; +import at.gv.egovernment.moa.spss.api.xmlbind.VerifyXMLSignatureResponseBuilder; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; +import at.gv.egovernment.moa.spss.server.invoke.CMSSignatureVerificationInvoker; +import at.gv.egovernment.moa.spss.server.invoke.XMLSignatureVerificationInvoker; +import at.gv.egovernment.moaspss.util.Constants; + +/** + * MOA-Sig based signature verification implementation. + * + * @author tlenz + * + */ +@Service(value = "moaSigVerifyService") +public class SignatureVerificationService extends AbstractSignatureService + implements ISignatureVerificationService { + private static final Logger log = LoggerFactory.getLogger(SignatureVerificationService.class); + + private static final String XMLNS_NS_URI = Constants.XMLNS_NS_URI; + private static final String MOA_NS_URI = Constants.MOA_NS_URI; + private static final String DSIG = Constants.DSIG_PREFIX + ":"; + private static final String DEFAULT_XPATH_SIGNATURE_LOCATION = "//" + DSIG + "Signature"; + + public static final String PATTERN_ISSUE_INSTANT = "yyyy-MM-dd'T'HH:mm:ssXXX"; + + private CMSSignatureVerificationInvoker cadesInvoker; + private XMLSignatureVerificationInvoker xadesInvocer; + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl. + * ISignatureVerificationService# verifyCMSSignature(byte[], java.lang.String) + */ + @Override + @Nullable + public ICmsSignatureVerificationResponse verifyCmsSignature(final byte[] signature, + final String trustProfileID) throws MoaSigServiceException { + return verifyCmsSignature(signature, trustProfileID, false); + + } + + @Override + public ICmsSignatureVerificationResponse verifyCmsSignature(byte[] signature, String trustProfileID, + boolean performExtendedValidation) throws MoaSigServiceException { + try { + // setup context + setUpContexts(Thread.currentThread().getName()); + + // verify signature + final VerifyCMSSignatureRequest cmsSigVerifyReq = + buildVerfifyCmsRequest(signature, trustProfileID, false, performExtendedValidation); + final VerifyCMSSignatureResponse cmsSigVerifyResp = + cadesInvoker.verifyCMSSignature(cmsSigVerifyReq); + return parseCmsVerificationResult(cmsSigVerifyResp); + + } catch (final MOAException e) { + log.warn("CMS signature verification has an error.", e); + throw new MoaSigServiceException("service.03", new Object[] { e.toString() }, e); + + } catch (final CertificateEncodingException e) { + log.warn("Can NOT serialize X509 certificate from CMS/CAdES signature-verification response", + e); + throw new MoaSigServiceException("service.03", new Object[] { e.toString() }, e); + + } finally { + tearDownContexts(); + + } + } + + @Override + public List<IPdfSignatureVerificationResponse> verifyPdfSignature(byte[] pdf, String trustProfileID) + throws MoaSigServiceException { + return verifyPdfSignature(pdf, trustProfileID, false); + + } + + @Override + public List<IPdfSignatureVerificationResponse> verifyPdfSignature(byte[] pdf, String trustProfileID, + boolean performExtendedValidation) throws MoaSigServiceException { + try { + // setup context + setUpContexts(Thread.currentThread().getName()); + + // verify signature + final VerifyCMSSignatureResponse cmsSigVerifyResp = cadesInvoker.verifyCMSSignature( + buildVerfifyCmsRequest(pdf, trustProfileID, true, performExtendedValidation)); + + return parsePdfVerificationResult(cmsSigVerifyResp); + + } catch (final MOAException e) { + log.warn("PDF signature verification has an error.", e); + throw new MoaSigServiceException("service.03", new Object[] { e.toString() }, e); + + } catch (final CertificateEncodingException e) { + log.warn("Can NOT serialize X509 certificate from PDF/PAdES signature-verification response", + e); + throw new MoaSigServiceException("service.03", new Object[] { e.toString() }, e); + + } finally { + tearDownContexts(); + + } + } + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl. + * ISignatureVerificationService# verifyXMLSignature(byte[], java.lang.String) + */ + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(final byte[] signature, + final String trustProfileID) throws MoaSigServiceException { + return verifyXmlSignature(signature, trustProfileID, null, DEFAULT_XPATH_SIGNATURE_LOCATION, null, + Collections.emptyMap()); + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl. + * ISignatureVerificationService# verifyXMLSignature(byte[], java.lang.String, + * java.util.List) + */ + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(final byte[] signature, + final String trustProfileID, final List<String> verifyTransformsInfoProfileID) + throws MoaSigServiceException { + return verifyXmlSignature(signature, trustProfileID, verifyTransformsInfoProfileID, + DEFAULT_XPATH_SIGNATURE_LOCATION, null, Collections.emptyMap()); + } + + /* + * (non-Javadoc) + * + * @see at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl. + * ISignatureVerificationService# verifyXMLSignature(byte[], java.lang.String, + * java.lang.String) + */ + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(final byte[] signature, + final String trustProfileID, final String signatureLocationXpath) + throws MoaSigServiceException { + return verifyXmlSignature(signature, trustProfileID, null, signatureLocationXpath, null, Collections.emptyMap()); + } + + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(byte[] signature, String trustProfileID, + Date signingDate) throws MoaSigServiceException { + return verifyXmlSignature(signature, trustProfileID, null, + DEFAULT_XPATH_SIGNATURE_LOCATION, signingDate, Collections.emptyMap()); + } + + + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(final byte[] signature, + final String trustProfileID, final List<String> verifyTransformsInfoProfileID, + final String xpathSignatureLocation, Date signingDate) throws MoaSigServiceException { + return verifyXmlSignature(signature, trustProfileID, verifyTransformsInfoProfileID, xpathSignatureLocation, + signingDate, Collections.emptyMap()); + } + + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(final byte[] signature, + final String trustProfileID, final List<String> verifyTransformsInfoProfileID, + final String xpathSignatureLocation, Date signingDate, final Map<String, byte[]> supplementContent) + throws MoaSigServiceException { + try { + // setup context + setUpContexts(Thread.currentThread().getName()); + + // build signature-verification request + final Element domVerifyXmlSignatureRequest = buildVerifyXmlRequest(signature, trustProfileID, + verifyTransformsInfoProfileID, xpathSignatureLocation, signingDate, supplementContent); + + // send signature-verification to MOA-Sig + final VerifyXMLSignatureRequest vsrequest = + new VerifyXMLSignatureRequestParser().parse(domVerifyXmlSignatureRequest); + final VerifyXMLSignatureResponse vsresponse = xadesInvocer.verifyXMLSignature(vsrequest); + final Document result = new VerifyXMLSignatureResponseBuilder(true).build(vsresponse); + + // parses the <IXMLSignatureVerificationResponse> + final IXmlSignatureVerificationResponse verifyXmlSignatureResponse = + new VerifyXmlSignatureResponseParser(result.getDocumentElement()).parseData(); + + return verifyXmlSignatureResponse; + + } catch (final MoaSigServiceException e) { + throw e; + + } catch (final MOAException e) { + log.warn("MOA-Sig signature-verification has an internal error." + " MsgCode: " + + e.getMessageId() + " Msg: " + e.getMessage(), e); + throw new MoaSigServiceException("service.moasig.03", new Object[] { e.getMessage() }, e); + + } finally { + tearDownContexts(); + + } + } + + private ICmsSignatureVerificationResponse parseCmsVerificationResult( + final VerifyCMSSignatureResponse cmsSigVerifyResp) throws CertificateEncodingException { + + if (cmsSigVerifyResp.getResponseElements() == null + || cmsSigVerifyResp.getResponseElements().isEmpty()) { + log.info("No CMS signature FOUND. "); + return null; + + } + + if (cmsSigVerifyResp.getResponseElements().size() > 1) { + log.warn( + "CMS or CAdES signature contains more than one technical signatures. Only validate the first signature"); + } + + return (ICmsSignatureVerificationResponse) parseBasisSignatureInformation( + new at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data.VerifyCmsSignatureResponse(), + (VerifyCMSSignatureResponseElement) cmsSigVerifyResp.getResponseElements().get(0)); + } + + private List<IPdfSignatureVerificationResponse> parsePdfVerificationResult( + VerifyCMSSignatureResponse cmsSigVerifyResp) throws CertificateEncodingException { + + List<IPdfSignatureVerificationResponse> result = new ArrayList<>(); + if (cmsSigVerifyResp.getResponseElements() == null + || cmsSigVerifyResp.getResponseElements().isEmpty()) { + log.info("No CMS signature FOUND. "); + + } else { + Iterator<?> it = cmsSigVerifyResp.getResponseElements().iterator(); + while (it.hasNext()) { + VerifyCMSSignatureResponseElement el = (VerifyCMSSignatureResponseElement) it.next(); + VerifyPdfSignatureResponse pdfSigResult = + (VerifyPdfSignatureResponse) parseBasisSignatureInformation(new VerifyPdfSignatureResponse(), el); + + pdfSigResult.setSignatureCoversFullDocument( + el.getCoversFullDocument() != null + ? el.getCoversFullDocument() ? CoversFullDocument.YES : CoversFullDocument.NO + : CoversFullDocument.UNKNOWN); + pdfSigResult.setByteRange(convertByteRanges(el.getByteRangeOfSignature())); + result.add(pdfSigResult); + + } + } + + return result; + + } + + private List<Pair<Integer, Integer>> convertByteRanges(int[] byteRangeOfSignature) { + List<Pair<Integer, Integer>> result = new ArrayList<>(); + + if (byteRangeOfSignature != null) { + for (int i = 0; i < byteRangeOfSignature.length / 2; i++) { + result.add(Pair.newInstance( + Integer.valueOf(byteRangeOfSignature[i]), + Integer.valueOf(byteRangeOfSignature[i + 1]))); + + } + } else { + log.debug("PDF signature-verification result contains no byte-range information"); + + } + + return result; + } + + private GenericSignatureVerificationResponse parseBasisSignatureInformation( + GenericSignatureVerificationResponse result, VerifyCMSSignatureResponseElement resp) + throws CertificateEncodingException { + // parse results into response container + result.setSignatureCheckCode(resp.getSignatureCheck().getCode()); + result.setCertificateCheckCode(resp.getCertificateCheck().getCode()); + + if (resp.getSignerInfo() != null) { + result.setSigningDateTime(resp.getSignerInfo().getSigningTime()); + result + .setX509CertificateEncoded(resp.getSignerInfo().getSignerCertificate().getEncoded()); + result.setQualifiedCertificate(resp.getSignerInfo().isQualifiedCertificate()); + + result.setPublicAuthority(resp.getSignerInfo().isPublicAuthority()); + result.setPublicAuthorityCode(resp.getSignerInfo().getPublicAuhtorityID()); + + } else { + log.info("CMS or CAdES verification result contains no SignerInfo"); + + } + + + //TODO: add extended validation infos + result.setSignatureAlgorithmIdentifier(resp.getSignatureAlgorithm()); + result.setExtendedCertificateCheckResult(resp.getExtendedCertificateCheck()); + result.setFormValidationResults(resp.getAdESFormResults()); + + return result; + + } + + /** + * Build a VerifyCMS-Siganture request for MOA-Sig. <br> + * <br> + * This builder only generates verification-request for enveloped CMS or CAdES + * signatures <br> + * This + * + * @param signature CMS or CAdES signature + * @param trustProfileID trustProfileID MOA-Sig Trust-Profile + * @param isPdfSignature Make CAdES signature as part of an PAdES + * document + * @param performExtendedValidation To extended validation. See MOA-Sig + * documentation for detailed information + * @return + */ + private VerifyCMSSignatureRequest buildVerfifyCmsRequest(final byte[] signature, + final String trustProfileID, final boolean isPdfSignature, + final boolean performExtendedValidation) { + final VerifyCMSSignatureRequestImpl verifyCmsSignatureRequest = + new VerifyCMSSignatureRequestImpl(); + verifyCmsSignatureRequest.setDateTime(null); + verifyCmsSignatureRequest.setCMSSignature(new ByteArrayInputStream(signature)); + verifyCmsSignatureRequest.setDataObject(null); + verifyCmsSignatureRequest.setTrustProfileId(trustProfileID); + verifyCmsSignatureRequest.setSignatories(VerifyCMSSignatureRequest.ALL_SIGNATORIES); + verifyCmsSignatureRequest.setPDF(isPdfSignature); + verifyCmsSignatureRequest.setExtended(performExtendedValidation); + return verifyCmsSignatureRequest; + + } + + /** + * Build a VerifyXML-Signature request for MOA-Sig. + * + * @param signature Serialized XML signature + * @param trustProfileID MOA-Sig Trust-Profile + * @param verifyTransformsInfoProfileID {@link List} of Transformation-Profiles + * used for validation + * @param xpathSignatureLocation Xpath that points to location of + * Signature element + * @param sigValDate Signature timestamp + * @param supplementContent Map that contains supplement profile content; keyed by references. Each entry + * in this map becomes a Content/Base64Content child in the SupplementProfile + * node. Use this map to specify content of references that the verification + * service cannot resolve. + * @return MOA-Sig verification request element + * @throws MoaSigServiceBuilderException In case of an error + */ + private Element buildVerifyXmlRequest(final byte[] signature, final String trustProfileID, + final List<String> verifyTransformsInfoProfileID, final String xpathSignatureLocation, + Date sigValDate, final Map<String, byte[]> supplementContent) throws MoaSigServiceBuilderException { + try { + // build empty document + final Document requestDoc_ = getNewDocumentBuilder(); + + final Element requestElem_ = + requestDoc_.createElementNS(MOA_NS_URI, "VerifyXMLSignatureRequest"); + requestElem_.setAttributeNS(XMLNS_NS_URI, "xmlns", MOA_NS_URI); + requestElem_.setAttributeNS(XMLNS_NS_URI, "xmlns:" + Constants.DSIG_PREFIX, + Constants.DSIG_NS_URI); + requestDoc_.appendChild(requestElem_); + + // build the request + + // build set signing time + if (sigValDate != null) { + final Element dateTimeElem = requestDoc_.createElementNS(MOA_NS_URI, "DateTime"); + requestElem_.appendChild(dateTimeElem); + final Node dateTime = requestDoc_.createTextNode( + DateFormatUtils.format(sigValDate, PATTERN_ISSUE_INSTANT)); + dateTimeElem.appendChild(dateTime); + + } + + //set other parameters + final Element verifiySignatureInfoElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureInfo"); + requestElem_.appendChild(verifiySignatureInfoElem); + final Element verifySignatureEnvironmentElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureEnvironment"); + verifiySignatureInfoElem.appendChild(verifySignatureEnvironmentElem); + final Element base64ContentElem = requestDoc_.createElementNS(MOA_NS_URI, "Base64Content"); + verifySignatureEnvironmentElem.appendChild(base64ContentElem); + + // insert the base64 encoded signature + String base64EncodedAssertion = Base64Utils.encodeToString(signature); + // replace all '\r' characters by no char. + final StringBuffer replaced = new StringBuffer(); + for (int i = 0; i < base64EncodedAssertion.length(); i++) { + final char c = base64EncodedAssertion.charAt(i); + if (c != '\r') { + replaced.append(c); + } + } + base64EncodedAssertion = replaced.toString(); + final Node base64Content = requestDoc_.createTextNode(base64EncodedAssertion); + base64ContentElem.appendChild(base64Content); + + // specify the signature location + final Element verifySignatureLocationElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifySignatureLocation"); + verifiySignatureInfoElem.appendChild(verifySignatureLocationElem); + final Node signatureLocation = requestDoc_.createTextNode(xpathSignatureLocation); + verifySignatureLocationElem.appendChild(signatureLocation); + + // signature manifest params + if (verifyTransformsInfoProfileID != null && !verifyTransformsInfoProfileID.isEmpty()) { + final Element signatureManifestCheckParamsElem = + requestDoc_.createElementNS(MOA_NS_URI, "SignatureManifestCheckParams"); + requestElem_.appendChild(signatureManifestCheckParamsElem); + signatureManifestCheckParamsElem.setAttribute("ReturnReferenceInputData", "false"); + + // verify transformations + final Element referenceInfoElem = requestDoc_.createElementNS(MOA_NS_URI, "ReferenceInfo"); + signatureManifestCheckParamsElem.appendChild(referenceInfoElem); + for (final String element : verifyTransformsInfoProfileID) { + final Element verifyTransformsInfoProfileIdElem = + requestDoc_.createElementNS(MOA_NS_URI, "VerifyTransformsInfoProfileID"); + referenceInfoElem.appendChild(verifyTransformsInfoProfileIdElem); + verifyTransformsInfoProfileIdElem.appendChild(requestDoc_.createTextNode(element)); + + } + } + + // hashinput data + final Element returnHashInputDataElem = + requestDoc_.createElementNS(MOA_NS_URI, "ReturnHashInputData"); + requestElem_.appendChild(returnHashInputDataElem); + + // add trustProfileID + final Element trustProfileIdElem = requestDoc_.createElementNS(MOA_NS_URI, "TrustProfileID"); + trustProfileIdElem.appendChild(requestDoc_.createTextNode(trustProfileID)); + requestElem_.appendChild(trustProfileIdElem); + + // add supplement profile + if (!supplementContent.isEmpty()) { + + final Element supplementProfile = requestDoc_.createElementNS(MOA_NS_URI, "SupplementProfile"); + + for (Map.Entry<String, byte[]> entry: supplementContent.entrySet()) { + String reference = entry.getKey(); + byte[] contentBytes = entry.getValue(); + final Element content = requestDoc_.createElementNS(MOA_NS_URI, "Content"); + content.setAttribute("Reference", reference); + final Element b64content = requestDoc_.createElementNS(MOA_NS_URI, "Base64Content"); + b64content.setTextContent(Base64Utils.encodeToString(contentBytes)); + content.appendChild(b64content); + supplementProfile.appendChild(content); + } + + requestElem_.appendChild(supplementProfile); + } + + return requestElem_; + + } catch (final Throwable t) { + log.warn("Can NOT build VerifyXML-Signature request for MOA-Sig", t); + throw new MoaSigServiceBuilderException("service.moasig.03", new Object[] { t.getMessage() }, + t); + + } + } + + @PostConstruct + protected void internalInitializer() { + log.debug("Instanzing SignatureVerificationService implementation ... "); + // svs = + // at.gv.egovernment.moa.spss.api.SignatureVerificationService.getInstance(); + cadesInvoker = CMSSignatureVerificationInvoker.getInstance(); + xadesInvocer = XMLSignatureVerificationInvoker.getInstance(); + log.info("MOA-Sig signature-verification service initialized"); + + } + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/GenericSignatureVerificationResponse.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/GenericSignatureVerificationResponse.java new file mode 100644 index 00000000..6006b731 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/GenericSignatureVerificationResponse.java @@ -0,0 +1,223 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data; + +import java.io.Serializable; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.IGenericSignatureVerificationResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceException; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceParserException; +import at.gv.egovernment.moa.spss.api.common.ExtendedCertificateCheckResult; +import at.gv.egovernment.moa.spss.api.xmlverify.AdESFormResults; +import iaik.x509.X509Certificate; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@Setter +public class GenericSignatureVerificationResponse + implements IGenericSignatureVerificationResponse, Serializable { + + private static final long serialVersionUID = -7751001050689401118L; + + /** The signing time. */ + private Date signingDateTime; + + /** The signatureCheckCode to be stored. */ + private int signatureCheckCode; + + /** The certificateCheckCode to be stored. */ + private int certificateCheckCode; + + /** The publicAuthority to be stored. */ + private boolean publicAuthority; + + /** The publicAuthorityCode to be stored. */ + private String publicAuthorityCode; + + /** The qualifiedCertificate to be stored. */ + private boolean qualifiedCertificate; + + private byte[] x509CertificateEncoded; + + /** + * Identifier of the signing algorithm. + */ + private String signatureAlgorithmIdentifier; + + private ExtendedCertificateValidation extendedCertificateValidation; + + private List<ExtendedResult> formValidationResults = null; + + @Override + public Date getSigningDateTime() { + if (this.signingDateTime != null) { + return new Date(this.signingDateTime.getTime()); + } + return null; + + } + + @Override + public X509Certificate getX509Certificate() throws MoaSigServiceException { + if (x509CertificateEncoded != null) { + try { + return new X509Certificate(x509CertificateEncoded); + + } catch (final CertificateException e) { + log.error("Can NOT parse X509 certifcate in " + + GenericSignatureVerificationResponse.class.getName(), e); + throw new MoaSigServiceParserException("service.moasig.01", null, e); + } + + } + + return null; + + } + + @Override + public byte[] getX509CertificateEncoded() { + if (this.x509CertificateEncoded != null) { + return this.x509CertificateEncoded.clone(); + + } + return null; + + } + + @Override + public String getPublicAuthorityCode() { + if (StringUtils.isNotEmpty(this.publicAuthorityCode)) { + return this.publicAuthorityCode; + + } else { + return null; + + } + + } + + @Override + public List<ExtendedResult> getFormValidationResults() { + if (formValidationResults == null) { + return Collections.emptyList(); + + } else { + return formValidationResults; + + } + } + + /** + * Set signature creation timestramp. + * + * @param signingDateTime timestamp + */ + public void setSigningDateTime(final Date signingDateTime) { + if (signingDateTime != null) { + this.signingDateTime = new Date(signingDateTime.getTime()); + } + } + + /** + * Set encoded signer certificate. + * + * @param x509CertificateEncoded signer cerificate + */ + public void setX509CertificateEncoded(final byte[] x509CertificateEncoded) { + if (x509CertificateEncoded != null) { + this.x509CertificateEncoded = x509CertificateEncoded.clone(); + + } + } + + /** + * Set extended certificate-validation result. + * + * @param extendedCertificateCheck Extended result from MOA-Sig + */ + public void setExtendedCertificateCheckResult(ExtendedCertificateCheckResult extendedCertificateCheck) { + if (extendedCertificateCheck != null) { + this.extendedCertificateValidation = ExtendedCertificateValidation.builder() + .majorResult(ExtendedResult.builder() + .code(extendedCertificateCheck.getMajorCode()) + .info(extendedCertificateCheck.getMajorInfo()) + .build()) + .minorResult(ExtendedResult.builder() + .code(extendedCertificateCheck.getMinorCode()) + .info(extendedCertificateCheck.getMinorInfo()) + .build()) + .build(); + + } else { + log.debug("No extended verification-result. Skipping certificate-result extraction ... "); + + } + } + + /** + * Set form-validation result. + * + * @param formCheckResult Extended form-validation result from MOA-Sig + */ + public void setFormValidationResults(List<?> formCheckResult) { + if (formCheckResult != null) { + for (Object elObj : formCheckResult) { + if (elObj instanceof AdESFormResults) { + AdESFormResults el = (AdESFormResults)elObj; + + if (formValidationResults == null) { + formValidationResults = new ArrayList<>(); + + } + + formValidationResults.add(ExtendedResult.builder() + .code(el.getCode()) + .info(el.getName()) + .build()); + + } else { + log.warn("Skip unknown form-validation result of type: {}", elObj.getClass().getName()); + + } + } + + } else { + log.debug("No extended verification-result. Skipping form-validation result extraction ... "); + + } + + } + + @Getter + @Builder + public static class ExtendedCertificateValidation implements Serializable { + + private static final long serialVersionUID = -7800026008655393276L; + + private ExtendedResult majorResult; + private ExtendedResult minorResult; + + } + + @Getter + @Builder + public static class ExtendedResult implements Serializable { + + private static final long serialVersionUID = 8523769744476971010L; + + private int code; + private String info; + + } + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyCmsSignatureResponse.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyCmsSignatureResponse.java new file mode 100644 index 00000000..a812db56 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyCmsSignatureResponse.java @@ -0,0 +1,14 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data; + +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.ICmsSignatureVerificationResponse; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class VerifyCmsSignatureResponse extends GenericSignatureVerificationResponse + implements ICmsSignatureVerificationResponse { + + private static final long serialVersionUID = 708260904158070696L; + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyPdfSignatureResponse.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyPdfSignatureResponse.java new file mode 100644 index 00000000..740ac55a --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyPdfSignatureResponse.java @@ -0,0 +1,30 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data; + +import java.util.List; + +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.IPdfSignatureVerificationResponse; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class VerifyPdfSignatureResponse extends VerifyCmsSignatureResponse + implements IPdfSignatureVerificationResponse { + + private static final long serialVersionUID = 1835687958341837826L; + + /** + * Flag if signature covers the full pdf-document. + */ + private CoversFullDocument signatureCoversFullDocument = CoversFullDocument.UNKNOWN; + + /** + * PDF signing ranges as {@link List} of {@link Pair} of starting-byte and byte-length. + */ + private List<Pair<Integer, Integer>> byteRange; + + + public enum CoversFullDocument { YES, NO, UNKNOWN } + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyXmlSignatureResponse.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyXmlSignatureResponse.java new file mode 100644 index 00000000..4021a90b --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/data/VerifyXmlSignatureResponse.java @@ -0,0 +1,35 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data; + +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.IXmlSignatureVerificationResponse; +import lombok.Getter; +import lombok.Setter; + +/** + * MOA-Sig signature verification response for XML based signatures. + * + * @author tlenz + * + */ + +@Getter +@Setter +public class VerifyXmlSignatureResponse extends GenericSignatureVerificationResponse + implements IXmlSignatureVerificationResponse { + + private static final long serialVersionUID = 8386070769565711601L; + + /** The xmlDsigSubjectName to be stored. */ + private String xmlDsigSubjectName; + + /** The xmlDSIGManifestCheckCode to be stored. */ + private int xmlDsigManifestCheckCode; + /** The xmlDSIGManigest to be stored. */ + private boolean xmlDsigManigest; + + /** + * The result of the signature manifest check. The default value <code>-1</code> + * indicates that the signature manifest has not been checked. + */ + private int signatureManifestCheckCode = -1; + +} diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/parser/VerifyXmlSignatureResponseParser.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/parser/VerifyXmlSignatureResponseParser.java new file mode 100644 index 00000000..746b5461 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/parser/VerifyXmlSignatureResponseParser.java @@ -0,0 +1,194 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl.parser; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import org.joda.time.DateTime; +import org.joda.time.format.ISODateTimeFormat; +import org.springframework.lang.NonNull; +import org.w3c.dom.Element; + +import at.gv.egiz.eaaf.modules.sigverify.moasig.api.data.IXmlSignatureVerificationResponse; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceException; +import at.gv.egiz.eaaf.modules.sigverify.moasig.exceptions.MoaSigServiceParserException; +import at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data.VerifyXmlSignatureResponse; +import at.gv.egovernment.moaspss.util.Constants; +import at.gv.egovernment.moaspss.util.DOMUtils; +import at.gv.egovernment.moaspss.util.XPathUtils; +import iaik.utils.Base64InputStream; +import iaik.x509.X509Certificate; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class VerifyXmlSignatureResponseParser { + + // + // XPath namespace prefix shortcuts + // + /** Xpath prefix for reaching MOA Namespaces. */ + private static final String MOA = Constants.MOA_PREFIX + ":"; + /** Xpath prefix for reaching DSIG Namespaces. */ + private static final String DSIG = Constants.DSIG_PREFIX + ":"; + /** Xpath expression to the root element. */ + private static final String ROOT = "/" + MOA + "VerifyXMLSignatureResponse/"; + + /** Xpath expression to the X509SubjectName element. */ + private static final String DSIG_SUBJECT_NAME_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + DSIG + "X509SubjectName"; + /** Xpath expression to the X509Certificate element. */ + private static final String DSIG_X509_CERTIFICATE_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + DSIG + "X509Certificate"; + /** Xpath expression to the PublicAuthority element. */ + private static final String PUBLIC_AUTHORITY_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + MOA + "PublicAuthority"; + /** Xpath expression to the PublicAuthorityCode element. */ + private static final String PUBLIC_AUTHORITY_CODE_XPATH = + PUBLIC_AUTHORITY_XPATH + "/" + MOA + "Code"; + /** Xpath expression to the QualifiedCertificate element. */ + private static final String QUALIFIED_CERTIFICATE_XPATH = + ROOT + MOA + "SignerInfo/" + DSIG + "X509Data/" + MOA + "QualifiedCertificate"; + + /** Xpath expression to the SignatureCheckCode element. */ + private static final String SIGNATURE_CHECK_CODE_XPATH = + ROOT + MOA + "SignatureCheck/" + MOA + "Code"; + /** Xpath expression to the XMLDSIGManifestCheckCode element. */ + private static final String XMLDSIG_MANIFEST_CHECK_CODE_XPATH = + ROOT + MOA + "XMLDSIGManifestCheck/" + MOA + "Code"; + /** Xpath expression to the SignatureManifestCheckCode element. */ + private static final String SIGNATURE_MANIFEST_CHECK_CODE_XPATH = + ROOT + MOA + "SignatureManifestCheck/" + MOA + "Code"; + /** Xpath expression to the CertificateCheckCode element. */ + private static final String CERTIFICATE_CHECK_CODE_XPATH = + ROOT + MOA + "CertificateCheck/" + MOA + "Code"; + + private static final String SIGNING_TIME_XPATH = ROOT + MOA + "SigningTime"; + + /** + * This is the root element of the XML-Document provided by the Security Layer + * Card. + */ + private Element verifyXmlSignatureResponse; + + /** + * Constructor for VerifyXMLSignatureResponseParser. A DOM-representation of the + * incoming String will be created + * + * @param xmlResponse <code><InfoboxReadResponse></code> as String + * @throws MoaSigServiceParserException on any parsing error + */ + public VerifyXmlSignatureResponseParser(final String xmlResponse) + throws MoaSigServiceParserException { + try { + final InputStream s = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8")); + verifyXmlSignatureResponse = DOMUtils.parseXmlValidating(s); + + } catch (final Throwable t) { + log.warn("Can not parse MOA-Sig response.", t); + throw new MoaSigServiceParserException("service.moasig.02", new Object[] { t.toString() }, t); + + } + } + + /** + * Constructor for VerifyXMLSignatureResponseParser. A DOM-representation of the + * incoming Inputstream will be created + * + * @param xmlResponse <code><InfoboxReadResponse></code> as InputStream + * @throws MoaSigServiceParserException on any parsing error + */ + public VerifyXmlSignatureResponseParser(final InputStream xmlResponse) + throws MoaSigServiceParserException { + try { + verifyXmlSignatureResponse = DOMUtils.parseXmlValidating(xmlResponse); + + } catch (final Throwable t) { + log.warn("Can not parse MOA-Sig response.", t); + throw new MoaSigServiceParserException("service.moasig.02", new Object[] { t.toString() }, t); + + } + } + + /** + * Constructor for VerifyXMLSignatureResponseParser. The incoming Element will + * be used for further operations + * + * @param xmlResponse <code><InfoboxReadResponse></code> as Element + */ + public VerifyXmlSignatureResponseParser(final Element xmlResponse) { + verifyXmlSignatureResponse = xmlResponse; + + } + + /** + * Parse MOA-Sig signatur-verification result into + * {@link IXmlSignatureVerificationResponse}. + * + * @return {@link IXmlSignatureVerificationResponse} + * @throws MoaSigServiceException on any parsing error + */ + @NonNull + public IXmlSignatureVerificationResponse parseData() throws MoaSigServiceException { + try { + final VerifyXmlSignatureResponse respData = new VerifyXmlSignatureResponse(); + respData.setXmlDsigSubjectName( + XPathUtils.getElementValue(verifyXmlSignatureResponse, DSIG_SUBJECT_NAME_XPATH, "")); + final Element e = (Element) XPathUtils.selectSingleNode(verifyXmlSignatureResponse, + QUALIFIED_CERTIFICATE_XPATH); + respData.setQualifiedCertificate(e != null); + + final Base64InputStream in = new Base64InputStream(new ByteArrayInputStream( + XPathUtils.getElementValue(verifyXmlSignatureResponse, DSIG_X509_CERTIFICATE_XPATH, "") + .getBytes("UTF-8")), + true); + + respData.setX509CertificateEncoded(new X509Certificate(in).getEncoded()); + + final Element publicAuthority = + (Element) XPathUtils.selectSingleNode(verifyXmlSignatureResponse, PUBLIC_AUTHORITY_XPATH); + respData.setPublicAuthority(publicAuthority != null); + respData.setPublicAuthorityCode( + XPathUtils.getElementValue(verifyXmlSignatureResponse, PUBLIC_AUTHORITY_CODE_XPATH, "")); + respData.setSignatureCheckCode(Integer.parseInt( + XPathUtils.getElementValue(verifyXmlSignatureResponse, SIGNATURE_CHECK_CODE_XPATH, ""))); + + final String xmlDsigCheckCode = XPathUtils.getElementValue(verifyXmlSignatureResponse, + XMLDSIG_MANIFEST_CHECK_CODE_XPATH, null); + if (xmlDsigCheckCode != null) { + respData.setXmlDsigManigest(true); + respData.setXmlDsigManifestCheckCode(Integer.parseInt(xmlDsigCheckCode)); + + } else { + respData.setXmlDsigManigest(false); + + } + + final String signatureManifestCheckCode = XPathUtils + .getElementValue(verifyXmlSignatureResponse, SIGNATURE_MANIFEST_CHECK_CODE_XPATH, null); + if (signatureManifestCheckCode != null) { + respData.setSignatureManifestCheckCode(Integer.parseInt(signatureManifestCheckCode)); + + } + respData.setCertificateCheckCode(Integer.parseInt( + XPathUtils.getElementValue(verifyXmlSignatureResponse, CERTIFICATE_CHECK_CODE_XPATH, ""))); + + final String signingTimeElement = + XPathUtils.getElementValue(verifyXmlSignatureResponse, SIGNING_TIME_XPATH, ""); + if (signingTimeElement != null && !signingTimeElement.isEmpty()) { + final DateTime datetime = + ISODateTimeFormat.dateOptionalTimeParser().parseDateTime(signingTimeElement); + respData.setSigningDateTime(datetime.toDate()); + + } + + //TODO: parse extended validation results + + return respData; + + } catch (final Throwable t) { + log.warn("Can not parse MOA-Sig response.", t); + throw new MoaSigServiceParserException("service.moasig.02", new Object[] { t.toString() }, t); + } + + } + +} |