/// <summary>
        /// Verify if the mandatory Target attribute exists on the SignatureProperty tag
        /// </summary>
        /// <param name="reader">NodeReader positioned at the SignatureProperty tag</param>
        /// <param name="signatureId">value of the Id attribute on the Signature tag</param>
        /// <returns>true, if Target attribute is present and has the correct value, else false</returns>
        private static bool VerifyTargetAttribute(XmlReader reader, string signatureId)
        {
            string idTargetValue = reader.GetAttribute(XTable.Get(XTable.ID.TargetAttrName));

            if (idTargetValue != null)
            {
                //whether there is an Id attribute on the <Signature> tag or no,
                //an empty Target attribute on <SignatureProperty> tag, is allowed.
                //Empty string means current document
                if (String.CompareOrdinal(idTargetValue, String.Empty) == 0)
                {
                    return(true);
                }
                else
                {
                    //If the Target attribute has a non-empty string then
                    //it must match the <Signature> tag Id attribute value
                    if (signatureId != null && String.CompareOrdinal(idTargetValue, "#" + signatureId) == 0)
                    {
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Parse the DigestMethod tag
        /// </summary>
        /// <param name="reader"></param>
        private static string ParseDigestAlgorithmTag(XmlReader reader)
        {
            // verify namespace and lack of attributes
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) > 1 ||
                String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 ||
                reader.Depth != 3)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            // get the Algorithm attribute
            string hashAlgorithm = null;

            if (reader.HasAttributes)
            {
                hashAlgorithm = reader.GetAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));
            }

            if (hashAlgorithm == null || hashAlgorithm.Length == 0)
            {
                throw new XmlException(SR.Get(SRID.UnsupportedHashAlgorithm));
            }

            return(hashAlgorithm);
        }
        /// <summary>
        /// Parses a Reference tag
        /// </summary>
        /// <param name="reader"></param>
        /// <returns>partManifestEntry that represents the state of the tag</returns>
        private static PartManifestEntry ParseReference(XmlReader reader)
        {
            Debug.Assert(reader != null);

            // <Reference> found - get part Uri from the tag
            ContentType contentType = null;
            Uri         partUri     = ParsePartUri(reader, out contentType);

            // only allocate if this turns out to be a Relationship transform
            List <PackageRelationshipSelector> relationshipSelectors = null;

            // move through the sub-tags: <DigestMethod>, <DigestValue> and optional <Transforms>
            string        hashAlgorithm    = null;  // digest method
            string        hashValue        = null;  // digest value
            List <String> transforms       = null;  // optional transform algorithm names
            bool          transformsParsed = false; // since null is legal for transforms var we need a

            // bool to detect multiples
            while (reader.Read() && (reader.MoveToContent() == XmlNodeType.Element))
            {
                // Correct Namespace?
                if (String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 ||
                    reader.Depth != 3)
                {
                    throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));
                }

                // DigestMethod?
                if (hashAlgorithm == null &&
                    String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.DigestMethodTagName)) == 0)
                {
                    hashAlgorithm = ParseDigestAlgorithmTag(reader);
                    continue;
                }

                // DigestValue?
                if (hashValue == null &&
                    String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.DigestValueTagName)) == 0)
                {
                    hashValue = ParseDigestValueTag(reader);
                    continue;
                }

                // TransformsTag?
                if (!transformsParsed &&
                    String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.TransformsTagName)) == 0)
                {
                    transforms       = ParseTransformsTag(reader, partUri, ref relationshipSelectors);
                    transformsParsed = true;
                    continue;
                }

                // if we get to here, we didn't see what we expected
                throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));
            }

            // add to our list
            return(new PartManifestEntry(partUri, contentType, hashAlgorithm, hashValue, transforms, relationshipSelectors));
        }
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
        /// <summary>
        /// Parse the Manifest tag
        /// </summary>
        /// <param name="manager"></param>
        /// <param name="reader">XmlReader positioned to the Manifest tag</param>
        /// <param name="partManifest"></param>
        /// <param name="partEntryManifest"></param>
        /// <param name="relationshipManifest"></param>
        internal static void ParseManifest(
            PackageDigitalSignatureManager manager,
            XmlReader reader,
            out List <Uri> partManifest,
            out List <PartManifestEntry> partEntryManifest,
            out List <PackageRelationshipSelector> relationshipManifest)
        {
            Invariant.Assert(manager != null);
            Invariant.Assert(reader != null);

            // these are empty (non-null) when nothing is found
            partManifest         = new List <Uri>();
            partEntryManifest    = new List <PartManifestEntry>();
            relationshipManifest = new List <PackageRelationshipSelector>();

            // manually parse the Relationship tags because they are custom formed and the Reference class will not handle
            // them correctly
            string referenceTagName = XTable.Get(XTable.ID.ReferenceTagName);
            int    referenceCount   = 0;

            while (reader.Read() && (reader.MoveToContent() == XmlNodeType.Element))
            {
                // should be on a <Reference> tag
                if (String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) == 0 &&
                    (String.CompareOrdinal(reader.LocalName, referenceTagName) == 0) &&
                    reader.Depth == 2)
                {
                    // Parse each reference - distinguish between Relationships and Parts
                    // because we don't store the Relationship-part itself - just it's Relationships.
                    PartManifestEntry partManifestEntry = ParseReference(reader);
                    if (partManifestEntry.IsRelationshipEntry)
                    {
                        foreach (PackageRelationshipSelector relationshipSelector in partManifestEntry.RelationshipSelectors)
                        {
                            relationshipManifest.Add(relationshipSelector);
                        }
                    }
                    else
                    {
                        partManifest.Add(partManifestEntry.Uri);
                    }

                    // return the manifest entry to be used for hashing
                    partEntryManifest.Add(partManifestEntry);

                    referenceCount++;
                }
                else
                {
                    throw new XmlException(SR.Get(SRID.UnexpectedXmlTag, reader.Name));
                }
            }

            // XmlDSig xsd requires at least one <Reference> tag
            if (referenceCount == 0)
            {
                throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));
            }
        }
        /// <summary>
        /// Parse the Relationship-specific Transform
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="partUri"></param>
        /// <param name="relationshipSelectors">may be allocated but will never be empty</param>
        private static void ParseRelationshipsTransform(XmlReader reader, Uri partUri, ref List <PackageRelationshipSelector> relationshipSelectors)
        {
            Uri owningPartUri = PackUriHelper.GetSourcePartUriFromRelationshipPartUri(partUri);

            // find all of the Relationship tags of form:
            //      <RelationshipReference SourceId="abc123" />
            // or
            //      <RelationshipsGroupReference SourceType="reference-type-of-the-week" />
            while (reader.Read() && (reader.MoveToContent() == XmlNodeType.Element) &&
                   reader.Depth == 5)
            {
                // both types have no children, a single required attribute and belong to the OPC namespace
                if (reader.IsEmptyElement &&
                    PackagingUtilities.GetNonXmlnsAttributeCount(reader) == 1 &&
                    (String.CompareOrdinal(reader.NamespaceURI, XTable.Get(XTable.ID.OpcSignatureNamespace)) == 0))
                {
                    // <RelationshipReference>?
                    if (String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.RelationshipReferenceTagName)) == 0)
                    {
                        // RelationshipReference tags are legal and these must be empty with a single SourceId attribute
                        // get the SourceId attribute
                        string id = reader.GetAttribute(XTable.Get(XTable.ID.SourceIdAttrName));
                        if (id != null && id.Length > 0)
                        {
                            if (relationshipSelectors == null)
                            {
                                relationshipSelectors = new List <PackageRelationshipSelector>();
                            }

                            // we found a legal SourceId so create a selector and continue searching
                            relationshipSelectors.Add(new PackageRelationshipSelector(owningPartUri, PackageRelationshipSelectorType.Id, id));
                            continue;
                        }
                    }   // <RelationshipsGroupReference>?
                    else if ((String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.RelationshipsGroupReferenceTagName)) == 0))
                    {
                        // RelationshipsGroupReference tags must be empty with a single SourceType attribute
                        string type = reader.GetAttribute(XTable.Get(XTable.ID.SourceTypeAttrName));
                        if (type != null && type.Length > 0)
                        {
                            // lazy init
                            if (relationshipSelectors == null)
                            {
                                relationshipSelectors = new List <PackageRelationshipSelector>();
                            }

                            // got a legal SourceType attribute
                            relationshipSelectors.Add(new PackageRelationshipSelector(owningPartUri, PackageRelationshipSelectorType.Type, type));
                            continue;
                        }
                    }
                }

                // if we get to here, we have not found a legal tag so we throw
                throw new XmlException(SR.Get(SRID.UnexpectedXmlTag, reader.LocalName));
            }
        }
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
        /// <summary>
        /// GenerateRelationshipSigningReferences
        /// </summary>
        /// <param name="manager"></param>
        /// <param name="xDoc"></param>
        /// <param name="hashAlgorithm"></param>
        /// <param name="relationshipSelectors"></param>
        /// <param name="manifest"></param>
        /// <returns>number of references to be signed</returns>
        private static int GenerateRelationshipSigningReferences(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc, HashAlgorithm hashAlgorithm,
            IEnumerable <PackageRelationshipSelector> relationshipSelectors,
            XmlNode manifest)
        {
            // PartUri - and its list of PackageRelationshipSelectors
            Dictionary <Uri, List <PackageRelationshipSelector> > partAndSelectorDictionary
                = new Dictionary <Uri, List <PackageRelationshipSelector> >();

            foreach (PackageRelationshipSelector relationshipSelector in relationshipSelectors)
            {
                //update the partAndSelectorDictionary for each relationshipSelector
                Uri relationshipPartUri = PackUriHelper.GetRelationshipPartUri(relationshipSelector.SourceUri);

                List <PackageRelationshipSelector> selectors;
                if (partAndSelectorDictionary.ContainsKey(relationshipPartUri))
                {
                    selectors = partAndSelectorDictionary[relationshipPartUri];
                }
                else
                {
                    selectors = new List <PackageRelationshipSelector>();
                    partAndSelectorDictionary.Add(relationshipPartUri, selectors);
                }

                selectors.Add(relationshipSelector);
            }

            // now that we have them grouped by Part name, emit the XML
            // Here is an optimization for saving space by declaring the OPC namespace and prefix
            // in the <Manifest> tag. It will become:
            // <Manifest xmlns:opc="http://schemas.openxmlformats.org/package/2006/digital-signature">
            // Later when we generate the RelationshipSigningReference we can use the namespace prefix "opc"
            // instead of the long namespace itself, thus saving some space if the manifest has more than one
            // RelationshipSigningReference.
            //
            XmlElement xmlE = (XmlElement)manifest;

            xmlE.SetAttribute(XTable.Get(XTable.ID.OpcSignatureNamespaceAttribute),
                              XTable.Get(XTable.ID.OpcSignatureNamespace));

            int count = 0;

            foreach (Uri partName in partAndSelectorDictionary.Keys)
            {
                // emit xml and append
                manifest.AppendChild(
                    GenerateRelationshipSigningReference(manager, xDoc, hashAlgorithm,
                                                         partName, /* we are guaranteed that this is a valid part Uri, so we do not use PackUriHelper.CreatePartUri */
                                                         partAndSelectorDictionary[partName]));

                count++;
            }

            return(count);
        }
        private static XmlNode GenerateDigestValueNode(XmlDocument xDoc, HashAlgorithm hashAlgorithm, Stream s, String transformName)
        {
            // <DigestValue>
            XmlElement digestValue     = xDoc.CreateElement(XTable.Get(XTable.ID.DigestValueTagName), SignedXml.XmlDsigNamespaceUrl);
            XmlText    digestValueText = xDoc.CreateTextNode(XmlDigitalSignatureProcessor.GenerateDigestValue(s, transformName, hashAlgorithm));

            digestValue.AppendChild(digestValueText);
            return(digestValue);
        }
        /// <summary>
        /// Obtain a W3C formatted SigningTime (equivalent to TimeStamp)
        /// </summary>
        /// <param name="xDoc">xml document we are building</param>
        /// <param name="dateTime">time to persist</param>
        /// <param name="signatureId">id of new signature</param>
        /// <param name="xmlDateTimeFormat">format to use - must be Xml date format legal syntax</param>
        /// <returns>given writer with SignatureProperties xml added to it</returns>
        /// <remarks>format matches that described in http://www.w3.org/TR/NOTE-datetime </remarks>
        /// <example>
        /// <Object Id="Package">
        ///     <SignatureProperties>
        ///         <SignatureProperty Target="#signatureId">
        ///             <SignatureTime>
        ///                 <Format>YYYY-MM-DDThh:mm:ssTZD</Format>
        ///                 <Value>1997-07-16T19:20:30.45+01:00</Value>
        ///             </SignatureTime>
        ///         </SignatureProperty>
        ///     </SignatureProperties>
        /// </Object>
        /// </example>
        internal static XmlElement AssembleSignatureProperties(
            XmlDocument xDoc,
            DateTime dateTime,
            String xmlDateTimeFormat,
            String signatureId)
        {
            Invariant.Assert(xDoc != null);
            Invariant.Assert(signatureId != null);

            // check for null format - use default if null
            if (xmlDateTimeFormat == null)
            {
                xmlDateTimeFormat = DefaultDateTimeFormat;
            }

            string[] dateTimeFormats = ConvertXmlFormatStringToDateTimeFormatString(xmlDateTimeFormat);

            // <SignatureProperties>
            XmlElement signatureProperties = xDoc.CreateElement(XTable.Get(XTable.ID.SignaturePropertiesTagName),
                                                                SignedXml.XmlDsigNamespaceUrl);

            // <SignatureProperty Id="idSignatureTime" Target="#signatureId">
            XmlElement signatureProperty = xDoc.CreateElement(XTable.Get(XTable.ID.SignaturePropertyTagName),
                                                              SignedXml.XmlDsigNamespaceUrl);

            signatureProperties.AppendChild(signatureProperty);
            XmlAttribute idAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.SignaturePropertyIdAttrName));

            idAttr.Value = XTable.Get(XTable.ID.SignaturePropertyIdAttrValue);
            signatureProperty.Attributes.Append(idAttr);
            XmlAttribute targetAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.TargetAttrName));

            targetAttr.Value = "#" + signatureId;
            signatureProperty.Attributes.Append(targetAttr);

            // <SignatureTime>
            XmlElement signatureTime = xDoc.CreateElement(XTable.Get(XTable.ID.SignatureTimeTagName),
                                                          XTable.Get(XTable.ID.OpcSignatureNamespace));
            XmlElement signatureTimeFormat = xDoc.CreateElement(XTable.Get(XTable.ID.SignatureTimeFormatTagName),
                                                                XTable.Get(XTable.ID.OpcSignatureNamespace));
            XmlElement signatureTimeValue = xDoc.CreateElement(XTable.Get(XTable.ID.SignatureTimeValueTagName),
                                                               XTable.Get(XTable.ID.OpcSignatureNamespace));

            signatureTimeFormat.AppendChild(xDoc.CreateTextNode(xmlDateTimeFormat));
            signatureTimeValue.AppendChild(xDoc.CreateTextNode(DateTimeToXmlFormattedTime(dateTime, dateTimeFormats[0])));

            signatureTime.AppendChild(signatureTimeFormat);
            signatureTime.AppendChild(signatureTimeValue);

            signatureProperty.AppendChild(signatureTime);

            return(signatureProperties);
        }
        private static XmlNode GenerateDigestMethod(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc)
        {
            // <DigestMethod>
            XmlElement   digestMethod        = xDoc.CreateElement(XTable.Get(XTable.ID.DigestMethodTagName), SignedXml.XmlDsigNamespaceUrl);
            XmlAttribute digestAlgorithmAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));

            digestAlgorithmAttr.Value = manager.HashAlgorithm;
            digestMethod.Attributes.Append(digestAlgorithmAttr);
            return(digestMethod);
        }
