package at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl; import java.io.ByteArrayInputStream; import java.security.cert.CertificateEncodingException; import java.util.List; 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.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.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.util.Constants; /** * @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 at.gv.egovernment.moa.spss.api.SignatureVerificationService svs; /* (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 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 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); } } @Override protected void internalInitializer() { log.debug("Instanzing SignatureVerificationService implementation ... "); svs = at.gv.egovernment.moa.spss.api.SignatureVerificationService.getInstance(); log.info("MOA-Sig signature-verification service initialized"); } }