diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureVerificationService.java')
-rw-r--r-- | eaaf_modules/eaaf_module_moa-sig/src/main/java/at/gv/egiz/eaaf/modules/sigverify/moasig/impl/SignatureVerificationService.java | 377 |
1 files changed, 377 insertions, 0 deletions
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..0818a260 --- /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,377 @@ +package at.gv.egiz.eaaf.modules.sigverify.moasig.impl; + +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateEncodingException; +import java.util.Date; +import java.util.List; + +import javax.annotation.PostConstruct; + +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.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.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; + +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; + +/** + * 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 { + try { + // setup context + setUpContexts(Thread.currentThread().getName()); + + // verify signature + final VerifyCMSSignatureRequest cmsSigVerifyReq = + buildVerfifyCmsRequest(signature, trustProfileID, false, false); + 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(); + + } + + } + + /* + * (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); + + } + + /* + * (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); + } + + /* + * (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); + } + + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(byte[] signature, String trustProfileID, + Date signingDate) throws MoaSigServiceException { + return verifyXmlSignature(signature, trustProfileID, null, + DEFAULT_XPATH_SIGNATURE_LOCATION, signingDate); + } + + @Override + public IXmlSignatureVerificationResponse verifyXmlSignature(final byte[] signature, + final String trustProfileID, final List<String> verifyTransformsInfoProfileID, + final String xpathSignatureLocation, Date signingDate) throws MoaSigServiceException { + try { + // setup context + setUpContexts(Thread.currentThread().getName()); + + // build signature-verification request + final Element domVerifyXmlSignatureRequest = buildVerifyXmlRequest(signature, trustProfileID, + verifyTransformsInfoProfileID, xpathSignatureLocation, signingDate); + + // 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"); + } + + final VerifyCMSSignatureResponseElement firstSig = + (VerifyCMSSignatureResponseElement) cmsSigVerifyResp.getResponseElements().get(0); + + final at.gv.egiz.eaaf.modules.sigverify.moasig.impl.data.VerifyCmsSignatureResponse result = + new at.gv.egiz.eaaf.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; + } + + /** + * 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 + * @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) 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); + + 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"); + + } + +} |