Beispiel #10
0
        /// <summary>
        /// Locates and selects the target XmlElement from all available Object tags
        /// </summary>
        /// <param name="signature"></param>
        /// <param name="idValue"></param>
        /// <returns>element if found; null if not found</returns>
        /// <remarks>relies on XPath query to search the Xml in each Object tag</remarks>
        private static XmlElement SelectSubObjectNodeForXAdESInDataObjects(Signature signature, string idValue)
        {
            XmlElement node       = null;
            bool       foundMatch = false; // true if id has matched, even with the wrong namespace

            // now find an object tag that includes an element that matches
            foreach (DataObject dataObject in signature.ObjectList)
            {
                // skip the package object
                if (String.CompareOrdinal(dataObject.Id, XTable.Get(XTable.ID.OpcAttrValue)) != 0)
                {
                    XmlElement element = dataObject.GetXml();

                    // NOTE: this is executing an XPath query
                    // idValue has already been tested as an NCName (unless overridden for compatibility), so there's no
                    // escaping that needs to be done here.
                    XmlNodeList nodeList = element.SelectNodes(".//*[@Id='" + idValue + "']");

                    if (nodeList.Count > 0)
                    {
                        if (!AllowAmbiguousReferenceTargets() &&
                            (nodeList.Count > 1 || foundMatch))
                        {
                            throw new XmlException(SR.Get(SRID.DuplicateObjectId));
                        }

                        foundMatch = true;
                        XmlNode local = nodeList[0] as XmlElement;

                        if (local != null)
                        {
                            XmlNode temp = local;

                            // climb the tree towards the root until we find our namespace
                            while ((temp != null) && (temp.NamespaceURI.Length == 0))
                            {
                                temp = temp.ParentNode;
                            }

                            // only match if the target is in the XAdES namespace
                            if ((temp != null) && (String.CompareOrdinal(temp.NamespaceURI, _XAdESNameSpace) == 0))
                            {
                                node = local as XmlElement;
                                // continue searching, to find duplicates from different objects
                            }
                        }
                    }
                }
            }

            return(node);
        }
        /// <summary>
        /// Verify if the SignatureProperty tag has a valid Id attribute
        /// </summary>
        /// <param name="reader">NodeReader positioned at the SignatureProperty tag</param>
        /// <returns>true, if Id attribute is present and has the correct value, else false</returns>
        private static bool VerifyIdAttribute(XmlReader reader)
        {
            string idAttrValue = reader.GetAttribute(XTable.Get(XTable.ID.SignaturePropertyIdAttrName));

            if (idAttrValue != null &&
                (String.CompareOrdinal(idAttrValue, XTable.Get(XTable.ID.SignaturePropertyIdAttrValue)) == 0))
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Generate Manifest tag
        /// </summary>
        /// <param name="manager">manager</param>
        /// <param name="xDoc">current Xml doc</param>
        /// <param name="hashAlgorithm">hash algorithm to hash with</param>
        /// <param name="parts">parts to sign - possibly null</param>
        /// <param name="relationshipSelectors">relationshipSelectors that represent the
        /// relationships that have to be signed - possibly null</param>
        /// <returns></returns>
        internal static XmlNode GenerateManifest(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm,
            IEnumerable <Uri> parts,
            IEnumerable <PackageRelationshipSelector> relationshipSelectors)
        {
            Debug.Assert(manager != null);
            Debug.Assert(xDoc != null);
            Debug.Assert(hashAlgorithm != null);

            // check args
            if (!hashAlgorithm.CanReuseTransform)
            {
                throw new ArgumentException(SR.Get(SRID.HashAlgorithmMustBeReusable));
            }

            // <Manifest>
            XmlNode manifest = xDoc.CreateNode(XmlNodeType.Element,
                                               XTable.Get(XTable.ID.ManifestTagName),
                                               SignedXml.XmlDsigNamespaceUrl);

            // add part references
            if (parts != null)
            {
                // loop and write - may still be empty
                foreach (Uri partUri in parts)
                {
                    // generate a reference tag
                    manifest.AppendChild(GeneratePartSigningReference(manager, xDoc, hashAlgorithm, partUri));
                }
            }

            // any relationship references?
            int relationshipCount = 0;

            if (relationshipSelectors != null)
            {
                relationshipCount = GenerateRelationshipSigningReferences(manager, xDoc, hashAlgorithm, relationshipSelectors, manifest);
            }

            // did we sign anything? Manifest can NOT be empty
            if (parts == null && relationshipCount == 0)
            {
                throw new ArgumentException(SR.Get(SRID.NothingToSign));
            }

            return(manifest);
        }
        private static XmlNode GeneratePartSigningReference(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm,
            Uri partName)
        {
            PackagePart part = manager.Package.GetPart(partName);

            // <Reference>
            XmlElement reference = xDoc.CreateElement(XTable.Get(XTable.ID.ReferenceTagName), SignedXml.XmlDsigNamespaceUrl);

            // add Uri with content type as Query
            XmlAttribute uriAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.UriAttrName));

            uriAttr.Value = PackUriHelper.GetStringForPartUri(partName) + _contentTypeQueryStringPrefix + part.ContentType;
            reference.Attributes.Append(uriAttr);

            // add transforms tag if necessary
            String transformName = String.Empty;

            if (manager.TransformMapping.ContainsKey(part.ContentType))
            {
                transformName = manager.TransformMapping[part.ContentType];

                // <Transforms>
                XmlElement transforms = xDoc.CreateElement(XTable.Get(XTable.ID.TransformsTagName), SignedXml.XmlDsigNamespaceUrl);

                // <Transform>
                XmlElement   transform     = xDoc.CreateElement(XTable.Get(XTable.ID.TransformTagName), SignedXml.XmlDsigNamespaceUrl);
                XmlAttribute algorithmAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));
                algorithmAttr.Value = transformName;
                transform.Attributes.Append(algorithmAttr);

                transforms.AppendChild(transform);
                reference.AppendChild(transforms);
            }

            // <DigestMethod>
            reference.AppendChild(GenerateDigestMethod(manager, xDoc));

            // <DigestValue>
            using (Stream s = part.GetStream(FileMode.Open, FileAccess.Read))
            {
                reference.AppendChild(GenerateDigestValueNode(xDoc, hashAlgorithm, s, transformName));
            }

            return(reference);
        }
