package at.gv.egiz.asic.impl.verifier; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.bind.JAXB; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; 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.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import at.gv.egiz.asic.ReferenceType; import at.gv.egiz.asic.SignatureType; import at.gv.egiz.asic.XAdESSignaturesType; import at.gv.egiz.asic.api.ASiC; import at.gv.egiz.asic.api.ASiCEntry; import at.gv.egiz.asic.api.ASiCFormat; import at.gv.egiz.asic.api.ASiCVerificationResult; import at.gv.egiz.asic.impl.AsicSignedFilesContainer; import at.gv.egovernment.moa.spss.MOAApplicationException; import at.gv.egovernment.moa.spss.MOAException; import at.gv.egovernment.moa.spss.MOARuntimeException; import at.gv.egovernment.moa.spss.MOASystemException; import at.gv.egovernment.moa.spss.api.SPSSFactory; import at.gv.egovernment.moa.spss.api.common.Content; import at.gv.egovernment.moa.spss.api.common.XMLDataObjectAssociation; import at.gv.egovernment.moa.spss.api.xmlverify.SupplementProfile; import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureInfo; import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureLocation; import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; import at.gv.egovernment.moa.spss.server.invoke.XMLSignatureVerificationInvoker; import at.gv.egovernment.moaspss.util.URLEncoder; /** * Created by Andreas Fitzek on 6/17/16. */ public class ExtendedXAdESVerifier extends XAdESVerifier { private static final Logger logger = LoggerFactory.getLogger(ExtendedXAdESVerifier.class); private void resetStream(InputStream is) { try { is.reset(); } catch (final IOException e) { throw new MOARuntimeException("Failed to reset inputStream", null, e); } } @Override public void verify(ASiC asic, String trustProfileID, Date date, List response) throws MOAException { try { final Iterator xadesSignatureIterator = asic.getSignaturesEntries().iterator(); while (xadesSignatureIterator.hasNext()) { final ASiCEntry xadesSignature = xadesSignatureIterator.next(); List xmlSignatures = null; // int signatureSize = 0; // TODO: support not only XAdESSignaturesType object 4.4.3.2 // XAdESSignaturesType xAdESSignaturesType = JAXB.unmarshal(xadesSignature.getContents(), XAdESSignaturesType.class); // signatureSize = xAdESSignaturesType.getSignature().size(); // this.resetStream(xadesSignature.getContents()); final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); dbFactory.setNamespaceAware(true); // dbFactory.setValidating(true); final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); final Document doc = dBuilder.parse(xadesSignature.getContents()); this.resetStream(xadesSignature.getContents()); final org.w3c.dom.Element rootElement = doc.getDocumentElement(); if ("http://www.w3.org/2000/09/xmldsig#".equals(rootElement.getNamespaceURI()) && "Signature".equals(rootElement.getTagName())) { final JAXBContext jc = JAXBContext.newInstance("at.gv.egiz.asic"); final JAXBElement xmlSignatureJaxb = jc.createUnmarshaller().unmarshal(rootElement, SignatureType.class); final SignatureType xmlSignature = xmlSignatureJaxb.getValue(); xmlSignatures = new ArrayList<>(); xmlSignatures.add(xmlSignature); } else if ("http://uri.etsi.org/02918/v1.2.1#".equals(rootElement.getNamespaceURI()) && "XAdESSignatures".equals(rootElement.getLocalName())) { final XAdESSignaturesType xAdESSignaturesType = JAXB.unmarshal(xadesSignature.getContents(), XAdESSignaturesType.class); xmlSignatures = xAdESSignaturesType.getSignature(); // TODO: maybe add additional XAdES version } else if ("http://uri.etsi.org/02918/v1.1.1#".equals(rootElement.getNamespaceURI()) && "XAdESSignatures".equals(rootElement.getLocalName())) { logger.warn( "ASiC v1.1.1 is not supported any more. MOA-SP only supports v1.2.1 (http://uri.etsi.org/02918/v1.2.1#)"); // XAdESSignaturesType xAdESSignaturesType = // JAXB.unmarshal(xadesSignature.getContents(), XAdESSignaturesType.class); // xmlSignatures = xAdESSignaturesType.getSignature(); } else { final NodeList childrenNodes = rootElement.getChildNodes(); for (int i = 0; i < childrenNodes.getLength(); i++) { final Node node = childrenNodes.item(i); final JAXBContext jc = JAXBContext.newInstance("at.gv.egiz.asic"); xmlSignatures = new ArrayList<>(); if ("http://www.w3.org/2000/09/xmldsig#".equals(node.getNamespaceURI()) && "Signature".equals(rootElement.getTagName())) { final JAXBElement xmlSignatureJaxb = jc.createUnmarshaller().unmarshal( rootElement, SignatureType.class); final SignatureType xmlSignature = xmlSignatureJaxb.getValue(); xmlSignatures.add(xmlSignature); } } } this.resetStream(xadesSignature.getContents()); final Map namespaces = new HashMap(); // namespaces.put("asic", "http://uri.etsi.org/02918/v1.2.1#"); namespaces.put("ds", "http://www.w3.org/2000/09/xmldsig#"); if (xmlSignatures == null || xmlSignatures.size() == 0) { logger.info("ASiC container does not include a signature or signature format is not supported"); throw new MOAApplicationException("asic.0016", null); } for (int i = 0; i < xmlSignatures.size(); i++) { // NodeList nodes = (NodeList) result; // for(int i = 0; i < nodes.getLength(); i++) { // Node node = nodes.item(i); // JAXBContext jc = JAXBContext.newInstance( "at.gv.egiz.asic" ); // JAXBElement xmlSignatureJaxb = // jc.createUnmarshaller().unmarshal(node, SignatureType.class); // SignatureType xmlSignature = xmlSignatureJaxb.getValue(); final List signedFiles = new ArrayList<>(); // Iterator it = // xmlSignature.getSignedInfo().getReference().iterator(); final Iterator it = xmlSignatures.get(i).getSignedInfo().getReference().iterator(); while (it.hasNext()) { final ReferenceType refType = it.next(); if (!refType.getURI().startsWith("#")) { signedFiles.add(new AsicSignedFilesContainer(refType.getURI(), refType.getDigestMethod() .getAlgorithm())); } } final Iterator dataEntryIterator = asic.getDataEntries().iterator(); final Content content = SPSSFactory.getInstance().createContent(xadesSignature.getContents(), null); final List supplementsList = new ArrayList(); while (dataEntryIterator.hasNext()) { final ASiCEntry dataEntry = dataEntryIterator.next(); dataEntry.getContents().reset(); final String entryName = URLEncoder.encode(dataEntry.getEntryName(), "UTF-8") .replaceAll("\\+", "%20") .replaceAll("\\%21", "!") .replaceAll("\\%2F", "/") // .replaceAll("\\%27", "'") // .replaceAll("\\%28", "(") // .replaceAll("\\%29", ")") .replaceAll("\\%7E", "~"); logger.info("Adding Entry : {}", entryName); final Content dataContent = SPSSFactory.getInstance().createContent(dataEntry.getContents(), entryName); final XMLDataObjectAssociation association = SPSSFactory.getInstance() .createXMLDataObjectAssociation(null, dataContent); final SupplementProfile profile = SPSSFactory.getInstance().createSupplementProfile(association); supplementsList.add(profile); } final String location = "(//ds:Signature)[" + (i + 1) + "]"; final VerifySignatureLocation verifySignatureLocation = SPSSFactory.getInstance() .createVerifySignatureLocation( location, namespaces); final VerifySignatureInfo verifySignatureInfo = SPSSFactory.getInstance().createVerifySignatureInfo( content, verifySignatureLocation); final VerifyXMLSignatureRequest verifyXMLSignatureRequest = SPSSFactory.getInstance() .createVerifyXMLSignatureRequest( date, verifySignatureInfo, supplementsList, null, false, trustProfileID, true); response.add(new ASiCVerificationResult(signedFiles, XMLSignatureVerificationInvoker.getInstance().verifyXMLSignature(verifyXMLSignatureRequest))); } } } catch (final UnsupportedEncodingException e) { logger.error("UTF8 encoding not supported by system. MOA will not work on this system!", e); throw new MOARuntimeException("asic.0003", null, e); } catch (final IOException ex) { throw new MOASystemException("asic.0003", null, ex); } catch (final ParserConfigurationException e) { throw new MOASystemException("asic.0003", null, e); } catch (final SAXException e) { throw new MOASystemException("asic.0003", null, e); } catch (final JAXBException e) { throw new MOASystemException("asic.0003", null, e); } } @Override public boolean handles(ASiC asic) { return super.handles(asic) && ASiCFormat.ASiCE.equals(asic.getFormat()); } }