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 <InfoboxReadResponse> 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 <InfoboxReadResponse> 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 <InfoboxReadResponse> 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); } } }