Beispiel #14
0
        /// <summary>
        /// Locates and selects the target XmlElement from all available Object tags
        /// </summary>
        /// <param name="signature"></param>
        /// <param name="idValue"></param>
        /// <returns>element if found; null if not found</returns>
        /// <remarks>relies on XPath query to search the Xml in each Object tag</remarks>
        private static XmlElement SelectSubObjectNodeForXAdESInDataObjects(Signature signature, string idValue)
        {
            XmlElement node = null;

            // now find an object tag that includes an element that matches
            foreach (DataObject dataObject in signature.ObjectList)
            {
                // skip the package object
                if (String.CompareOrdinal(dataObject.Id, XTable.Get(XTable.ID.OpcAttrValue)) != 0)
                {
                    XmlElement element = dataObject.GetXml();

                    // NOTE: this is executing an XPath query
                    XmlElement local = element.SelectSingleNode("//*[@Id='" + idValue + "']") as XmlElement;
                    if (local == null)
                    {
                        continue;
                    }

                    // node found?
                    if (local != null)
                    {
                        XmlNode temp = local;

                        // climb the tree towards the root until we find our namespace
                        while ((temp != null) && (temp.NamespaceURI.Length == 0))
                        {
                            temp = temp.ParentNode;
                        }

                        // only match if the target is in the XAdES namespace
                        if ((temp != null) && (String.CompareOrdinal(temp.NamespaceURI, _XAdESNameSpace) == 0))
                        {
                            node = local as XmlElement;
                            break;
                        }
                    }
                }
            }

            return(node);
        }
        /// <summary>
        /// Get the part uri and it's content type from the current Reference tag
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="contentType">contentType extracted from the query portion of the Uri</param>
        /// <returns>PackagePart uri and contentType</returns>
        private static Uri ParsePartUri(XmlReader reader, out ContentType contentType)
        {
            // should be a relative Package uri with a query portion that contains the ContentType
            contentType = ContentType.Empty;
            Uri partUri = null;

            // must be one and only one attribute
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) == 1)
            {
                string uriAttrValue = reader.GetAttribute(XTable.Get(XTable.ID.UriAttrName));
                if (uriAttrValue != null)
                {
                    partUri = ParsePartUriAttribute(uriAttrValue, out contentType);
                }
            }

            // will be null if we had no success
            if (partUri == null)
            {
                throw new XmlException(SR.Get(SRID.RequiredXmlAttributeMissing, XTable.Get(XTable.ID.UriAttrName)));
            }

            return(partUri);
        }
        //-----------------------------------------------------------------------------
        //
        // Private Methods
        //
        //-----------------------------------------------------------------------------

        /// <summary>
        /// Parse the SignatureTime tag
        /// </summary>
        /// <param name="reader">NodeReader positioned at the SignatureProperty tag</param>
        /// <param name="timeFormat">format found</param>
        /// <exception cref="XmlException">illegal format</exception>
        /// <returns>signing time</returns>
        private static DateTime ParseSignatureTimeTag(XmlReader reader, out String timeFormat)
        {
            //There are no attributes on all the three tags that we parse in this method
            //<SignatureTime>, <Format>, <Value>
            int expectedAttributeCount = 0;

            string opcSignatureNameSpace = XTable.Get(XTable.ID.OpcSignatureNamespace);
            string signaturePropertyTag  = XTable.Get(XTable.ID.SignaturePropertyTagName);
            string signatureTimeTag      = XTable.Get(XTable.ID.SignatureTimeTagName);
            string timeValueTagName      = XTable.Get(XTable.ID.SignatureTimeValueTagName);
            string timeFormatTagName     = XTable.Get(XTable.ID.SignatureTimeFormatTagName);

            // <SignatureTime> must be one of <Format> or <Time>
            timeFormat = null;
            string timeValue = null;

            //Look for <SignatureTime> Tag
            if (reader.Read() &&
                reader.MoveToContent() == XmlNodeType.Element &&
                (String.CompareOrdinal(reader.NamespaceURI, opcSignatureNameSpace) == 0) &&
                (String.CompareOrdinal(reader.LocalName, signatureTimeTag) == 0) &&
                reader.Depth == 3 &&
                PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributeCount)
            {
                while (reader.Read())
                {
                    if (String.CompareOrdinal(reader.NamespaceURI, opcSignatureNameSpace) == 0 &&
                        reader.MoveToContent() == XmlNodeType.Element &&
                        reader.Depth == 4)
                    {
                        // which tag do we have?
                        if ((String.CompareOrdinal(reader.LocalName, timeValueTagName) == 0) &&
                            PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributeCount)
                        {
                            if (timeValue == null &&
                                reader.Read() &&
                                reader.MoveToContent() == XmlNodeType.Text &&
                                reader.Depth == 5)
                            {
                                //After reading the content, the reader progresses to the next element.
                                //So after this method is called, the reader is positioned at the
                                //EndElement corresponding to Value tag - </Value>
                                // Note: ReadContentAsString will return String.Empty but never null
                                timeValue = reader.ReadContentAsString();
                                Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
                            }
                            else
                            {
                                //This would happen if we found more than one Value tags or if there
                                //are other nested elements of if they are of a different XmlNodeType type
                                throw new XmlException(SR.PackageSignatureCorruption);
                            }
                        }
                        else if ((String.CompareOrdinal(reader.LocalName, timeFormatTagName) == 0) &&
                                 PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributeCount)
                        {
                            if (timeFormat == null &&
                                reader.Read() &&
                                reader.MoveToContent() == XmlNodeType.Text &&
                                reader.Depth == 5)
                            {
                                //After reading the content, the reader progresses to the next element.
                                //So after this method is called, the reader is positioned at the
                                //EndElement corresponding to Format tag - </Format>
                                // Note: ReadContentAsString will return String.Empty but never null
                                timeFormat = reader.ReadContentAsString();
                                Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
                            }
                            else
                            {
                                //This would happen if we found more than one Format tags or if there
                                //are other nested elements of if they are of a different XmlNodeType type
                                throw new XmlException(SR.PackageSignatureCorruption);
                            }
                        }
                        else
                        {
                            //If we encounter any tag other than <Format> or <Time> nested within the <SignatureTime> tag
                            throw new XmlException(SR.PackageSignatureCorruption);
                        }
                    }
                    else
                    //If we have encountered the end tag for the <SignatureTime> tag
                    //then we are done parsing the tag, and we can stop the parsing.
                    if (String.CompareOrdinal(signatureTimeTag, reader.LocalName) == 0 &&
                        (reader.NodeType == XmlNodeType.EndElement))
                    {
                        //We must find a  </SignatureProperty> tag at this point,
                        //else it could be that there are more SignatureTime or
                        //other tags nested here and that is an error.
                        if (reader.Read() &&
                            reader.MoveToContent() == XmlNodeType.EndElement &&
                            String.CompareOrdinal(signaturePropertyTag, reader.LocalName) == 0)
                        {
                            break;
                        }
                        else
                        {
                            throw new XmlException(SR.PackageSignatureCorruption);
                        }
                    }
                    else
                    {
                        // if we do not find the nested elements as expected
                        throw new XmlException(SR.PackageSignatureCorruption);
                    }
                }
            }
            else
            {
                throw new XmlException(SR.Format(SR.RequiredTagNotFound, signatureTimeTag));
            }


            // generate an equivalent DateTime object
            if (timeValue != null && timeFormat != null)
            {
                return(XmlFormattedTimeToDateTime(timeValue, timeFormat));
            }
            else
            {
                throw new XmlException(SR.PackageSignatureCorruption);
            }
        }
        /// <summary>
        /// Generates a Reference tag that contains a Relationship transform
        /// </summary>
        /// <param name="manager">manager</param>
        /// <param name="relationshipPartName">name of the relationship part</param>
        /// <param name="xDoc">current xml document</param>
        /// <param name="hashAlgorithm">hash algorithm = digest method</param>
        /// <param name="relationshipSelectors">relationshipSelectors that represent the relationships to sign </param>
        /// <remarks>ContentType is known and part name can be derived from the relationship collection</remarks>
        private static XmlNode GenerateRelationshipSigningReference(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm,
            Uri relationshipPartName,
            IEnumerable <PackageRelationshipSelector> relationshipSelectors)
        {
            string relPartContentType = PackagingUtilities.RelationshipPartContentType.ToString();

            // <Reference>
            XmlElement reference = xDoc.CreateElement(XTable.Get(XTable.ID.ReferenceTagName), SignedXml.XmlDsigNamespaceUrl);

            // add Uri
            // persist the Uri of the associated Relationship part
            String relationshipPartString;

            if (PackUriHelper.ComparePartUri(relationshipPartName, PackageRelationship.ContainerRelationshipPartName) == 0)
            {
                relationshipPartString = PackageRelationship.ContainerRelationshipPartName.ToString();
            }
            else
            {
                relationshipPartString = PackUriHelper.GetStringForPartUri(relationshipPartName);
            }

            XmlAttribute uriAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.UriAttrName));

            uriAttr.Value = relationshipPartString + _contentTypeQueryStringPrefix + relPartContentType;
            reference.Attributes.Append(uriAttr);

            // add transforms tag (always necessary)

            // <Transforms>
            XmlElement transforms = xDoc.CreateElement(XTable.Get(XTable.ID.TransformsTagName), SignedXml.XmlDsigNamespaceUrl);

            // add Relationship transform
            String opcNamespace       = XTable.Get(XTable.ID.OpcSignatureNamespace);
            String opcNamespacePrefix = XTable.Get(XTable.ID.OpcSignatureNamespacePrefix);

            XmlElement   transform     = xDoc.CreateElement(XTable.Get(XTable.ID.TransformTagName), SignedXml.XmlDsigNamespaceUrl);
            XmlAttribute algorithmAttr = xDoc.CreateAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));

            algorithmAttr.Value = XTable.Get(XTable.ID.RelationshipsTransformName);
            transform.Attributes.Append(algorithmAttr);

            // <RelationshipReference SourceId="abc" /> or
            // <RelationshipGroupReference SourceType="xyz" />
            foreach (PackageRelationshipSelector relationshipSelector in relationshipSelectors)
            {
                switch (relationshipSelector.SelectorType)
                {
                case PackageRelationshipSelectorType.Id:
                {
                    XmlNode      relationshipNode = xDoc.CreateElement(opcNamespacePrefix, XTable.Get(XTable.ID.RelationshipReferenceTagName), opcNamespace);
                    XmlAttribute idAttr           = xDoc.CreateAttribute(XTable.Get(XTable.ID.SourceIdAttrName));
                    idAttr.Value = relationshipSelector.SelectionCriteria;
                    relationshipNode.Attributes.Append(idAttr);
                    transform.AppendChild(relationshipNode);
                }
                break;

                case PackageRelationshipSelectorType.Type:
                {
                    XmlNode      relationshipNode = xDoc.CreateElement(opcNamespacePrefix, XTable.Get(XTable.ID.RelationshipsGroupReferenceTagName), opcNamespace);
                    XmlAttribute typeAttr         = xDoc.CreateAttribute(XTable.Get(XTable.ID.SourceTypeAttrName));
                    typeAttr.Value = relationshipSelector.SelectionCriteria;
                    relationshipNode.Attributes.Append(typeAttr);
                    transform.AppendChild(relationshipNode);
                }
                break;

                default:
                    Invariant.Assert(false, "This option should never be executed");
                    break;
                }
            }

            transforms.AppendChild(transform);

            // add non-Relationship transform (if any)
            String transformName = null;

            if (manager.TransformMapping.ContainsKey(relPartContentType))
            {
                transformName = manager.TransformMapping[relPartContentType];       // let them override

                //Currently we only support two transforms and so we validate whether its
                //one of those
                if (transformName == null ||
                    transformName.Length == 0 ||
                    !XmlDigitalSignatureProcessor.IsValidXmlCanonicalizationTransform(transformName))
                {
                    throw new InvalidOperationException(SR.Get(SRID.UnsupportedTransformAlgorithm));
                }

                // <Transform>
                transform           = xDoc.CreateElement(XTable.Get(XTable.ID.TransformTagName), SignedXml.XmlDsigNamespaceUrl);
                algorithmAttr       = xDoc.CreateAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));
                algorithmAttr.Value = transformName;
                transform.Attributes.Append(algorithmAttr);

                transforms.AppendChild(transform);
            }
            reference.AppendChild(transforms);

            // <DigestMethod>
            reference.AppendChild(GenerateDigestMethod(manager, xDoc));

            // <DigestValue> - digest the virtual node list made from these Relationship tags
            using (Stream s = XmlDigitalSignatureProcessor.GenerateRelationshipNodeStream(GetRelationships(manager, relationshipSelectors)))    // serialized node list
            {
                reference.AppendChild(GenerateDigestValueNode(xDoc, hashAlgorithm, s, transformName));
            }

            return(reference);
        }
        /// <summary>
        /// Parse the xml and determine the signing time
        /// </summary>
        /// <param name="reader">NodeReader positioned at the SignatureProperties tag</param>
        /// <param name="signatureId">value of the Id attribute on the Signature tag</param>
        /// <param name="timeFormat">format found</param>
        /// <exception cref="XmlException">illegal format</exception>
        /// <returns>signing time</returns>
        internal static DateTime ParseSigningTime(XmlReader reader, string signatureId, out String timeFormat)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            bool   signatureTimePropertyFound = false;
            bool   signatureTimeIdFound       = false;
            string w3cSignatureNameSpace      = SignedXml.XmlDsigNamespaceUrl;

            // <SignatureProperty> tag
            string signaturePropertyTag   = XTable.Get(XTable.ID.SignaturePropertyTagName);
            string signaturePropertiesTag = XTable.Get(XTable.ID.SignaturePropertiesTagName);

            //initializing to a dummy value
            DateTime signingTime = DateTime.Now;

            timeFormat = null;

            while (reader.Read())
            {
                //Looking for <SignatureProperty> tag
                if (reader.MoveToContent() == XmlNodeType.Element &&
                    (String.CompareOrdinal(reader.NamespaceURI, w3cSignatureNameSpace) == 0) &&
                    (String.CompareOrdinal(reader.LocalName, signaturePropertyTag) == 0) &&
                    reader.Depth == 2)
                {
                    //Verify Attributes
                    //Look for well-defined Id attribute and if it is present
                    if (VerifyIdAttribute(reader))
                    {
                        //If we encounter more than one <SignatureProperty> tag with the expected
                        //id, then its an error.
                        if (signatureTimeIdFound)
                        {
                            throw new XmlException(SR.PackageSignatureCorruption);
                        }
                        else
                        {
                            signatureTimeIdFound = true;
                        }

                        //VerifyTargetAttribute will return false, if the Target attribute is missing
                        //or contains an incorrect value.
                        if (VerifyTargetAttribute(reader, signatureId))
                        {
                            signingTime = ParseSignatureTimeTag(reader, out timeFormat);
                            signatureTimePropertyFound = true;
                        }
                    }
                }
                else
                //Expected <SignatureProperty> tag not found.
                //Look for end tag corresponding to </SignatureProperty> or
                //if these are other custom defined properties, then anything with
                //depth greater than 2 should be ignored as these can be nested elements.
                if (((String.CompareOrdinal(signaturePropertyTag, reader.LocalName) == 0 &&
                      (reader.NodeType == XmlNodeType.EndElement))) ||
                    reader.Depth > 2)
                {
                    continue;
                }
                else
                //If we find the end tag for </SignatureProperties> then we can stop parsing
                if ((String.CompareOrdinal(signaturePropertiesTag, reader.LocalName) == 0 &&
                     (reader.NodeType == XmlNodeType.EndElement)))
                {
                    break;
                }
                else
                {
                    throw new XmlException(SR.Format(SR.RequiredTagNotFound, signaturePropertyTag));
                }
            }

            //We did find one or more <SignatureProperty> tags but there were none that
            //defined the id attribute and target attribute and <SignatureTime> element tag correctly.
            if (!signatureTimePropertyFound)
            {
                throw new XmlException(SR.PackageSignatureCorruption);
            }

            return(signingTime);
        }
        /// <summary>
        /// Parses Transforms tag
        /// </summary>
        /// <param name="reader">node to parse</param>
        /// <param name="partUri">Part Uri for the part owning the relationships</param>
        /// <param name="relationshipSelectors">allocates and returns a list of
        /// PackageRelationshipSelectors if Relationship transform</param>
        /// <returns>ordered list of Transform names</returns>
        private static List <String> ParseTransformsTag(XmlReader reader, Uri partUri, ref List <PackageRelationshipSelector> relationshipSelectors)
        {
            // # reference that signs multiple PackageRelationships
            // <Reference URI="/shared/_rels/image.jpg.rels?ContentType=image/jpg">
            //      <Transforms>
            //          <Transform Algorithm="http://schemas.openxmlformats.org/package/2006/RelationshipTransform">
            //              <RelationshipReference SourceId="1" />
            //              <RelationshipReference SourceId="2" />
            //              <RelationshipReference SourceId="8" />
            //          </Transform>
            //          <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
            //      </Transforms>
            //      <DigestMethod Algorithm="sha1" />
            //      <DigestValue>... </DigestValue>
            // </Reference>

            // verify lack of attributes
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) != 0)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            List <String> transforms = null;
            bool          relationshipTransformFound = false;
            int           transformsCountWhenRelationshipTransformFound = 0;

            // Look for transforms.
            // There are currently only 3 legal transforms which can be arranged in any
            // combination.
            while (reader.Read() && (reader.MoveToContent() == XmlNodeType.Element))
            {
                String transformName = null;

                // at this level, all tags must be Transform tags
                if (reader.Depth != 4 ||
                    String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 ||
                    String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.TransformTagName)) != 0)
                {
                    throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
                }

                // inspect the Algorithm attribute to determine the type of transform
                if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) == 1)
                {
                    transformName = reader.GetAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));
                }

                // legal transform name?
                if ((transformName != null) && (transformName.Length > 0))
                {
                    // what type of transform?
                    if (String.CompareOrdinal(transformName, XTable.Get(XTable.ID.RelationshipsTransformName)) == 0)
                    {
                        if (!relationshipTransformFound)
                        {
                            // relationship transform
                            ParseRelationshipsTransform(reader, partUri, ref relationshipSelectors);

                            if (transforms == null)
                            {
                                transforms = new List <String>();
                            }

                            transforms.Add(transformName);

                            relationshipTransformFound = true;
                            transformsCountWhenRelationshipTransformFound = transforms.Count;
                            continue;   // success
                        }
                        else
                        {
                            throw new XmlException(SR.Get(SRID.MultipleRelationshipTransformsFound));
                        }
                    }
                    else
                    {
                        // non-Relationship transform should have no children
                        if (reader.IsEmptyElement)
                        {
                            if (transforms == null)
                            {
                                transforms = new List <String>();
                            }

                            if (XmlDigitalSignatureProcessor.IsValidXmlCanonicalizationTransform(transformName))
                            {
                                transforms.Add(transformName); // return it
                                continue;                      // success
                            }
                            else
                            {
                                throw new InvalidOperationException(SR.Get(SRID.UnsupportedTransformAlgorithm));
                            }
                        }
                    }
                }
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            if (transforms.Count == 0)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            //If we found another transform after the Relationship transform, it will be validated earlier
            //in this method to make sure that its a supported xml canonicalization algorithm and so we can
            //simplify this test condition - As per the OPC spec - Relationship transform must be followed
            //by a canonicalization algorithm.
            if (relationshipTransformFound && (transforms.Count == transformsCountWhenRelationshipTransformFound))
            {
                throw new XmlException(SR.Get(SRID.RelationshipTransformNotFollowedByCanonicalizationTransform));
            }

            return(transforms);
        }