public ValidationError DigestValueVerificationHandler(XmlDocument xmlDoc, string xmlFileName) { ValidationError validationError = new ValidationError(xmlFileName, null); if (!ValidationEnums.ReferenceTypeConstraints.Mappings.ContainsKey("ds:Manifest")) { return(validationError.AppendErrorMessage("Signature reference type was not found.")); } var referenceType = ValidationEnums.ReferenceTypeConstraints.Mappings["ds:Manifest"]; var referencesNodes = xmlDoc.SelectXmlNodes($"//ds:Signature/ds:SignedInfo/ds:Reference[@Type='{referenceType}']"); foreach (XmlNode refNode in referencesNodes) { string uriTarget = refNode.AtrValue("URI")?.Substring(1); var manifestNode = xmlDoc.SelectXmlNode($"//ds:Manifest[@Id='{uriTarget}']"); if (manifestNode == null) { return(validationError.AppendErrorMessage($"Couldnt find Manifest element with id : {uriTarget}.")); } // Reference digest method string digestAlgorithm = refNode.SelectXmlNode("//ds:DigestMethod")?.AtrValue("Algorithm"); if (!ValidationEnums.HashAlgorithms.SHAMappings.ContainsKey(digestAlgorithm)) { return(validationError.AppendErrorMessage($"Invalid digest method algorithm : {digestAlgorithm}")); } var transformNodes = refNode.SelectXmlNodes("ds:Transforms/ds:Transform"); // Should be only one algorithm (Canonicalization - omit comments) foreach (XmlNode transformNode in transformNodes) { string transformAlgorithm = transformNode.AtrValue("Algorithm"); if (transformAlgorithm != ValidationEnums.Canonicalization.CanonicalizationMethod) { return(validationError.AppendErrorMessage($"Invalid transform algorithm : {transformAlgorithm}")); } var outputArray = CanonicalizationHelper.CanonicalizeXmlDigest(manifestNode, ValidationEnums.HashAlgorithms.SHAMappings[digestAlgorithm]); string digestOutputBase64String = Convert.ToBase64String(outputArray); // Retrieve expected digest string xmlDigestValueBase64String = refNode.SelectXmlNode("ds:DigestValue")?.InnerText; if (digestOutputBase64String != xmlDigestValueBase64String) { return(validationError.AppendErrorMessage("Digest values do not match.")); } } } return(validationError); }
public ValidationError ValidateManifestReference(XmlDocument xmlDoc, string xmlFileName) { ValidationError validationError = new ValidationError(xmlFileName, null); XmlNodeList manifestReferences = xmlDoc.SelectXmlNodes("//ds:Signature/ds:Object/ds:Manifest/ds:Reference"); foreach (XmlNode manifestRef in manifestReferences) { var refURI = manifestRef.AtrValue("URI")?.Substring(1); XmlNode referencedObject = xmlDoc.SelectXmlNode($"ds:Object[@Id='{refURI}']"); if (referencedObject == null) { return(validationError.AppendErrorMessage("Referenced object does not exist")); } byte[] referencedElementByte = CanonicalizationHelper.CanonicalizeXml(referencedObject); string refStr = Encoding.UTF8.GetString(referencedElementByte); XmlNodeList transforms = manifestRef.SelectXmlNodes("ds:Transforms/ds:Transform"); string digestAlgo = manifestRef.SelectXmlNode("ds:DigestMethod")?.AtrValue("Algorithm"); string digestOutputBase64String = null; foreach (XmlNode transformEle in transforms) { string transformAlgo = transformEle.AtrValue("Algorithm"); if (transformAlgo == ValidationEnums.Canonicalization.CanonicalizationMethod) { var hashAlgo = ValidationEnums.HashAlgorithms.SHAMappings[digestAlgo]; var outputArray = CanonicalizationHelper.CanonicalizeXmlDigest(referencedObject, hashAlgo); digestOutputBase64String = Convert.ToBase64String(outputArray); } else if (transformAlgo == "http://www.w3.org/2000/09/xmldsig#base64") { digestOutputBase64String = Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(referencedElementByte))); } else { return(validationError.AppendErrorMessage($"Not supported transform algorithm : {transformAlgo}")); } string digestValue = manifestRef.SelectXmlNode("ds:DigestValue")?.InnerText; if (digestValue != digestOutputBase64String) { return(validationError.AppendErrorMessage($"ds:DigestValue values do not match {digestValue} <-> {digestOutputBase64String}")); } else { ; } } } return(validationError); }