From 0951a2656073d847f492587d6101eec95c30301f Mon Sep 17 00:00:00 2001 From: Stefanos Doumpoulakis <dubulak@gmail.com> Date: Thu, 11 Jan 2024 14:00:35 +0200 Subject: [PATCH] Feat #258: VIF validation by hashing tool --- HashingTool/Helper/HashingHelper.cs | 13 +++++-- .../ViewModel/UserControl/VectoJobFile.cs | 11 +++++- VectoCommon/VectoHashing/VectoHash.cs | 35 ++++++++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/HashingTool/Helper/HashingHelper.cs b/HashingTool/Helper/HashingHelper.cs index 9d1f1db7b7..9a5c494a9d 100644 --- a/HashingTool/Helper/HashingHelper.cs +++ b/HashingTool/Helper/HashingHelper.cs @@ -80,11 +80,18 @@ namespace HashingTool.Helper if (x == null || x.DocumentElement == null) { return null; } - var valid = x.DocumentElement.LocalName == XMLNames.VectoInputDeclaration && - x.DocumentElement.FirstChild.LocalName == XMLNames.Component_Vehicle; + var validSingleStep = (x.DocumentElement.LocalName == XMLNames.VectoInputDeclaration && + x.DocumentElement.FirstChild.LocalName == XMLNames.Component_Vehicle); + + var validMultiStep = (x.DocumentElement.LocalName == XMLNames.VectoOutputMultistep && + x.DocumentElement.FirstChild.LocalName == XMLNames.Bus_PrimaryVehicle); + + var valid = validSingleStep || validMultiStep; + if (!valid) { errorLog.LogError($"Invalid XML file given ({x.DocumentElement.LocalName}/{x.DocumentElement.FirstChild.LocalName}). " + - $"Expected Vehicle XML ({XMLNames.VectoInputDeclaration}/{XMLNames.Component_Vehicle})!"); + $"Expected Vehicle XML ({XMLNames.VectoInputDeclaration}/{XMLNames.Component_Vehicle}) or " + + $"({XMLNames.VectoOutputMultistep}/{XMLNames.Bus_PrimaryVehicle}) !"); } return valid; } diff --git a/HashingTool/ViewModel/UserControl/VectoJobFile.cs b/HashingTool/ViewModel/UserControl/VectoJobFile.cs index c8f1a7a5ad..acb5c4df0b 100644 --- a/HashingTool/ViewModel/UserControl/VectoJobFile.cs +++ b/HashingTool/ViewModel/UserControl/VectoJobFile.cs @@ -37,6 +37,7 @@ using System.Xml; using HashingTool.Helper; using TUGraz.VectoCommon.Hashing; using TUGraz.VectoCommon.Resources; +using TUGraz.VectoCommon.Utils; using TUGraz.VectoHashing; using XmlDocumentType = TUGraz.VectoCore.Utils.XmlDocumentType; @@ -51,7 +52,8 @@ namespace HashingTool.ViewModel.UserControl public VectoJobFile(string name, Func<XmlDocument, IErrorLogger, bool?> contentCheck, - Action<XmlDocument, VectoXMLFile> hashValidation = null) : base(name, true, contentCheck, XmlDocumentType.DeclarationJobData, hashValidation) + Action<XmlDocument, VectoXMLFile> hashValidation = null) : + base(name, true, contentCheck, XmlDocumentType.DeclarationJobData | XmlDocumentType.MultistepOutputData, hashValidation) { _xmlFile.PropertyChanged += JobFilechanged; Components = new ObservableCollection<ComponentEntry>(); @@ -176,6 +178,13 @@ namespace HashingTool.ViewModel.UserControl entry.Component = component.Count == 1 ? component.Entry.XMLElementName() : $"{component.Entry.XMLElementName()} ({i + 1})"; + + if (entry.Component.IsOneOf(XMLNames.Bus_PrimaryVehicle, XMLNames.ManufacturingStep) + || !h.ElementIsSigned(component.Entry, i)) { + + continue; + } + entry.Valid = h.ValidateHash(component.Entry, i); entry.CanonicalizationMethod = h.GetCanonicalizationMethods(component.Entry, i).ToArray(); entry.DigestMethod = h.GetDigestMethod(component.Entry, i); diff --git a/VectoCommon/VectoHashing/VectoHash.cs b/VectoCommon/VectoHashing/VectoHash.cs index 83cd73763e..4a371f543e 100644 --- a/VectoCommon/VectoHashing/VectoHash.cs +++ b/VectoCommon/VectoHashing/VectoHash.cs @@ -110,11 +110,13 @@ namespace TUGraz.VectoHashing public IList<VectoComponents> GetContainigComponents() { var retVal = new List<VectoComponents>(); + var rootName = Document.FirstChild.NextSibling.LocalName; + foreach (var component in EnumHelper.GetValues<VectoComponents>()) { // special treatment for REESS: can be either supercap or multiple batteries where the component node may contain several sub-components var select = component == VectoComponents.ElectricEnergyStorage - ? $"//*[local-name()='{XMLNames.VectoInputDeclaration}']//*[local-name()='{component.XMLElementName()}' or local-name()='Capacitor']//*[local-name()='Data']" - : $"//*[local-name()='{XMLNames.VectoInputDeclaration}']//*[local-name()='{component.XMLElementName()}']"; + ? $"//*[local-name()='{rootName}']//*[local-name()='{component.XMLElementName()}' or local-name()='Capacitor']//*[local-name()='Data']" + : $"//*[local-name()='{rootName}']//*[local-name()='{component.XMLElementName()}']"; var nodes = Document.SelectNodes(select); var count = nodes?.Count ?? 0; for (var i = 0; i < count; i++) { @@ -137,7 +139,10 @@ namespace TUGraz.VectoHashing public string ComputeHash(IEnumerable<string> canonicalization = null, string digestMethod = null) { - var nodes = Document.SelectNodes(GetComponentQueryString()); + var isMultiStep = (Document.ChildNodes.Count > 0) + && Document.ChildNodes[1].ChildNodes.Cast<XmlNode>().Any(x => x.LocalName == XMLNames.ManufacturingStep); + + var nodes = Document.SelectNodes(GetComponentQueryString(null, isMultiStep)); if (nodes == null || nodes.Count == 0) { throw new Exception("No component found"); } @@ -420,12 +425,32 @@ namespace TUGraz.VectoHashing ComputeHash(component, index)); } + public bool ElementIsSigned(VectoComponents component, int index = 0) + { + var nodes = GetNodes(component, index); + + var parent = nodes[index].ParentNode; + if (parent == null) { + throw new Exception("Invalid structure of input XML!"); + } + + if (nodes[index].Attributes[XMLNames.Component_ID_Attr] == null) { + return false; + } + + var elementToHash = nodes[index].Attributes[XMLNames.Component_ID_Attr].Value; + var nodesDV = parent.SelectNodes(".//*[@URI='#" + elementToHash + "']/*[local-name() = 'DigestValue']"); + + return (nodesDV != null && nodesDV.Count > 0); + } - protected static string GetComponentQueryString(VectoComponents? component = null) + protected static string GetComponentQueryString(VectoComponents? component = null, bool isMultiStep = false) { switch (component) { case null: - return "(//*[@id])[1]"; + return isMultiStep + ? $"//*[local-name()='{XMLNames.ManufacturingStep}']/*[local-name()='Data']" + : "(//*[@id])[1]"; case VectoComponents.Vehicle: return $"//*[local-name()='{component.Value.XMLElementName()}']"; case VectoComponents.ElectricEnergyStorage: -- GitLab