diff options
author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-05-17 12:36:23 +0200 |
---|---|---|
committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-05-17 12:36:23 +0200 |
commit | 7070adf32df6534edfaf4e4217eb426158eb561d (patch) | |
tree | 7174116a6b6a1eb6e039d41b581ba04debd26760 /eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eid/authhandler/modules/sigverify/moasig/impl/SignatureVerificationService.java | |
parent | 99c8b69b8f5ad797b92b2a6be8f1b913ed975b71 (diff) | |
download | EAAF-Components-7070adf32df6534edfaf4e4217eb426158eb561d.tar.gz EAAF-Components-7070adf32df6534edfaf4e4217eb426158eb561d.tar.bz2 EAAF-Components-7070adf32df6534edfaf4e4217eb426158eb561d.zip |
add EAAF module for MOA-Sig integration
Diffstat (limited to 'eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eid/authhandler/modules/sigverify/moasig/impl/SignatureVerificationService.java')
-rw-r--r-- | eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eid/authhandler/modules/sigverify/moasig/impl/SignatureVerificationService.java | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eid/authhandler/modules/sigverify/moasig/impl/SignatureVerificationService.java b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eid/authhandler/modules/sigverify/moasig/impl/SignatureVerificationService.java new file mode 100644 index 00000000..b2ea5cb7 --- /dev/null +++ b/eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eid/authhandler/modules/sigverify/moasig/impl/SignatureVerificationService.java @@ -0,0 +1,348 @@ +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<providerList.length; i++) + log.debug(i + ": " + providerList[i].getName() + " Version " + providerList[i].getVersion()); + + } + + log.debug("Instanzing SignatureVerificationService implementation ... "); + svs = at.gv.egovernment.moa.spss.api.SignatureVerificationService.getInstance(); + + log.info("MOA-Sig signature-verification service initialized"); + } + + + + /* (non-Javadoc) + * @see at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.ISignatureVerificationService#verifyCMSSignature(byte[], java.lang.String) + */ + @Override + @Nullable + public ICMSSignatureVerificationResponse verifyCMSSignature(byte[] signature, String trustProfileID) throws MOASigServiceException { + try { + final VerifyCMSSignatureRequest cmsSigVerifyReq = buildVerfifyCMSRequest(signature, trustProfileID, false, false); + final VerifyCMSSignatureResponse cmsSigVerifyResp = svs.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); + + } + + } + + private ICMSSignatureVerificationResponse parseCMSVerificationResult(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"); + + 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<String> 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 <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); + + } + } + + /** + * 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(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<String> 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"); + } +} |