package at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl; import java.io.ByteArrayInputStream; import java.security.Provider; import java.security.Security; import java.security.cert.CertificateEncodingException; import java.util.List; import javax.annotation.PostConstruct; 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.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.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.data.ICMSSignatureVerificationResponse; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.data.IXMLSignatureVerificationResponse; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.exceptions.MOASigServiceBuilderException; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.exceptions.MOASigServiceConfigurationException; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.exceptions.MOASigServiceException; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.parser.VerifyXMLSignatureResponseParser; import at.gv.egovernment.moa.spss.MOAException; import at.gv.egovernment.moa.spss.api.Configurator; 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.moaspss.logging.LoggingContext; import at.gv.egovernment.moaspss.logging.LoggingContextManager; import at.gv.egovernment.moaspss.util.Constants; import iaik.asn1.structures.AlgorithmID; import iaik.security.ec.provider.ECCelerate; import iaik.security.provider.IAIK; /** * @author tlenz * */ @Service public class SignatureVerificationService 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 at.gv.egovernment.moa.spss.api.SignatureVerificationService svs; @PostConstruct private 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 ... "); Configurator.getInstance().init(); log.info("MOA-Sig library initialization complete "); } catch (final MOAException e) { log.error("MOA-SP initialization FAILED!", e.getWrapped()); throw new MOASigServiceConfigurationException("service.moasig.04", new Object[] { e .toString() }, e); } Security.insertProviderAt(IAIK.getInstance(), 0); final ECCelerate eccProvider = ECCelerate.getInstance(); if (Security.getProvider(eccProvider.getName()) != null) Security.removeProvider(eccProvider.getName()); Security.addProvider(new ECCelerate()); fixJava8_141ProblemWithSSLAlgorithms(); if (log.isDebugEnabled()) { log.debug("Loaded Security Provider:"); final Provider[] providerList = Security.getProviders(); for (int i=0; i 1) log.warn("CMS or CAdES signature contains more than one technical signatures. Only validate the first signature"); final VerifyCMSSignatureResponseElement firstSig = (VerifyCMSSignatureResponseElement) cmsSigVerifyResp.getResponseElements().get(0); final at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.data.VerifyCMSSignatureResponse result = new at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.data.VerifyCMSSignatureResponse(); //parse results into response container result.setSignatureCheckCode(firstSig.getSignatureCheck().getCode()); result.setCertificateCheckCode(firstSig.getCertificateCheck().getCode()); if (firstSig.getSignerInfo() != null) { result.setSigningDateTime(firstSig.getSignerInfo().getSigningTime()); result.setX509CertificateEncoded(firstSig.getSignerInfo().getSignerCertificate().getEncoded()); result.setQualifiedCertificate(firstSig.getSignerInfo().isQualifiedCertificate()); result.setPublicAuthority(firstSig.getSignerInfo().isPublicAuthority()); result.setPublicAuthorityCode(firstSig.getSignerInfo().getPublicAuhtorityID()); } else log.info("CMS or CAdES verification result contains no SignerInfo"); return result; } /* (non-Javadoc) * @see at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.ISignatureVerificationService#verifyXMLSignature(byte[], java.lang.String) */ @Override public IXMLSignatureVerificationResponse verifyXMLSignature(byte[] signature, String trustProfileID) throws MOASigServiceException { return verifyXMLSignature(signature, trustProfileID, null); } /* (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(byte[] signature, String trustProfileID, List verifyTransformsInfoProfileID) throws MOASigServiceException { try { //build signature-verification request final Element domVerifyXMLSignatureRequest = buildVerifyXMLRequest(signature, trustProfileID, verifyTransformsInfoProfileID); //send signature-verification to MOA-Sig final VerifyXMLSignatureRequest vsrequest = new VerifyXMLSignatureRequestParser().parse(domVerifyXMLSignatureRequest); final VerifyXMLSignatureResponse vsresponse = svs.verifyXMLSignature(vsrequest); final Document result = new VerifyXMLSignatureResponseBuilder(true).build(vsresponse); // parses the 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); } } /** * Build a VerifyCMS-Siganture request for MOA-Sig. *

* This builder only generates verification-request for enveloped CMS or CAdES signatures *
* 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(byte[] signature, String trustProfileID, boolean isPdfSignature, 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 * @return * @throws MOASigServiceBuilderException */ private Element buildVerifyXMLRequest(byte[] signature, String trustProfileID, List verifyTransformsInfoProfileID) 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 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(DSIG + "Signature"); verifySignatureLocationElem.appendChild(signatureLocation); // signature manifest params final Element signatureManifestCheckParamsElem = requestDoc_.createElementNS(MOA_NS_URI, "SignatureManifestCheckParams"); requestElem_.appendChild(signatureManifestCheckParamsElem); signatureManifestCheckParamsElem.setAttribute("ReturnReferenceInputData", "false"); //verify transformations if (verifyTransformsInfoProfileID != null && !verifyTransformsInfoProfileID.isEmpty()) { 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); 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); } } /** * 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 */ private synchronized Document getNewDocumentBuilder() throws ParserConfigurationException { final DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); return docBuilder.newDocument(); } 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"); } }