// XadesSignedXml.cs // // XAdES Starter Kit for Microsoft .NET 3.5 (and above) // 2010 Microsoft France // Published under the CECILL-B Free Software license agreement. // (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt) // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, // WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. // THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE // AND INFORMATION REMAINS WITH THE USER. using System; using System.Collections; using System.Globalization; using System.IO; using System.Reflection; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; using System.Xml; using System.Xml.Schema; namespace Microsoft.Xades { /// /// Types of signature standards that can be contained in XadesSignedXml class instance /// public enum KnownSignatureStandard { /// /// XML Digital Signature (XMLDSIG) /// XmlDsig, /// /// XML Advanced Electronic Signature (XAdES) /// Xades } /// /// Bitmasks to indicate which checks need to be executed on the XAdES signature /// [FlagsAttribute] public enum XadesCheckSignatureMasks : ulong { /// /// Check the signature of the underlying XMLDSIG signature /// CheckXmldsigSignature = 0x01, /// /// Validate the XML representation of the signature against the XAdES and XMLDSIG schemas /// ValidateAgainstSchema = 0x02, /// /// Check to see if first XMLDSIG certificate has same hashvalue as first XAdES SignatureCertificate /// CheckSameCertificate = 0x04, /// /// Check if there is a HashDataInfo for each reference if there is a AllDataObjectsTimeStamp /// CheckAllReferencesExistInAllDataObjectsTimeStamp = 0x08, /// /// Check if the HashDataInfo of each IndividualDataObjectsTimeStamp points to existing Reference /// CheckAllHashDataInfosInIndividualDataObjectsTimeStamp = 0x10, /// /// Perform XAdES checks on contained counter signatures /// CheckCounterSignatures = 0x20, /// /// Counter signatures should all contain a reference to the parent signature SignatureValue element /// CheckCounterSignaturesReference = 0x40, /// /// Check if each ObjectReference in CommitmentTypeIndication points to Reference element /// CheckObjectReferencesInCommitmentTypeIndication = 0x80, /// /// Check if at least ClaimedRoles or CertifiedRoles present in SignerRole /// CheckIfClaimedRolesOrCertifiedRolesPresentInSignerRole = 0x0100, /// /// Check if HashDataInfo of SignatureTimeStamp points to SignatureValue /// CheckHashDataInfoOfSignatureTimeStampPointsToSignatureValue = 0x0200, /// /// Check if the QualifyingProperties Target attribute points to the signature element /// CheckQualifyingPropertiesTarget = 0x0400, /// /// Check that QualifyingProperties occur in one Object, check that there is only one QualifyingProperties and that signed properties occur in one QualifyingProperties element /// CheckQualifyingProperties = 0x0800, /// /// Check if all required HashDataInfos are present on SigAndRefsTimeStamp /// CheckSigAndRefsTimeStampHashDataInfos = 0x1000, /// /// Check if all required HashDataInfos are present on RefsOnlyTimeStamp /// CheckRefsOnlyTimeStampHashDataInfos = 0x2000, /// /// Check if all required HashDataInfos are present on ArchiveTimeStamp /// CheckArchiveTimeStampHashDataInfos = 0x4000, /// /// Check if a XAdES-C signature is also a XAdES-T signature /// CheckXadesCIsXadesT = 0x8000, /// /// Check if a XAdES-XL signature is also a XAdES-X signature /// CheckXadesXLIsXadesX = 0x010000, /// /// Check if CertificateValues match CertificateRefs /// CheckCertificateValuesMatchCertificateRefs = 0x020000, /// /// Check if RevocationValues match RevocationRefs /// CheckRevocationValuesMatchRevocationRefs = 0x040000, /// /// Do all known tests on XAdES signature /// AllChecks = 0xFFFFFF } /// /// Facade class for the XAdES signature library. The class inherits from /// the System.Security.Cryptography.Xml.SignedXml class and is backwards /// compatible with it, so this class can host xmldsig signatures and XAdES /// signatures. The property SignatureStandard will indicate the type of the /// signature: XMLDSIG or XAdES. /// public class XadesSignedXml : System.Security.Cryptography.Xml.SignedXml { #region Constants /// /// The XAdES XML namespace URI /// public const string XadesNamespaceUri = "http://uri.etsi.org/01903/v1.3.2#"; /// /// Mandated type name for the Uri reference to the SignedProperties element /// // TODO: Проверить комментарий //public const string SignedPropertiesType = "http://uri.etsi.org/01903/v1.3.2#SignedProperties"; public const string SignedPropertiesType = "http://uri.etsi.org/01903#SignedProperties"; #endregion #region Private variables private static readonly string[] idAttrs = new string[] { "_id", "_Id", "_ID", "id", "Id", "ID", "iD" }; private KnownSignatureStandard signatureStandard; private XmlDocument cachedXadesObjectDocument; private string signedPropertiesIdBuffer; private string signatureValueId; private bool validationErrorOccurred; private string validationErrorDescription; // TODO: Проверить комментарий //private string signedInfoIdBuffer = null; #endregion #region Public properties /// /// Property indicating the type of signature (XmlDsig or XAdES) /// public KnownSignatureStandard SignatureStandard { get { return this.signatureStandard; } } /// /// Read-only property containing XAdES information /// public XadesObject XadesObject { get { XadesObject retVal = new XadesObject(); retVal.LoadXml(this.GetXadesObjectElement(this.GetXml()), this.GetXml()); return retVal; } } /// /// Setting this property will add an ID attribute to the SignatureValue element. /// This is required when constructing a XAdES-T signature. /// public string SignatureValueId { get { return this.signatureValueId; } set { this.signatureValueId = value; } } /// /// This property allows to access and modify the unsigned properties /// after the XAdES object has been added to the signature. /// Because the unsigned properties are part of a location in the /// signature that is not used when computing the signature, it is save /// to modify them even after the XMLDSIG signature has been computed. /// This is needed when XAdES objects that depend on the XMLDSIG /// signature value need to be added to the signature. The /// SignatureTimeStamp element is such a property, it can only be /// created when the XMLDSIG signature has been computed. /// public UnsignedProperties UnsignedProperties { get { XmlElement dataObjectXmlElement; System.Security.Cryptography.Xml.DataObject xadesDataObject; XmlNamespaceManager xmlNamespaceManager; XmlNodeList xmlNodeList; UnsignedProperties retVal; retVal = new UnsignedProperties(); xadesDataObject = this.GetXadesDataObject(); if (xadesDataObject != null) { dataObjectXmlElement = xadesDataObject.GetXml(); xmlNamespaceManager = new XmlNamespaceManager(dataObjectXmlElement.OwnerDocument.NameTable); xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri); xmlNodeList = dataObjectXmlElement.SelectNodes("xsd:QualifyingProperties/xsd:UnsignedProperties", xmlNamespaceManager); if (xmlNodeList.Count != 0) { retVal = new UnsignedProperties(); retVal.LoadXml((XmlElement)xmlNodeList[0], (XmlElement)xmlNodeList[0]); } } else { throw new CryptographicException("XAdES object not found. Use AddXadesObject() before accessing UnsignedProperties."); } return retVal; } set { XmlElement dataObjectXmlElement = null; System.Security.Cryptography.Xml.DataObject xadesDataObject, newXadesDataObject; XmlNamespaceManager xmlNamespaceManager; XmlNodeList qualifyingPropertiesXmlNodeList; XmlNodeList unsignedPropertiesXmlNodeList; xadesDataObject = this.GetXadesDataObject(); if (xadesDataObject != null) { dataObjectXmlElement = xadesDataObject.GetXml(); xmlNamespaceManager = new XmlNamespaceManager(dataObjectXmlElement.OwnerDocument.NameTable); xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri); qualifyingPropertiesXmlNodeList = dataObjectXmlElement.SelectNodes("xsd:QualifyingProperties", xmlNamespaceManager); unsignedPropertiesXmlNodeList = dataObjectXmlElement.SelectNodes("xsd:QualifyingProperties/xsd:UnsignedProperties", xmlNamespaceManager); if (unsignedPropertiesXmlNodeList.Count != 0) { qualifyingPropertiesXmlNodeList[0].RemoveChild(unsignedPropertiesXmlNodeList[0]); } qualifyingPropertiesXmlNodeList[0].AppendChild(dataObjectXmlElement.OwnerDocument.ImportNode(value.GetXml(), true)); newXadesDataObject = new DataObject(); newXadesDataObject.LoadXml(dataObjectXmlElement); xadesDataObject.Data = newXadesDataObject.Data; } else { throw new CryptographicException("XAdES object not found. Use AddXadesObject() before accessing UnsignedProperties."); } } } /// /// This property contains xml document node id, /// which will be singed by XAdES /// public string SignedElementId { get; set; } #endregion #region Constructors /// /// Default constructor for the XadesSignedXml class /// public XadesSignedXml() : base() { this.cachedXadesObjectDocument = null; this.signatureStandard = KnownSignatureStandard.XmlDsig; } /// /// Constructor for the XadesSignedXml class /// /// XmlElement used to create the instance public XadesSignedXml(XmlElement signatureElement) : base(signatureElement) { this.cachedXadesObjectDocument = null; } /// /// Constructor for the XadesSignedXml class /// /// XmlDocument used to create the instance public XadesSignedXml(System.Xml.XmlDocument signatureDocument) : base(signatureDocument) { this.cachedXadesObjectDocument = null; } /// /// Constructor for the XadesSignedXml class /// /// XmlDocument used to create the instance /// XmlDocument signed node identifier public XadesSignedXml(System.Xml.XmlDocument signatureDocument, string signedElementId) : base(signatureDocument) { this.cachedXadesObjectDocument = null; this.SignedElementId = signedElementId; } #endregion #region Public methods /// /// Load state from an XML element /// /// The XML element from which to load the XadesSignedXml state public new void LoadXml(System.Xml.XmlElement xmlElement) { this.cachedXadesObjectDocument = null; this.signatureValueId = null; base.LoadXml(xmlElement); XmlNode idAttribute = xmlElement.Attributes.GetNamedItem("Id"); if (idAttribute != null) { this.Signature.Id = idAttribute.Value; } this.SetSignatureStandard(xmlElement); XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlElement.OwnerDocument.NameTable); xmlNamespaceManager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); XmlNodeList xmlNodeList = xmlElement.SelectNodes("ds:SignatureValue", xmlNamespaceManager); if (xmlNodeList.Count > 0) { if (((XmlElement)xmlNodeList[0]).HasAttribute("Id")) { this.signatureValueId = ((XmlElement)xmlNodeList[0]).Attributes["Id"].Value; } } } /// /// Returns the XML representation of the this object /// /// XML element containing the state of this object public new XmlElement GetXml() { XmlElement retVal; XmlNodeList xmlNodeList; XmlNamespaceManager xmlNamespaceManager; retVal = base.GetXml(); if (this.signatureValueId != null && this.signatureValueId != "") { //Id on Signature value is needed for XAdES-T. We inject it here. xmlNamespaceManager = new XmlNamespaceManager(retVal.OwnerDocument.NameTable); xmlNamespaceManager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); xmlNodeList = retVal.SelectNodes("ds:SignatureValue", xmlNamespaceManager); if (xmlNodeList.Count > 0) { ((XmlElement)xmlNodeList[0]).SetAttribute("Id", this.signatureValueId); } } // Add "ds" namespace prefix to all XmlDsig nodes in the signature SetPrefix("ds", retVal); return retVal; } /// /// Overridden virtual method to be able to find the nested SignedProperties /// element inside of the XAdES object /// /// Document in which to find the Id /// Value of the Id to look for /// XmlElement with requested Id public override XmlElement GetIdElement(XmlDocument xmlDocument, string idValue) { XmlElement retVal = base.GetIdElement(xmlDocument, idValue); if (retVal != null) return retVal; foreach (var customId in idAttrs) { var found = xmlDocument.SelectSingleNode("//*[@" + customId + "=\"" + idValue + "\"]") as XmlElement; if (found != null) { return found; } } if (Signature != null && Signature.SignedInfo != null && Signature.SignatureValue != null) { var signature = new XmlDocument(); signature.AppendChild(signature.ImportNode(Signature.GetXml(), true)); signature.DocumentElement.SetAttribute("xmlns:ds", SignedXml.XmlDsigNamespaceUrl); retVal = base.GetIdElement(signature, idValue); if (retVal != null) { return retVal; } // If not, search for custom ids foreach (string idAttr in idAttrs) { retVal = signature.SelectSingleNode("//*[@" + idAttr + "=\"" + idValue + "\"]") as XmlElement; if (retVal != null) { return retVal; } } } if (idValue == this.signedPropertiesIdBuffer) { var xmlDocumentCloned = new XmlDocument(); xmlDocumentCloned.LoadXml(xmlDocument.OuterXml); var signedDataContainer = this.GetIdElement(xmlDocumentCloned, SignedElementId); signedDataContainer.InsertBefore(xmlDocumentCloned.ImportNode(cachedXadesObjectDocument.DocumentElement, true), signedDataContainer.FirstChild); // TODO: Проверить комментарий //xmlDocumentCloned.DocumentElement.AppendChild(xmlDocumentCloned.ImportNode(cachedXadesObjectDocument.DocumentElement, true)); retVal = base.GetIdElement(xmlDocumentCloned, idValue); if (retVal != null) { return retVal; } // If not, search for custom ids foreach (string idAttr in idAttrs) { retVal = this.cachedXadesObjectDocument.SelectSingleNode("//*[@" + idAttr + "=\"" + idValue + "\"]") as XmlElement; if (retVal != null) { break; } } } else { if (xmlDocument != null) { retVal = base.GetIdElement(xmlDocument, idValue); if (retVal != null) { return retVal; } // If not, search for custom ids foreach (string idAttr in idAttrs) { retVal = xmlDocument.SelectSingleNode("//*[@" + idAttr + "=\"" + idValue + "\"]") as XmlElement; if (retVal != null) { break; } } } } return retVal; } /// /// Add a XAdES object to the signature /// /// XAdES object to add to signature public void AddXadesObject(XadesObject xadesObject) { Reference reference; DataObject dataObject; XmlElement bufferXmlElement; if (this.SignatureStandard != KnownSignatureStandard.Xades) { dataObject = new DataObject(); dataObject.Id = xadesObject.Id; dataObject.Data = xadesObject.GetXml().ChildNodes; this.AddObject(dataObject); reference = new Reference(); reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#gostr3411"; signedPropertiesIdBuffer = xadesObject.QualifyingProperties.SignedProperties.Id; reference.Uri = "#" + signedPropertiesIdBuffer; reference.Type = SignedPropertiesType; this.AddReference(reference); this.cachedXadesObjectDocument = new XmlDocument(); bufferXmlElement = xadesObject.GetXml(); // Add "ds" namespace prefix to all XmlDsig nodes in the XAdES object SetPrefix("ds", bufferXmlElement); this.cachedXadesObjectDocument.PreserveWhitespace = true; this.cachedXadesObjectDocument.LoadXml(bufferXmlElement.OuterXml); this.signatureStandard = KnownSignatureStandard.Xades; } else { throw new CryptographicException("Can't add XAdES object, the signature already contains a XAdES object"); } } /// /// Additional tests for XAdES signatures. These tests focus on /// XMLDSIG verification and correct form of the XAdES XML structure /// (schema validation and completeness as defined by the XAdES standard). /// /// /// Because of the fact that the XAdES library is intentionally /// independent of standards like TSP (RFC3161) or OCSP (RFC2560), /// these tests do NOT include any verification of timestamps nor OCSP /// responses. /// These checks are important and have to be done in the application /// built on top of the XAdES library. /// /// Thrown when the signature is not /// a XAdES signature. SignatureStandard should be equal to /// KnownSignatureStandard.Xades. /// Use the CheckSignature method for non-XAdES signatures. /// Bitmask to indicate which /// tests need to be done. This function will call a public virtual /// methods for each bit that has been set in this mask. /// See the XadesCheckSignatureMasks /// enum for the bitmask definitions. The virtual test method associated /// with a bit in the mask has the same name as enum value name. /// If the function returns true the check was OK. If the /// check fails an exception with a explanatory message is thrown. public bool XadesCheckSignature(XadesCheckSignatureMasks xadesCheckSignatureMasks) { bool retVal; retVal = true; if (this.SignatureStandard != KnownSignatureStandard.Xades) { throw new Exception("SignatureStandard is not XAdES. CheckSignature returned: " + this.CheckSignature()); } else { if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckXmldsigSignature) != 0) { retVal &= this.CheckXmldsigSignature(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.ValidateAgainstSchema) != 0) { retVal &= this.ValidateAgainstSchema(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckSameCertificate) != 0) { retVal &= this.CheckSameCertificate(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckAllReferencesExistInAllDataObjectsTimeStamp) != 0) { retVal &= this.CheckAllReferencesExistInAllDataObjectsTimeStamp(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckAllHashDataInfosInIndividualDataObjectsTimeStamp) != 0) { retVal &= this.CheckAllHashDataInfosInIndividualDataObjectsTimeStamp(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckCounterSignatures) != 0) { retVal &= this.CheckCounterSignatures(xadesCheckSignatureMasks); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckCounterSignaturesReference) != 0) { retVal &= this.CheckCounterSignaturesReference(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckObjectReferencesInCommitmentTypeIndication) != 0) { retVal &= this.CheckObjectReferencesInCommitmentTypeIndication(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckIfClaimedRolesOrCertifiedRolesPresentInSignerRole) != 0) { retVal &= this.CheckIfClaimedRolesOrCertifiedRolesPresentInSignerRole(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckHashDataInfoOfSignatureTimeStampPointsToSignatureValue) != 0) { retVal &= this.CheckHashDataInfoOfSignatureTimeStampPointsToSignatureValue(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckQualifyingPropertiesTarget) != 0) { retVal &= this.CheckQualifyingPropertiesTarget(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckQualifyingProperties) != 0) { retVal &= this.CheckQualifyingProperties(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckSigAndRefsTimeStampHashDataInfos) != 0) { retVal &= this.CheckSigAndRefsTimeStampHashDataInfos(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckRefsOnlyTimeStampHashDataInfos) != 0) { retVal &= this.CheckRefsOnlyTimeStampHashDataInfos(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckArchiveTimeStampHashDataInfos) != 0) { retVal &= this.CheckArchiveTimeStampHashDataInfos(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckXadesCIsXadesT) != 0) { retVal &= this.CheckXadesCIsXadesT(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckXadesXLIsXadesX) != 0) { retVal &= this.CheckXadesXLIsXadesX(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckCertificateValuesMatchCertificateRefs) != 0) { retVal &= this.CheckCertificateValuesMatchCertificateRefs(); } if ((xadesCheckSignatureMasks & XadesCheckSignatureMasks.CheckRevocationValuesMatchRevocationRefs) != 0) { retVal &= this.CheckRevocationValuesMatchRevocationRefs(); } } return retVal; } #region XadesCheckSignature routines /// /// Check the signature of the underlying XMLDSIG signature /// /// If the function returns true the check was OK public virtual bool CheckXmldsigSignature() { bool retVal = false; // TODO: Проверить комментарий //KeyInfo keyInfo = new KeyInfo(); //X509Certificate xmldsigCert = new X509Certificate(System.Text.Encoding.ASCII.GetBytes(this.KeyInfo.GetXml().InnerText)); //keyInfo.AddClause(new KeyInfoX509Data(xmldsigCert)); //this.KeyInfo = keyInfo; retVal = this.CheckSignature(); if (retVal == false) { throw new CryptographicException("CheckXmldsigSignature() failed"); } return retVal; } /// /// Validate the XML representation of the signature against the XAdES and XMLDSIG schemas /// /// If the function returns true the check was OK public virtual bool ValidateAgainstSchema() { bool retValue = false; Assembly assembly = Assembly.GetExecutingAssembly(); XmlSchemaSet schemaSet = new XmlSchemaSet(); XmlSchema xmlSchema; Stream schemaStream; NameTable xadesNameTable; XmlNamespaceManager xmlNamespaceManager; XmlParserContext xmlParserContext; this.validationErrorOccurred = false; this.validationErrorDescription = ""; try { schemaStream = assembly.GetManifestResourceStream("Microsoft.Xades.xmldsig-core-schema.xsd"); xmlSchema = XmlSchema.Read(schemaStream, new ValidationEventHandler(this.SchemaValidationHandler)); schemaSet.Add(xmlSchema); schemaStream.Close(); schemaStream = assembly.GetManifestResourceStream("Microsoft.Xades.XAdES.xsd"); xmlSchema = XmlSchema.Read(schemaStream, new ValidationEventHandler(this.SchemaValidationHandler)); schemaSet.Add(xmlSchema); schemaStream.Close(); if (this.validationErrorOccurred) { throw new CryptographicException("Schema read validation error: " + this.validationErrorDescription); } } catch (Exception exception) { throw new CryptographicException("Problem during access of validation schemas", exception); } XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); xmlReaderSettings.ValidationEventHandler += new ValidationEventHandler(this.XmlValidationHandler); xmlReaderSettings.ValidationType = ValidationType.Schema; xmlReaderSettings.Schemas = schemaSet; xmlReaderSettings.ConformanceLevel = ConformanceLevel.Auto; xadesNameTable = new NameTable(); xmlNamespaceManager = new XmlNamespaceManager(xadesNameTable); xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri); xmlParserContext = new XmlParserContext(null, xmlNamespaceManager, null, XmlSpace.None); XmlTextReader txtReader = new XmlTextReader(this.GetXml().OuterXml, XmlNodeType.Element, xmlParserContext); XmlReader reader = XmlReader.Create(txtReader, xmlReaderSettings); try { while (reader.Read()) ; if (this.validationErrorOccurred) { throw new CryptographicException("Schema validation error: " + this.validationErrorDescription); } } catch (Exception exception) { throw new CryptographicException("Schema validation error", exception); } finally { reader.Close(); } retValue = true; return retValue; } /// /// Check to see if first XMLDSIG certificate has same hashvalue as first XAdES SignatureCertificate /// /// If the function returns true the check was OK public virtual bool CheckSameCertificate() { bool retVal = false; // TODO: Проверить комментарий //KeyInfoX509Data keyInfoX509Data = new KeyInfoX509Data(); //keyInfoX509Data.LoadXml(this.KeyInfo.GetXml()); //if (keyInfoX509Data.Certificates.Count <= 0) //{ // throw new CryptographicException("Certificate not found in XMLDSIG signature while doing CheckSameCertificate()"); //} //string xmldsigCertHash = Convert.ToBase64String(((X509Certificate)keyInfoX509Data.Certificates[0]).GetCertHash()); X509Certificate xmldsigCert = new X509Certificate(System.Text.Encoding.ASCII.GetBytes(this.KeyInfo.GetXml().InnerText)); string xmldsigCertHash = Convert.ToBase64String(xmldsigCert.GetCertHash()); CertCollection xadesSigningCertificateCollection = this.XadesObject.QualifyingProperties.SignedProperties.SignedSignatureProperties.SigningCertificate.CertCollection; if (xadesSigningCertificateCollection.Count <= 0) { throw new CryptographicException("Certificate not found in SigningCertificate element while doing CheckSameCertificate()"); } string xadesCertHash = Convert.ToBase64String(((Cert)xadesSigningCertificateCollection[0]).CertDigest.DigestValue); if (String.Compare(xmldsigCertHash, xadesCertHash, true, CultureInfo.InvariantCulture) != 0) { throw new CryptographicException("Certificate in XMLDSIG signature doesn't match certificate in SigningCertificate element"); } retVal = true; return retVal; } /// /// Check if there is a HashDataInfo for each reference if there is a AllDataObjectsTimeStamp /// /// If the function returns true the check was OK public virtual bool CheckAllReferencesExistInAllDataObjectsTimeStamp() { AllDataObjectsTimeStampCollection allDataObjectsTimeStampCollection; bool allHashDataInfosExist; TimeStamp timeStamp; int timeStampCounter; bool retVal; allHashDataInfosExist = true; retVal = false; allDataObjectsTimeStampCollection = this.XadesObject.QualifyingProperties.SignedProperties.SignedDataObjectProperties.AllDataObjectsTimeStampCollection; if (allDataObjectsTimeStampCollection.Count > 0) { for (timeStampCounter = 0; allHashDataInfosExist && (timeStampCounter < allDataObjectsTimeStampCollection.Count); timeStampCounter++) { timeStamp = allDataObjectsTimeStampCollection[timeStampCounter]; allHashDataInfosExist &= this.CheckHashDataInfosForTimeStamp(timeStamp); } if (!allHashDataInfosExist) { throw new CryptographicException("At least one HashDataInfo is missing in AllDataObjectsTimeStamp element"); } } retVal = true; return retVal; } /// /// Check if the HashDataInfo of each IndividualDataObjectsTimeStamp points to existing Reference /// /// If the function returns true the check was OK public virtual bool CheckAllHashDataInfosInIndividualDataObjectsTimeStamp() { IndividualDataObjectsTimeStampCollection individualDataObjectsTimeStampCollection; bool hashDataInfoExists; TimeStamp timeStamp; int timeStampCounter; bool retVal; hashDataInfoExists = true; retVal = false; individualDataObjectsTimeStampCollection = this.XadesObject.QualifyingProperties.SignedProperties.SignedDataObjectProperties.IndividualDataObjectsTimeStampCollection; if (individualDataObjectsTimeStampCollection.Count > 0) { for (timeStampCounter = 0; hashDataInfoExists && (timeStampCounter < individualDataObjectsTimeStampCollection.Count); timeStampCounter++) { timeStamp = individualDataObjectsTimeStampCollection[timeStampCounter]; hashDataInfoExists &= this.CheckHashDataInfosExist(timeStamp); } if (hashDataInfoExists == false) { throw new CryptographicException("At least one HashDataInfo is pointing to non-existing reference in IndividualDataObjectsTimeStamp element"); } } retVal = true; return retVal; } /// /// Perform XAdES checks on contained counter signatures. If couter signature is XMLDSIG, only XMLDSIG check (CheckSignature()) is done. /// /// Check mask applied to counter signatures /// If the function returns true the check was OK public virtual bool CheckCounterSignatures(XadesCheckSignatureMasks counterSignatureMask) { CounterSignatureCollection counterSignatureCollection; XadesSignedXml counterSignature; bool retVal; retVal = true; counterSignatureCollection = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties.CounterSignatureCollection; for (int counterSignatureCounter = 0; (retVal == true) && (counterSignatureCounter < counterSignatureCollection.Count); counterSignatureCounter++) { counterSignature = counterSignatureCollection[counterSignatureCounter]; if (counterSignature.signatureStandard == KnownSignatureStandard.Xades) { retVal &= counterSignature.XadesCheckSignature(counterSignatureMask); } else { retVal &= counterSignature.CheckSignature(); } } if (retVal == false) { throw new CryptographicException("XadesCheckSignature() failed on at least one counter signature"); } retVal = true; return retVal; } /// /// Counter signatures should all contain a reference to the parent signature SignatureValue element /// /// If the function returns true the check was OK public virtual bool CheckCounterSignaturesReference() { CounterSignatureCollection counterSignatureCollection; XadesSignedXml counterSignature; string referenceUri; ArrayList parentSignatureValueChain; bool referenceToParentSignatureFound; bool retVal; retVal = true; parentSignatureValueChain = new ArrayList(); parentSignatureValueChain.Add("#" + this.signatureValueId); counterSignatureCollection = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties.CounterSignatureCollection; for (int counterSignatureCounter = 0; (retVal == true) && (counterSignatureCounter < counterSignatureCollection.Count); counterSignatureCounter++) { counterSignature = counterSignatureCollection[counterSignatureCounter]; referenceToParentSignatureFound = false; for (int referenceCounter = 0; referenceToParentSignatureFound == false && (referenceCounter < counterSignature.SignedInfo.References.Count); referenceCounter++) { referenceUri = ((Reference)counterSignature.SignedInfo.References[referenceCounter]).Uri; if (parentSignatureValueChain.BinarySearch(referenceUri) >= 0) { referenceToParentSignatureFound = true; } parentSignatureValueChain.Add("#" + counterSignature.SignatureValueId); parentSignatureValueChain.Sort(); } retVal = referenceToParentSignatureFound; } if (retVal == false) { throw new CryptographicException("CheckCounterSignaturesReference() failed on at least one counter signature"); } retVal = true; return retVal; } /// /// Check if each ObjectReference in CommitmentTypeIndication points to Reference element /// /// If the function returns true the check was OK public virtual bool CheckObjectReferencesInCommitmentTypeIndication() { CommitmentTypeIndicationCollection commitmentTypeIndicationCollection; CommitmentTypeIndication commitmentTypeIndication; bool objectReferenceOK; bool retVal; retVal = true; commitmentTypeIndicationCollection = this.XadesObject.QualifyingProperties.SignedProperties.SignedDataObjectProperties.CommitmentTypeIndicationCollection; if (commitmentTypeIndicationCollection.Count > 0) { for (int commitmentTypeIndicationCounter = 0; (retVal == true) && (commitmentTypeIndicationCounter < commitmentTypeIndicationCollection.Count); commitmentTypeIndicationCounter++) { commitmentTypeIndication = commitmentTypeIndicationCollection[commitmentTypeIndicationCounter]; objectReferenceOK = true; foreach (ObjectReference objectReference in commitmentTypeIndication.ObjectReferenceCollection) { objectReferenceOK &= this.CheckObjectReference(objectReference); } retVal = objectReferenceOK; } if (retVal == false) { throw new CryptographicException("At least one ObjectReference in CommitmentTypeIndication did not point to a Reference"); } } return retVal; } /// /// Check if at least ClaimedRoles or CertifiedRoles present in SignerRole /// /// If the function returns true the check was OK public virtual bool CheckIfClaimedRolesOrCertifiedRolesPresentInSignerRole() { SignerRole signerRole; bool retVal; retVal = false; signerRole = this.XadesObject.QualifyingProperties.SignedProperties.SignedSignatureProperties.SignerRole; if (signerRole != null) { if (signerRole.CertifiedRoles != null) { retVal = (signerRole.CertifiedRoles.CertifiedRoleCollection.Count > 0); } if (retVal == false) { if (signerRole.ClaimedRoles != null) { retVal = (signerRole.ClaimedRoles.ClaimedRoleCollection.Count > 0); } } if (retVal == false) { throw new CryptographicException("SignerRole element must contain at least one CertifiedRole or ClaimedRole element"); } } else { retVal = true; } return retVal; } /// /// Check if HashDataInfo of SignatureTimeStamp points to SignatureValue /// /// If the function returns true the check was OK public virtual bool CheckHashDataInfoOfSignatureTimeStampPointsToSignatureValue() { SignatureTimeStampCollection signatureTimeStampCollection; bool hashDataInfoPointsToSignatureValue; TimeStamp timeStamp; int timeStampCounter; bool retVal; hashDataInfoPointsToSignatureValue = true; retVal = false; signatureTimeStampCollection = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties.SignatureTimeStampCollection; if (signatureTimeStampCollection.Count > 0) { for (timeStampCounter = 0; hashDataInfoPointsToSignatureValue && (timeStampCounter < signatureTimeStampCollection.Count); timeStampCounter++) { timeStamp = signatureTimeStampCollection[timeStampCounter]; hashDataInfoPointsToSignatureValue &= this.CheckHashDataInfoPointsToSignatureValue(timeStamp); } if (hashDataInfoPointsToSignatureValue == false) { throw new CryptographicException("HashDataInfo of SignatureTimeStamp doesn't point to signature value element"); } } retVal = true; return retVal; } /// /// Check if the QualifyingProperties Target attribute points to the signature element /// /// If the function returns true the check was OK public virtual bool CheckQualifyingPropertiesTarget() { string qualifyingPropertiesTarget; bool retVal; retVal = true; qualifyingPropertiesTarget = this.XadesObject.QualifyingProperties.Target; if (this.Signature.Id == null) { retVal = false; } else { if (qualifyingPropertiesTarget != ("#" + this.Signature.Id)) { retVal = false; } } if (retVal == false) { throw new CryptographicException("Qualifying properties target doesn't point to signature element or signature element doesn't have an Id"); } return retVal; } /// /// Check that QualifyingProperties occur in one Object, check that there is only one QualifyingProperties and that signed properties occur in one QualifyingProperties element /// /// If the function returns true the check was OK public virtual bool CheckQualifyingProperties() { XmlElement signatureElement; XmlNamespaceManager xmlNamespaceManager; XmlNodeList xmlNodeList; signatureElement = this.GetXml(); xmlNamespaceManager = new XmlNamespaceManager(signatureElement.OwnerDocument.NameTable); xmlNamespaceManager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri); xmlNodeList = signatureElement.SelectNodes("ds:Object/xsd:QualifyingProperties", xmlNamespaceManager); if (xmlNodeList.Count > 1) { throw new CryptographicException("More than one Object contains a QualifyingProperties element"); } return true; } /// /// Check if all required HashDataInfos are present on SigAndRefsTimeStamp /// /// If the function returns true the check was OK public virtual bool CheckSigAndRefsTimeStampHashDataInfos() { SignatureTimeStampCollection signatureTimeStampCollection; TimeStamp timeStamp; bool allRequiredhashDataInfosFound; bool retVal; retVal = true; signatureTimeStampCollection = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties.SigAndRefsTimeStampCollection; if (signatureTimeStampCollection.Count > 0) { allRequiredhashDataInfosFound = true; for (int timeStampCounter = 0; allRequiredhashDataInfosFound && (timeStampCounter < signatureTimeStampCollection.Count); timeStampCounter++) { timeStamp = signatureTimeStampCollection[timeStampCounter]; allRequiredhashDataInfosFound &= this.CheckHashDataInfosOfSigAndRefsTimeStamp(timeStamp); } if (allRequiredhashDataInfosFound == false) { throw new CryptographicException("At least one required HashDataInfo is missing in a SigAndRefsTimeStamp element"); } } return retVal; } /// /// Check if all required HashDataInfos are present on RefsOnlyTimeStamp /// /// If the function returns true the check was OK public virtual bool CheckRefsOnlyTimeStampHashDataInfos() { SignatureTimeStampCollection signatureTimeStampCollection; TimeStamp timeStamp; bool allRequiredhashDataInfosFound; bool retVal; retVal = true; signatureTimeStampCollection = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties.RefsOnlyTimeStampCollection; if (signatureTimeStampCollection.Count > 0) { allRequiredhashDataInfosFound = true; for (int timeStampCounter = 0; allRequiredhashDataInfosFound && (timeStampCounter < signatureTimeStampCollection.Count); timeStampCounter++) { timeStamp = signatureTimeStampCollection[timeStampCounter]; allRequiredhashDataInfosFound &= this.CheckHashDataInfosOfRefsOnlyTimeStamp(timeStamp); } if (allRequiredhashDataInfosFound == false) { throw new CryptographicException("At least one required HashDataInfo is missing in a RefsOnlyTimeStamp element"); } } return retVal; } /// /// Check if all required HashDataInfos are present on ArchiveTimeStamp /// /// If the function returns true the check was OK public virtual bool CheckArchiveTimeStampHashDataInfos() { SignatureTimeStampCollection signatureTimeStampCollection; TimeStamp timeStamp; bool allRequiredhashDataInfosFound; bool retVal; retVal = true; signatureTimeStampCollection = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties.ArchiveTimeStampCollection; if (signatureTimeStampCollection.Count > 0) { allRequiredhashDataInfosFound = true; for (int timeStampCounter = 0; allRequiredhashDataInfosFound && (timeStampCounter < signatureTimeStampCollection.Count); timeStampCounter++) { timeStamp = signatureTimeStampCollection[timeStampCounter]; allRequiredhashDataInfosFound &= this.CheckHashDataInfosOfArchiveTimeStamp(timeStamp); } if (allRequiredhashDataInfosFound == false) { throw new CryptographicException("At least one required HashDataInfo is missing in a ArchiveTimeStamp element"); } } return retVal; } /// /// Check if a XAdES-C signature is also a XAdES-T signature /// /// If the function returns true the check was OK public virtual bool CheckXadesCIsXadesT() { UnsignedSignatureProperties unsignedSignatureProperties; bool retVal; retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; if (((unsignedSignatureProperties.CompleteCertificateRefs != null) && (unsignedSignatureProperties.CompleteCertificateRefs.HasChanged())) || ((unsignedSignatureProperties.CompleteCertificateRefs != null) && (unsignedSignatureProperties.CompleteCertificateRefs.HasChanged()))) { if (unsignedSignatureProperties.SignatureTimeStampCollection.Count == 0) { throw new CryptographicException("XAdES-C signature should also contain a SignatureTimeStamp element"); } } return retVal; } /// /// Check if a XAdES-XL signature is also a XAdES-X signature /// /// If the function returns true the check was OK public virtual bool CheckXadesXLIsXadesX() { UnsignedSignatureProperties unsignedSignatureProperties; bool retVal; retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; if (((unsignedSignatureProperties.CertificateValues != null) && (unsignedSignatureProperties.CertificateValues.HasChanged())) || ((unsignedSignatureProperties.RevocationValues != null) && (unsignedSignatureProperties.RevocationValues.HasChanged()))) { if ((unsignedSignatureProperties.SigAndRefsTimeStampCollection.Count == 0) && (unsignedSignatureProperties.RefsOnlyTimeStampCollection.Count == 0)) { throw new CryptographicException("XAdES-XL signature should also contain a XAdES-X element"); } } return retVal; } /// /// Check if CertificateValues match CertificateRefs /// /// If the function returns true the check was OK public virtual bool CheckCertificateValuesMatchCertificateRefs() { SHA1Managed sha1Managed; UnsignedSignatureProperties unsignedSignatureProperties; ArrayList certDigests; byte[] certDigest; int index; bool retVal; retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; if ((unsignedSignatureProperties.CompleteCertificateRefs != null) && (unsignedSignatureProperties.CompleteCertificateRefs.CertRefs != null) && (unsignedSignatureProperties.CertificateValues != null)) { certDigests = new ArrayList(); foreach (Cert cert in unsignedSignatureProperties.CompleteCertificateRefs.CertRefs.CertCollection) { certDigests.Add(Convert.ToBase64String(cert.CertDigest.DigestValue)); } certDigests.Sort(); foreach (EncapsulatedX509Certificate encapsulatedX509Certificate in unsignedSignatureProperties.CertificateValues.EncapsulatedX509CertificateCollection) { sha1Managed = new SHA1Managed(); certDigest = sha1Managed.ComputeHash(encapsulatedX509Certificate.PkiData); index = certDigests.BinarySearch(Convert.ToBase64String(certDigest)); if (index >= 0) { certDigests.RemoveAt(index); } } if (certDigests.Count != 0) { throw new CryptographicException("Not all CertificateRefs correspond to CertificateValues"); } } return retVal; } /// /// Check if RevocationValues match RevocationRefs /// /// If the function returns true the check was OK public virtual bool CheckRevocationValuesMatchRevocationRefs() { SHA1Managed sha1Managed; UnsignedSignatureProperties unsignedSignatureProperties; ArrayList crlDigests; byte[] crlDigest; int index; bool retVal; retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; if ((unsignedSignatureProperties.CompleteRevocationRefs != null) && (unsignedSignatureProperties.CompleteRevocationRefs.CRLRefs != null) && (unsignedSignatureProperties.RevocationValues != null)) { crlDigests = new ArrayList(); foreach (CRLRef crlRef in unsignedSignatureProperties.CompleteRevocationRefs.CRLRefs.CRLRefCollection) { crlDigests.Add(Convert.ToBase64String(crlRef.CertDigest.DigestValue)); } crlDigests.Sort(); foreach (CRLValue crlValue in unsignedSignatureProperties.RevocationValues.CRLValues.CRLValueCollection) { sha1Managed = new SHA1Managed(); crlDigest = sha1Managed.ComputeHash(crlValue.PkiData); index = crlDigests.BinarySearch(Convert.ToBase64String(crlDigest)); if (index >= 0) { crlDigests.RemoveAt(index); } } if (crlDigests.Count != 0) { throw new CryptographicException("Not all RevocationRefs correspond to RevocationValues"); } } return retVal; } #endregion #endregion #region Fix to add a namespace prefix for all XmlDsig nodes private void SetPrefix(String prefix, XmlNode node) { if (node.NamespaceURI == SignedXml.XmlDsigNamespaceUrl) { node.Prefix = prefix; } foreach (XmlNode child in node.ChildNodes) { SetPrefix(prefix, child); } return; } /// /// Copy of System.Security.Cryptography.Xml.SignedXml.ComputeSignature() which will end up calling /// our own GetC14NDigest with a namespace prefix for all XmlDsig nodes /// public new void ComputeSignature() { AsymmetricAlgorithm signingKey = this.SigningKey; if (signingKey == null) { throw new CryptographicException("Cryptography_Xml_LoadKeyFailed"); } if (this.SignedInfo.SignatureMethod == null) { if (!(signingKey is DSA)) { if (!(signingKey is RSA)) { throw new CryptographicException("Cryptography_Xml_CreatedKeyFailed"); } if (this.SignedInfo.SignatureMethod == null) { this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; } } else { this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; } } HashAlgorithm hash; var description = GetSignedInfoHash(out hash); // this.m_signature.SignatureValue = description.CreateFormatter(signingKey).CreateSignature(hash); } private HashAlgorithm signedInfoHash = null; /// /// Calculates standalone SignedInfo hash /// /// /// /// public SignatureDescription GetSignedInfoHash(out HashAlgorithm hash) { SignatureDescription description; if (signedInfoHash != null) { description = CryptoConfig.CreateFromName(this.SignedInfo.SignatureMethod) as SignatureDescription; hash = signedInfoHash; return description; } this.BuildDigestedReferences(); description = CryptoConfig.CreateFromName(this.SignedInfo.SignatureMethod) as SignatureDescription; if (description == null) { throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated"); } hash = description.CreateDigest(); if (hash == null) { throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed"); } this.GetC14NDigest(hash, "ds"); this.signedInfoHash = hash; return description; } /// /// Copy of System.Security.Cryptography.Xml.SignedXml.BuildDigestedReferences() which will add a "ds" /// namespace prefix to all XmlDsig nodes /// private void BuildDigestedReferences() { ArrayList references = this.SignedInfo.References; // TODO: Проверить комментарий //this.m_refProcessed = new bool[references.Count]; Type SignedXml_Type = typeof(SignedXml); FieldInfo SignedXml_m_refProcessed = SignedXml_Type.GetField("m_refProcessed", BindingFlags.NonPublic | BindingFlags.Instance); SignedXml_m_refProcessed.SetValue(this, new bool[references.Count]); // TODO: Проверить комментарий //this.m_refLevelCache = new int[references.Count]; FieldInfo SignedXml_m_refLevelCache = SignedXml_Type.GetField("m_refLevelCache", BindingFlags.NonPublic | BindingFlags.Instance); SignedXml_m_refLevelCache.SetValue(this, new int[references.Count]); // TODO: Проверить комментарий //ReferenceLevelSortOrder comparer = new ReferenceLevelSortOrder(); Assembly System_Security_Assembly = Assembly.Load("System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); Type ReferenceLevelSortOrder_Type = System_Security_Assembly.GetType("System.Security.Cryptography.Xml.SignedXml+ReferenceLevelSortOrder"); ConstructorInfo ReferenceLevelSortOrder_Constructor = ReferenceLevelSortOrder_Type.GetConstructor(new Type[] { }); Object comparer = ReferenceLevelSortOrder_Constructor.Invoke(null); // TODO: Проверить комментарий //comparer.References = references; PropertyInfo ReferenceLevelSortOrder_References = ReferenceLevelSortOrder_Type.GetProperty("References", BindingFlags.Public | BindingFlags.Instance); ReferenceLevelSortOrder_References.SetValue(comparer, references, null); // ArrayList list2 = new ArrayList(); foreach (Reference reference in references) { list2.Add(reference); } list2.Sort((IComparer)comparer); // TODO: Проверить комментарий //CanonicalXmlNodeList refList = new CanonicalXmlNodeList(); Type CanonicalXmlNodeList_Type = System_Security_Assembly.GetType("System.Security.Cryptography.Xml.CanonicalXmlNodeList"); ConstructorInfo CanonicalXmlNodeList_Constructor = CanonicalXmlNodeList_Type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null); Object refList = CanonicalXmlNodeList_Constructor.Invoke(null); MethodInfo CanonicalXmlNodeList_Add = CanonicalXmlNodeList_Type.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance); foreach (DataObject obj2 in this.m_signature.ObjectList) { // TODO: Проверить комментарий //refList.Add(obj2.GetXml()); XmlElement xml = obj2.GetXml(); SetPrefix("ds", xml); CanonicalXmlNodeList_Add.Invoke(refList, new object[] { xml }); } FieldInfo SignedXml_m_containingDocument = SignedXml_Type.GetField("m_containingDocument", BindingFlags.NonPublic | BindingFlags.Instance); Type Reference_Type = typeof(Reference); MethodInfo Reference_UpdateHashValue = Reference_Type.GetMethod("UpdateHashValue", BindingFlags.NonPublic | BindingFlags.Instance); foreach (Reference reference2 in list2) { if (reference2.DigestMethod == null) { // TODO: Проверить комментарий //reference2.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1"; reference2.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#gostr3411"; } // TODO: Проверить комментарий //reference2.UpdateHashValue(this.m_containingDocument, refList); object m_containingDocument = SignedXml_m_containingDocument.GetValue(this); Reference_UpdateHashValue.Invoke(reference2, new object[] { m_containingDocument, refList }); if (reference2.Id != null) { // TODO: Проверить комментарий //refList.Add(reference2.GetXml()); XmlElement xml = reference2.GetXml(); SetPrefix("ds", xml); CanonicalXmlNodeList_Add.Invoke(refList, new object[] { xml }); } } } /// /// We won't call System.Security.Cryptography.Xml.SignedXml.GetC14NDigest(), as we want to use our own /// private byte[] GetC14NDigest(HashAlgorithm hash) { return null; } /// /// Copy of System.Security.Cryptography.Xml.SignedXml.GetC14NDigest() which will add a /// namespace prefix to all XmlDsig nodes /// private byte[] GetC14NDigest(HashAlgorithm hash, string prefix) { // TODO: Проверить комментарий //if (!this.bCacheValid || !this.SignedInfo.CacheValid) //{ Type SignedXml_Type = typeof(SignedXml); FieldInfo SignedXml_bCacheValid = SignedXml_Type.GetField("bCacheValid", BindingFlags.NonPublic | BindingFlags.Instance); bool bCacheValid = (bool)SignedXml_bCacheValid.GetValue(this); Type SignedInfo_Type = typeof(SignedInfo); PropertyInfo SignedInfo_CacheValid = SignedInfo_Type.GetProperty("CacheValid", BindingFlags.NonPublic | BindingFlags.Instance); bool CacheValid = (bool)SignedInfo_CacheValid.GetValue(this.SignedInfo, null); FieldInfo SignedXml__digestedSignedInfo = SignedXml_Type.GetField("_digestedSignedInfo", BindingFlags.NonPublic | BindingFlags.Instance); if (!bCacheValid || !CacheValid) { // TODO: Проверить комментарий //string securityUrl = (this.m_containingDocument == null) ? null : this.m_containingDocument.BaseURI; FieldInfo SignedXml_m_containingDocument = SignedXml_Type.GetField("m_containingDocument", BindingFlags.NonPublic | BindingFlags.Instance); XmlDocument m_containingDocument = (XmlDocument)SignedXml_m_containingDocument.GetValue(this); string securityUrl = (m_containingDocument == null) ? null : m_containingDocument.BaseURI; // TODO: Проверить комментарий //XmlResolver xmlResolver = this.m_bResolverSet ? this.m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), securityUrl); FieldInfo SignedXml_m_bResolverSet = SignedXml_Type.GetField("m_bResolverSet", BindingFlags.NonPublic | BindingFlags.Instance); bool m_bResolverSet = (bool)SignedXml_m_bResolverSet.GetValue(this); FieldInfo SignedXml_m_xmlResolver = SignedXml_Type.GetField("m_xmlResolver", BindingFlags.NonPublic | BindingFlags.Instance); XmlResolver m_xmlResolver = (XmlResolver)SignedXml_m_xmlResolver.GetValue(this); XmlResolver xmlResolver = m_bResolverSet ? m_xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), securityUrl); // TODO: Проверить комментарий //XmlDocument document = Utils.PreProcessElementInput(this.SignedInfo.GetXml(), xmlResolver, securityUrl); Assembly System_Security_Assembly = Assembly.Load("System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); Type Utils_Type = System_Security_Assembly.GetType("System.Security.Cryptography.Xml.Utils"); MethodInfo Utils_PreProcessElementInput = Utils_Type.GetMethod("PreProcessElementInput", BindingFlags.NonPublic | BindingFlags.Static); XmlElement xml = this.SignedInfo.GetXml(); SetPrefix(prefix, xml); XmlDocument document = (XmlDocument)Utils_PreProcessElementInput.Invoke(null, new object[] { xml, xmlResolver, securityUrl }); // TODO: Проверить комментарий //CanonicalXmlNodeList namespaces = (this.m_context == null) ? null : Utils.GetPropagatedAttributes(this.m_context); //FieldInfo SignedXml_m_context = SignedXml_Type.GetField("m_context", BindingFlags.NonPublic | BindingFlags.Instance); MethodInfo Utils_GetPropagatedAttributes = Utils_Type.GetMethod("GetPropagatedAttributes", BindingFlags.NonPublic | BindingFlags.Static); var xmlDocumentCloned = new XmlDocument(); xmlDocumentCloned.LoadXml(m_containingDocument.OuterXml); var signedDataContainer = GetIdElement(xmlDocumentCloned, SignedElementId); signedDataContainer.InsertBefore(xmlDocumentCloned.ImportNode(document.DocumentElement, true), signedDataContainer.FirstChild); object namespaces = Utils_GetPropagatedAttributes.Invoke(null, new object[] { signedDataContainer.FirstChild }); // TODO: Проверить комментарий //object m_context = SignedXml_m_context.GetValue(this); //object namespaces = (m_context == null) ? null : Utils_GetPropagatedAttributes.Invoke(null, new object[] { m_context }); // TODO: Проверить комментарий // Utils.AddNamespaces(document.DocumentElement, namespaces); Type CanonicalXmlNodeList_Type = System_Security_Assembly.GetType("System.Security.Cryptography.Xml.CanonicalXmlNodeList"); MethodInfo Utils_AddNamespaces = Utils_Type.GetMethod("AddNamespaces", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(XmlElement), CanonicalXmlNodeList_Type }, null); Utils_AddNamespaces.Invoke(null, new object[] { document.DocumentElement, namespaces }); // TODO: Проверить комментарий //Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject; System.Security.Cryptography.Xml.Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject; canonicalizationMethodObject.Resolver = xmlResolver; // TODO: Проверить комментарий //canonicalizationMethodObject.BaseURI = securityUrl; Type Transform_Type = typeof(System.Security.Cryptography.Xml.Transform); PropertyInfo Transform_BaseURI = Transform_Type.GetProperty("BaseURI", BindingFlags.NonPublic | BindingFlags.Instance); Transform_BaseURI.SetValue(canonicalizationMethodObject, securityUrl, null); canonicalizationMethodObject.LoadInput(document); // TODO: Проверить комментарий //this._digestedSignedInfo = canonicalizationMethodObject.GetDigestedOutput(hash); SignedXml__digestedSignedInfo.SetValue(this, canonicalizationMethodObject.GetDigestedOutput(hash)); // TODO: Проверить комментарий //this.bCacheValid = true; SignedXml_bCacheValid.SetValue(this, true); } // TODO: Проверить комментарий //return this._digestedSignedInfo; byte[] _digestedSignedInfo = (byte[])SignedXml__digestedSignedInfo.GetValue(this); return _digestedSignedInfo; } #endregion #region Private methods protected XmlElement GetXadesObjectElement(XmlElement signatureElement) { XmlElement retVal = null; XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(signatureElement.OwnerDocument.NameTable); //Create an XmlNamespaceManager to resolve namespace xmlNamespaceManager.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri); XmlNodeList xmlNodeList = signatureElement.SelectNodes("ds:Object/xsd:QualifyingProperties", xmlNamespaceManager); if (xmlNodeList.Count > 0) { retVal = (XmlElement)xmlNodeList.Item(0).ParentNode; } else { retVal = null; } return retVal; } private void SetSignatureStandard(XmlElement signatureElement) { if (this.GetXadesObjectElement(signatureElement) != null) { this.signatureStandard = KnownSignatureStandard.Xades; } else { this.signatureStandard = KnownSignatureStandard.XmlDsig; } } private System.Security.Cryptography.Xml.DataObject GetXadesDataObject() { System.Security.Cryptography.Xml.DataObject retVal = null; for (int dataObjectCounter = 0; dataObjectCounter < (this.Signature.ObjectList.Count); dataObjectCounter++) { System.Security.Cryptography.Xml.DataObject dataObject = (System.Security.Cryptography.Xml.DataObject)this.Signature.ObjectList[dataObjectCounter]; XmlElement dataObjectXmlElement = dataObject.GetXml(); XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(dataObjectXmlElement.OwnerDocument.NameTable); xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri); XmlNodeList xmlNodeList = dataObjectXmlElement.SelectNodes("xsd:QualifyingProperties", xmlNamespaceManager); if (xmlNodeList.Count != 0) { retVal = dataObject; break; } } return retVal; } private void SchemaValidationHandler(object sender, ValidationEventArgs validationEventArgs) { this.validationErrorOccurred = true; this.validationErrorDescription += "Validation error:\n"; this.validationErrorDescription += "\tSeverity: " + validationEventArgs.Severity.ToString() + "\n"; this.validationErrorDescription += "\tMessage: " + validationEventArgs.Message + "\n"; } private void XmlValidationHandler(object sender, ValidationEventArgs validationEventArgs) { if (validationEventArgs.Severity != XmlSeverityType.Warning) { this.validationErrorOccurred = true; this.validationErrorDescription += "Validation error:\n"; this.validationErrorDescription += "\tSeverity: " + validationEventArgs.Severity.ToString() + "\n"; this.validationErrorDescription += "\tMessage: " + validationEventArgs.Message + "\n"; } } private bool CheckHashDataInfosForTimeStamp(TimeStamp timeStamp) { bool retVal = true; for (int referenceCounter = 0; retVal == true && (referenceCounter < this.SignedInfo.References.Count); referenceCounter++) { string referenceId = ((Reference)this.SignedInfo.References[referenceCounter]).Id; string referenceUri = ((Reference)this.SignedInfo.References[referenceCounter]).Uri; if (referenceUri != ("#" + this.XadesObject.QualifyingProperties.SignedProperties.Id)) { bool hashDataInfoFound = false; for (int hashDataInfoCounter = 0; hashDataInfoFound == false && (hashDataInfoCounter < timeStamp.HashDataInfoCollection.Count); hashDataInfoCounter++) { HashDataInfo hashDataInfo = timeStamp.HashDataInfoCollection[hashDataInfoCounter]; hashDataInfoFound = (("#" + referenceId) == hashDataInfo.UriAttribute); } retVal = hashDataInfoFound; } } return retVal; } private bool CheckHashDataInfosExist(TimeStamp timeStamp) { bool retVal = true; for (int hashDataInfoCounter = 0; retVal == true && (hashDataInfoCounter < timeStamp.HashDataInfoCollection.Count); hashDataInfoCounter++) { HashDataInfo hashDataInfo = timeStamp.HashDataInfoCollection[hashDataInfoCounter]; bool referenceFound = false; string referenceId; for (int referenceCounter = 0; referenceFound == false && (referenceCounter < this.SignedInfo.References.Count); referenceCounter++) { referenceId = ((Reference)this.SignedInfo.References[referenceCounter]).Id; if (("#" + referenceId) == hashDataInfo.UriAttribute) { referenceFound = true; } } retVal = referenceFound; } return retVal; } private bool CheckObjectReference(ObjectReference objectReference) { bool retVal = false; for (int referenceCounter = 0; retVal == false && (referenceCounter < this.SignedInfo.References.Count); referenceCounter++) { string referenceId = ((Reference)this.SignedInfo.References[referenceCounter]).Id; if (("#" + referenceId) == objectReference.ObjectReferenceUri) { retVal = true; } } return retVal; } private bool CheckHashDataInfoPointsToSignatureValue(TimeStamp timeStamp) { bool retVal = true; foreach (HashDataInfo hashDataInfo in timeStamp.HashDataInfoCollection) { retVal &= (hashDataInfo.UriAttribute == ("#" + this.signatureValueId)); } return retVal; } private bool CheckHashDataInfosOfSigAndRefsTimeStamp(TimeStamp timeStamp) { UnsignedSignatureProperties unsignedSignatureProperties; bool signatureValueHashDataInfoFound = false; bool allSignatureTimeStampHashDataInfosFound = false; bool completeCertificateRefsHashDataInfoFound = false; bool completeRevocationRefsHashDataInfoFound = false; ArrayList signatureTimeStampIds = new ArrayList(); bool retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; foreach (TimeStamp signatureTimeStamp in unsignedSignatureProperties.SignatureTimeStampCollection) { signatureTimeStampIds.Add("#" + signatureTimeStamp.EncapsulatedTimeStamp.Id); } signatureTimeStampIds.Sort(); foreach (HashDataInfo hashDataInfo in timeStamp.HashDataInfoCollection) { if (hashDataInfo.UriAttribute == "#" + this.signatureValueId) { signatureValueHashDataInfoFound = true; } int signatureTimeStampIdIndex = signatureTimeStampIds.BinarySearch(hashDataInfo.UriAttribute); if (signatureTimeStampIdIndex >= 0) { signatureTimeStampIds.RemoveAt(signatureTimeStampIdIndex); } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CompleteCertificateRefs.Id) { completeCertificateRefsHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CompleteRevocationRefs.Id) { completeRevocationRefsHashDataInfoFound = true; } } if (signatureTimeStampIds.Count == 0) { allSignatureTimeStampHashDataInfosFound = true; } retVal = signatureValueHashDataInfoFound && allSignatureTimeStampHashDataInfosFound && completeCertificateRefsHashDataInfoFound && completeRevocationRefsHashDataInfoFound; return retVal; } private bool CheckHashDataInfosOfRefsOnlyTimeStamp(TimeStamp timeStamp) { UnsignedSignatureProperties unsignedSignatureProperties; bool completeCertificateRefsHashDataInfoFound; bool completeRevocationRefsHashDataInfoFound; bool retVal; completeCertificateRefsHashDataInfoFound = false; completeRevocationRefsHashDataInfoFound = false; retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; foreach (HashDataInfo hashDataInfo in timeStamp.HashDataInfoCollection) { if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CompleteCertificateRefs.Id) { completeCertificateRefsHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CompleteRevocationRefs.Id) { completeRevocationRefsHashDataInfoFound = true; } } retVal = completeCertificateRefsHashDataInfoFound && completeRevocationRefsHashDataInfoFound; return retVal; } private bool CheckHashDataInfosOfArchiveTimeStamp(TimeStamp timeStamp) { UnsignedSignatureProperties unsignedSignatureProperties; SignedProperties signedProperties; bool allReferenceHashDataInfosFound = false; bool signedInfoHashDataInfoFound = false; bool signedPropertiesHashDataInfoFound = false; bool signatureValueHashDataInfoFound = false; bool allSignatureTimeStampHashDataInfosFound = false; bool completeCertificateRefsHashDataInfoFound = false; bool completeRevocationRefsHashDataInfoFound = false; bool certificatesValuesHashDataInfoFound = false; bool revocationValuesHashDataInfoFound = false; bool allSigAndRefsTimeStampHashDataInfosFound = false; bool allRefsOnlyTimeStampHashDataInfosFound = false; bool allArchiveTimeStampHashDataInfosFound = false; bool allOlderArchiveTimeStampsFound = false; ArrayList referenceIds = new ArrayList(); ArrayList signatureTimeStampIds = new ArrayList(); ArrayList sigAndRefsTimeStampIds = new ArrayList(); ArrayList refsOnlyTimeStampIds = new ArrayList(); ArrayList archiveTimeStampIds = new ArrayList(); bool retVal = true; unsignedSignatureProperties = this.XadesObject.QualifyingProperties.UnsignedProperties.UnsignedSignatureProperties; signedProperties = this.XadesObject.QualifyingProperties.SignedProperties; foreach (Reference reference in this.Signature.SignedInfo.References) { if (reference.Uri != "#" + signedProperties.Id) { referenceIds.Add(reference.Uri); } } referenceIds.Sort(); foreach (TimeStamp signatureTimeStamp in unsignedSignatureProperties.SignatureTimeStampCollection) { signatureTimeStampIds.Add("#" + signatureTimeStamp.EncapsulatedTimeStamp.Id); } signatureTimeStampIds.Sort(); foreach (TimeStamp sigAndRefsTimeStamp in unsignedSignatureProperties.SigAndRefsTimeStampCollection) { sigAndRefsTimeStampIds.Add("#" + sigAndRefsTimeStamp.EncapsulatedTimeStamp.Id); } sigAndRefsTimeStampIds.Sort(); foreach (TimeStamp refsOnlyTimeStamp in unsignedSignatureProperties.RefsOnlyTimeStampCollection) { refsOnlyTimeStampIds.Add("#" + refsOnlyTimeStamp.EncapsulatedTimeStamp.Id); } refsOnlyTimeStampIds.Sort(); allOlderArchiveTimeStampsFound = false; for (int archiveTimeStampCounter = 0; !allOlderArchiveTimeStampsFound && (archiveTimeStampCounter < unsignedSignatureProperties.ArchiveTimeStampCollection.Count); archiveTimeStampCounter++) { TimeStamp archiveTimeStamp = unsignedSignatureProperties.ArchiveTimeStampCollection[archiveTimeStampCounter]; if (archiveTimeStamp.EncapsulatedTimeStamp.Id == timeStamp.EncapsulatedTimeStamp.Id) { allOlderArchiveTimeStampsFound = true; } else { archiveTimeStampIds.Add("#" + archiveTimeStamp.EncapsulatedTimeStamp.Id); } } archiveTimeStampIds.Sort(); foreach (HashDataInfo hashDataInfo in timeStamp.HashDataInfoCollection) { int index = referenceIds.BinarySearch(hashDataInfo.UriAttribute); if (index >= 0) { referenceIds.RemoveAt(index); } // TODO: Проверить комментарий //if (hashDataInfo.UriAttribute == "#" + this.signedInfoIdBuffer) if (hashDataInfo.UriAttribute == "#") { signedInfoHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + signedProperties.Id) { signedPropertiesHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + this.signatureValueId) { signatureValueHashDataInfoFound = true; } index = signatureTimeStampIds.BinarySearch(hashDataInfo.UriAttribute); if (index >= 0) { signatureTimeStampIds.RemoveAt(index); } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CompleteCertificateRefs.Id) { completeCertificateRefsHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CompleteRevocationRefs.Id) { completeRevocationRefsHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.CertificateValues.Id) { certificatesValuesHashDataInfoFound = true; } if (hashDataInfo.UriAttribute == "#" + unsignedSignatureProperties.RevocationValues.Id) { revocationValuesHashDataInfoFound = true; } index = sigAndRefsTimeStampIds.BinarySearch(hashDataInfo.UriAttribute); if (index >= 0) { sigAndRefsTimeStampIds.RemoveAt(index); } index = refsOnlyTimeStampIds.BinarySearch(hashDataInfo.UriAttribute); if (index >= 0) { refsOnlyTimeStampIds.RemoveAt(index); } index = archiveTimeStampIds.BinarySearch(hashDataInfo.UriAttribute); if (index >= 0) { archiveTimeStampIds.RemoveAt(index); } } if (referenceIds.Count == 0) { allReferenceHashDataInfosFound = true; } if (signatureTimeStampIds.Count == 0) { allSignatureTimeStampHashDataInfosFound = true; } if (sigAndRefsTimeStampIds.Count == 0) { allSigAndRefsTimeStampHashDataInfosFound = true; } if (refsOnlyTimeStampIds.Count == 0) { allRefsOnlyTimeStampHashDataInfosFound = true; } if (archiveTimeStampIds.Count == 0) { allArchiveTimeStampHashDataInfosFound = true; } retVal = allReferenceHashDataInfosFound && signedInfoHashDataInfoFound && signedPropertiesHashDataInfoFound && signatureValueHashDataInfoFound && allSignatureTimeStampHashDataInfosFound && completeCertificateRefsHashDataInfoFound && completeRevocationRefsHashDataInfoFound && certificatesValuesHashDataInfoFound && revocationValuesHashDataInfoFound && allSigAndRefsTimeStampHashDataInfosFound && allRefsOnlyTimeStampHashDataInfosFound && allArchiveTimeStampHashDataInfosFound; return retVal; } #endregion public SignedDataObjectProperties SignedDataObjectProperties => SignedProperties.SignedDataObjectProperties; public SignedProperties SignedProperties => XadesObject.QualifyingProperties.SignedProperties; public SignedSignatureProperties SignedSignatureProperties => SignedProperties.SignedSignatureProperties; } }