package eu.europa.esig.dss.asic.validation;
import java.io.InputStream;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import eu.europa.esig.dss.DSSDocument;
import eu.europa.esig.dss.DigestAlgorithm;
import eu.europa.esig.dss.DomUtils;
import eu.europa.esig.dss.asic.ASiCNamespace;
import eu.europa.esig.dss.utils.Utils;
public class ASiCEWithCAdESManifestValidator {
private static final Logger LOG = LoggerFactory.getLogger(ASiCEWithCAdESManifestValidator.class);
static {
DomUtils.registerNamespace("asic", ASiCNamespace.NS);
}
private final DSSDocument signature;
private final List<DSSDocument> manifestDocuments;
private final List<DSSDocument> signedDocuments;
public ASiCEWithCAdESManifestValidator(DSSDocument signature, List<DSSDocument> manifestDocuments, List<DSSDocument> signedDocuments) {
this.signature = signature;
this.manifestDocuments = manifestDocuments;
this.signedDocuments = signedDocuments;
}
public DSSDocument getLinkedManifest() {
String expectedSignatureURI = signature.getName();
for (DSSDocument manifestDocument : manifestDocuments) {
InputStream is = null;
try {
is = manifestDocument.openStream();
Document manifestDom = DomUtils.buildDOM(is);
String signatureURI = DomUtils.getValue(manifestDom, ASiCNamespace.XPATH_ASIC_SIGREF_URL);
if (Utils.areStringsEqual(expectedSignatureURI, signatureURI) && checkManifestDigests(manifestDom)) {
return manifestDocument;
}
} catch (Exception e) {
LOG.warn("Unable to analyze manifest file '" + manifestDocument.getName() + "' : " + e.getMessage());
} finally {
Utils.closeQuietly(is);
}
}
return null;
}
private boolean checkManifestDigests(Document manifestDom) {
NodeList dataObjectReferences = DomUtils.getNodeList(manifestDom, ASiCNamespace.XPATH_ASIC_DATA_OBJECT_REFERENCE);
if (dataObjectReferences == null || dataObjectReferences.getLength() == 0) {
LOG.warn("No DataObjectReference found in manifest file");
return false;
} else {
for (int i = 0; i < dataObjectReferences.getLength(); i++) {
Element dataObjectReference = (Element) dataObjectReferences.item(i);
String filename = dataObjectReference.getAttribute("URI");
DSSDocument signedFile = getSignedFileByName(filename);
if (signedFile == null) {
LOG.warn("Signed data with name '{}' not found", filename);
return false;
}
DigestAlgorithm digestAlgo = getDigestAlgorithm(dataObjectReference);
if (digestAlgo == null) {
LOG.warn("Digest algo is not defined for signed data with name '{}'", filename);
return false;
}
String expectedDigestB64 = getDigestValue(dataObjectReference);
String computedDigestB64 = signedFile.getDigest(digestAlgo);
if (!Utils.areStringsEqual(expectedDigestB64, computedDigestB64)) {
LOG.warn("Digest value doesn't match for signed data with name '{}'", filename);
LOG.warn("Expected : '{}'", expectedDigestB64);
LOG.warn("Computed : '{}'", computedDigestB64);
return false;
}
}
}
return true;
}
private DSSDocument getSignedFileByName(String filename) {
for (DSSDocument signedDocument : signedDocuments) {
if (Utils.areStringsEqual(filename, signedDocument.getName())) {
return signedDocument;
}
}
return null;
}
private DigestAlgorithm getDigestAlgorithm(Element element) {
final String xmlName = DomUtils.getElement(element, "ds:DigestMethod").getAttribute("Algorithm");
return DigestAlgorithm.forXML(xmlName, null);
}
private String getDigestValue(Element element) {
Element digestValueElement = DomUtils.getElement(element, "ds:DigestValue");
if (digestValueElement != null) {
return digestValueElement.getTextContent();
}
return Utils.EMPTY_STRING;
}
}