XmlSignatureManifest.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / MS / Internal / IO / Packaging / XmlSignatureManifest.cs / 1 / XmlSignatureManifest.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  Signature processor implementation that follows the Feb 12, 2002 W3C DigSig Recommendation 
//
//  Generates and consumes Manifest portion of the 
//  XmlDSig-compliant digital signatures based on the subset
//  specified by the OPC file format.
//
// Manifest appears in this context: 
//
//       
//          ... 
//          ...
//       
//
// Manifest form is:
//
//       
//
//          # simple reference - no transforms 
//           
//              
//              ...  
//          
//
//          # simple reference with c14n canonicalization transform
//           
//              
//                   
//               
//              
//              ...  
//          
//
//          # reference that signs multiple PackageRelationships
//           
//              
//                   
//                       
//                      
//                       
//                  
//                  
//              
//               
//              ... 
//           
// 
//          # reference that signs PackageRelationships by Relationship Type and a single Relationship by ID
//           
//              
//                  
//                      
//                       
//                  
//                   
//               
//              
//              ...  
//          
//          ...
//
//       

// History: 
//  01/25/2004: BruceMac: Initial Implementation 
//
//----------------------------------------------------------------------------- 

using System;
using System.Diagnostics;
using System.Collections; 
using System.Collections.Generic;
//using System.Security;                      // for SecurityCritical and SecurityTreatAsSafe 
using System.Security.Cryptography; 
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates; 
using System.Xml;
using System.IO;
using System.Windows;
using System.IO.Packaging; 
using MS.Internal;
 
namespace MS.Internal.IO.Packaging 
{
    ///  
    /// Manifest generator/parser
    /// 
    /// See: http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/ for details
    internal static class XmlSignatureManifest 
    {
        //----------------------------------------------------- 
        // 
        //  Internal Methods
        // 
        //-----------------------------------------------------
        /// 
        /// Parse the Manifest tag
        ///  
        /// 
        /// XmlReader positioned to the Manifest tag 
        ///  
        /// 
        ///  
        internal static void ParseManifest(
            PackageDigitalSignatureManager manager,
            XmlReader reader,
            out List partManifest, 
            out List partEntryManifest,
            out List relationshipManifest) 
        { 
            Invariant.Assert(manager != null);
            Invariant.Assert(reader != null); 

            // these are empty (non-null) when nothing is found
            partManifest = new List();
            partEntryManifest = new List(); 
            relationshipManifest = new List();
 
            // 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  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  tag
            if (referenceCount == 0)
                throw new XmlException(SR.Get(SRID.PackageSignatureCorruption)); 
        }
 
        ///  
        /// Parse the DigestMethod tag
        ///  
        /// 
        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;
        }
 
        /// 
        /// Parse the DigestValue tag 
        ///  
        /// 
        private static string ParseDigestValueTag(XmlReader reader) 
        {
            Debug.Assert(reader != null);

            // verify namespace and lack of attributes 
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) > 0
                || String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 
                || reader.Depth != 3) 
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
 
            // there are no legal attributes and the only content must be text
            if (reader.HasAttributes || (reader.Read() && reader.MoveToContent() != XmlNodeType.Text))
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
 
            // get the Value
            return reader.ReadString(); 
        } 

        ///  
        /// Get the part uri and it's content type from the current Reference tag
        /// 
        /// 
        /// contentType extracted from the query portion of the Uri 
        /// PackagePart uri and contentType
        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;
        } 

        /// 
        /// Parses a Reference tag
        ///  
        /// 
        /// partManifestEntry that represents the state of the tag 
        private static PartManifestEntry ParseReference(XmlReader reader) 
        {
            Debug.Assert(reader != null); 

            //  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 relationshipSelectors = null; 

            // move through the sub-tags: ,  and optional  
            string hashAlgorithm = null;    // digest method
            string hashValue = null;        // digest value
            List 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); 
        }

        /// 
        /// Parses Transforms tag 
        /// 
        /// node to parse 
        /// Part Uri for the part owning the relationships 
        /// allocates and returns a list of
        /// PackageRelationshipSelectors if Relationship transform 
        /// ordered list of Transform names
        private static List ParseTransformsTag(XmlReader reader, Uri partUri, ref List relationshipSelectors)
        {
            // # reference that signs multiple PackageRelationships 
            // 
            //       
            //           
            //              
            //               
            //              
            //          
            //          
            //       
            //      
            //      ...  
            //  

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

            List 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();
 
                            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(); 

                            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;
        }
 
        /// 
        /// Parse the Relationship-specific Transform 
        ///  
        /// 
        ///  
        /// may be allocated but will never be empty
        private static void ParseRelationshipsTransform(XmlReader reader, Uri partUri, ref List relationshipSelectors)
        {
            Uri owningPartUri = PackUriHelper.GetSourcePartUriFromRelationshipPartUri(partUri); 

            // find all of the Relationship tags of form: 
            //       
            // or
            //       
            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)) 
                {
                    // ? 
                    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(); 

                            // we found a legal SourceId so create a selector and continue searching
                            relationshipSelectors.Add(new PackageRelationshipSelector(owningPartUri, PackageRelationshipSelectorType.Id, id));
                            continue; 
                        }
                    }   // ? 
                    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(); 
 
                            // 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)); 
            }
        } 

        /// 
        /// Generate Manifest tag
        ///  
        /// manager
        /// current Xml doc 
        /// hash algorithm to hash with 
        /// parts to sign - possibly null
        /// relationshipSelectors that represent the 
        /// relationships that have to be signed - possibly null
        /// 
        internal static XmlNode GenerateManifest(
            PackageDigitalSignatureManager manager, 
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm, 
            IEnumerable parts, 
            IEnumerable 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)); 

            //  
            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 Methods
        // 
        //----------------------------------------------------- 
        /// 
        /// GenerateRelationshipSigningReferences 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        /// number of references to be signed 
        private static int GenerateRelationshipSigningReferences(
            PackageDigitalSignatureManager manager, 
            XmlDocument xDoc, HashAlgorithm hashAlgorithm,
            IEnumerable relationshipSelectors,
            XmlNode manifest)
        { 
            // PartUri - and its list of PackageRelationshipSelectors
            Dictionary> partAndSelectorDictionary 
                = new Dictionary>(); 

            foreach (PackageRelationshipSelector relationshipSelector in relationshipSelectors) 
            {
                //update the partAndSelectorDictionary for each relationshipSelector
                Uri relationshipPartUri = PackUriHelper.GetRelationshipPartUri(relationshipSelector.SourceUri);
 
                List selectors;
                if (partAndSelectorDictionary.ContainsKey(relationshipPartUri)) 
                    selectors = partAndSelectorDictionary[relationshipPartUri]; 
                else
                { 
                    selectors = new List();
                    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  tag. It will become:
            // 
            // 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 Uri ParsePartUriAttribute(String attrValue, out ContentType contentType)
        { 
            // extract the query portion - do not ask the Uri class for it because it will escape
            // characters and we want to do a simple text comparison later
            contentType = ContentType.Empty;             // out argument must always be set
            int index = attrValue.IndexOf('?'); 
            Uri uri = null;
            if (index > 0) 
            { 
                try
                { 
                    // ensure it starts with the correct query prefix
                    String query = attrValue.Substring(index);
                    if ((query.Length > _contentTypeQueryStringPrefix.Length) && (query.StartsWith(_contentTypeQueryStringPrefix, StringComparison.Ordinal)))
                    { 
                        // truncate the prefix and validate
                        contentType = new ContentType(query.Substring(_contentTypeQueryStringPrefix.Length)); 
 
                    }
 
                    // now construct the uri without the query
                    uri = PackUriHelper.ValidatePartUri(new Uri(attrValue.Substring(0, index), UriKind.Relative));
                }
                catch (ArgumentException ae) 
                {
                    // Content type or part uri is malformed so we have a bad signature. 
                    // Rethrow as XmlException so outer validation loop can catch it and return validation result. 
                    throw new XmlException(SR.Get(SRID.PartReferenceUriMalformed), ae);
                } 
            }

            // throw if we failed
            if (contentType.ToString().Length <= 0) 
                throw new XmlException(SR.Get(SRID.PartReferenceUriMalformed));
 
            return uri; 
        }
 
        /// 
        /// Generates a Reference tag that contains a Relationship transform
        /// 
        /// manager 
        /// name of the relationship part
        /// current xml document 
        /// hash algorithm = digest method 
        /// relationshipSelectors that represent the relationships to sign 
        /// ContentType is known and part name can be derived from the relationship collection 
        private static XmlNode GenerateRelationshipSigningReference(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm, 
            Uri relationshipPartName,
            IEnumerable relationshipSelectors) 
        { 
            string relPartContentType = PackagingUtilities.RelationshipPartContentType.ToString();
 
            // 
            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) 

            //  
            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);

            //  or
            //  
            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 = 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);

            //  
            reference.AppendChild(GenerateDigestMethod(manager, xDoc));
 
            //  - 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; 
        }
 
        private static XmlNode GeneratePartSigningReference( 
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc, 
            HashAlgorithm hashAlgorithm,
            Uri partName)
        {
            PackagePart part = manager.Package.GetPart(partName); 

            //  
            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]; 

                // 
                XmlElement transforms = xDoc.CreateElement(XTable.Get(XTable.ID.TransformsTagName), SignedXml.XmlDsigNamespaceUrl);
 
                // 
                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);
            } 

            //  
            reference.AppendChild(GenerateDigestMethod(manager, xDoc)); 

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

            return reference; 
        } 

        private static XmlNode GenerateDigestMethod( 
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc)
        {
            //  
            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; 
        }

        private static XmlNode GenerateDigestValueNode(XmlDocument xDoc, HashAlgorithm hashAlgorithm, Stream s, String transformName)
        { 
            // 
            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; 
        }


        //Returns the sorted PackageRelationship collection from a given collection of PackageRelationshipSelectors 
        //Note: All the selectors in the given selector collection are assumed to be for the same Part/PackageRoot
        //This method should be called for a part/packageroot 
        private static IEnumerable GetRelationships( 
            PackageDigitalSignatureManager manager,
            IEnumerable relationshipSelectorsWithSameSource) 
        {
            SortedDictionary
                relationshipsDictionarySortedById = new SortedDictionary(StringComparer.Ordinal);
 
            foreach (PackageRelationshipSelector relationshipSelector in relationshipSelectorsWithSameSource)
            { 
                // loop and accumulate and group them by owning Part 
                foreach (PackageRelationship r in relationshipSelector.Select(manager.Package))
                { 
                    // add relationship
                    if(!relationshipsDictionarySortedById.ContainsKey(r.Id))
                        relationshipsDictionarySortedById.Add(r.Id, r);
                } 
            }
            return relationshipsDictionarySortedById.Values; 
        } 

        //------------------------------------------------------ 
        //
        //  Private Members
        //
        //------------------------------------------------------ 
        const string _contentTypeQueryStringPrefix = "?ContentType=";
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  Signature processor implementation that follows the Feb 12, 2002 W3C DigSig Recommendation 
//
//  Generates and consumes Manifest portion of the 
//  XmlDSig-compliant digital signatures based on the subset
//  specified by the OPC file format.
//
// Manifest appears in this context: 
//
//       
//          ... 
//          ...
//       
//
// Manifest form is:
//
//       
//
//          # simple reference - no transforms 
//           
//              
//              ...  
//          
//
//          # simple reference with c14n canonicalization transform
//           
//              
//                   
//               
//              
//              ...  
//          
//
//          # reference that signs multiple PackageRelationships
//           
//              
//                   
//                       
//                      
//                       
//                  
//                  
//              
//               
//              ... 
//           
// 
//          # reference that signs PackageRelationships by Relationship Type and a single Relationship by ID
//           
//              
//                  
//                      
//                       
//                  
//                   
//               
//              
//              ...  
//          
//          ...
//
//       

// History: 
//  01/25/2004: BruceMac: Initial Implementation 
//
//----------------------------------------------------------------------------- 

using System;
using System.Diagnostics;
using System.Collections; 
using System.Collections.Generic;
//using System.Security;                      // for SecurityCritical and SecurityTreatAsSafe 
using System.Security.Cryptography; 
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates; 
using System.Xml;
using System.IO;
using System.Windows;
using System.IO.Packaging; 
using MS.Internal;
 
namespace MS.Internal.IO.Packaging 
{
    ///  
    /// Manifest generator/parser
    /// 
    /// See: http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/ for details
    internal static class XmlSignatureManifest 
    {
        //----------------------------------------------------- 
        // 
        //  Internal Methods
        // 
        //-----------------------------------------------------
        /// 
        /// Parse the Manifest tag
        ///  
        /// 
        /// XmlReader positioned to the Manifest tag 
        ///  
        /// 
        ///  
        internal static void ParseManifest(
            PackageDigitalSignatureManager manager,
            XmlReader reader,
            out List partManifest, 
            out List partEntryManifest,
            out List relationshipManifest) 
        { 
            Invariant.Assert(manager != null);
            Invariant.Assert(reader != null); 

            // these are empty (non-null) when nothing is found
            partManifest = new List();
            partEntryManifest = new List(); 
            relationshipManifest = new List();
 
            // 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  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  tag
            if (referenceCount == 0)
                throw new XmlException(SR.Get(SRID.PackageSignatureCorruption)); 
        }
 
        ///  
        /// Parse the DigestMethod tag
        ///  
        /// 
        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;
        }
 
        /// 
        /// Parse the DigestValue tag 
        ///  
        /// 
        private static string ParseDigestValueTag(XmlReader reader) 
        {
            Debug.Assert(reader != null);

            // verify namespace and lack of attributes 
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) > 0
                || String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 
                || reader.Depth != 3) 
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
 
            // there are no legal attributes and the only content must be text
            if (reader.HasAttributes || (reader.Read() && reader.MoveToContent() != XmlNodeType.Text))
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
 
            // get the Value
            return reader.ReadString(); 
        } 

        ///  
        /// Get the part uri and it's content type from the current Reference tag
        /// 
        /// 
        /// contentType extracted from the query portion of the Uri 
        /// PackagePart uri and contentType
        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;
        } 

        /// 
        /// Parses a Reference tag
        ///  
        /// 
        /// partManifestEntry that represents the state of the tag 
        private static PartManifestEntry ParseReference(XmlReader reader) 
        {
            Debug.Assert(reader != null); 

            //  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 relationshipSelectors = null; 

            // move through the sub-tags: ,  and optional  
            string hashAlgorithm = null;    // digest method
            string hashValue = null;        // digest value
            List 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); 
        }

        /// 
        /// Parses Transforms tag 
        /// 
        /// node to parse 
        /// Part Uri for the part owning the relationships 
        /// allocates and returns a list of
        /// PackageRelationshipSelectors if Relationship transform 
        /// ordered list of Transform names
        private static List ParseTransformsTag(XmlReader reader, Uri partUri, ref List relationshipSelectors)
        {
            // # reference that signs multiple PackageRelationships 
            // 
            //       
            //           
            //              
            //               
            //              
            //          
            //          
            //       
            //      
            //      ...  
            //  

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

            List 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();
 
                            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(); 

                            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;
        }
 
        /// 
        /// Parse the Relationship-specific Transform 
        ///  
        /// 
        ///  
        /// may be allocated but will never be empty
        private static void ParseRelationshipsTransform(XmlReader reader, Uri partUri, ref List relationshipSelectors)
        {
            Uri owningPartUri = PackUriHelper.GetSourcePartUriFromRelationshipPartUri(partUri); 

            // find all of the Relationship tags of form: 
            //       
            // or
            //       
            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)) 
                {
                    // ? 
                    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(); 

                            // we found a legal SourceId so create a selector and continue searching
                            relationshipSelectors.Add(new PackageRelationshipSelector(owningPartUri, PackageRelationshipSelectorType.Id, id));
                            continue; 
                        }
                    }   // ? 
                    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(); 
 
                            // 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)); 
            }
        } 

        /// 
        /// Generate Manifest tag
        ///  
        /// manager
        /// current Xml doc 
        /// hash algorithm to hash with 
        /// parts to sign - possibly null
        /// relationshipSelectors that represent the 
        /// relationships that have to be signed - possibly null
        /// 
        internal static XmlNode GenerateManifest(
            PackageDigitalSignatureManager manager, 
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm, 
            IEnumerable parts, 
            IEnumerable 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)); 

            //  
            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 Methods
        // 
        //----------------------------------------------------- 
        /// 
        /// GenerateRelationshipSigningReferences 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        /// number of references to be signed 
        private static int GenerateRelationshipSigningReferences(
            PackageDigitalSignatureManager manager, 
            XmlDocument xDoc, HashAlgorithm hashAlgorithm,
            IEnumerable relationshipSelectors,
            XmlNode manifest)
        { 
            // PartUri - and its list of PackageRelationshipSelectors
            Dictionary> partAndSelectorDictionary 
                = new Dictionary>(); 

            foreach (PackageRelationshipSelector relationshipSelector in relationshipSelectors) 
            {
                //update the partAndSelectorDictionary for each relationshipSelector
                Uri relationshipPartUri = PackUriHelper.GetRelationshipPartUri(relationshipSelector.SourceUri);
 
                List selectors;
                if (partAndSelectorDictionary.ContainsKey(relationshipPartUri)) 
                    selectors = partAndSelectorDictionary[relationshipPartUri]; 
                else
                { 
                    selectors = new List();
                    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  tag. It will become:
            // 
            // 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 Uri ParsePartUriAttribute(String attrValue, out ContentType contentType)
        { 
            // extract the query portion - do not ask the Uri class for it because it will escape
            // characters and we want to do a simple text comparison later
            contentType = ContentType.Empty;             // out argument must always be set
            int index = attrValue.IndexOf('?'); 
            Uri uri = null;
            if (index > 0) 
            { 
                try
                { 
                    // ensure it starts with the correct query prefix
                    String query = attrValue.Substring(index);
                    if ((query.Length > _contentTypeQueryStringPrefix.Length) && (query.StartsWith(_contentTypeQueryStringPrefix, StringComparison.Ordinal)))
                    { 
                        // truncate the prefix and validate
                        contentType = new ContentType(query.Substring(_contentTypeQueryStringPrefix.Length)); 
 
                    }
 
                    // now construct the uri without the query
                    uri = PackUriHelper.ValidatePartUri(new Uri(attrValue.Substring(0, index), UriKind.Relative));
                }
                catch (ArgumentException ae) 
                {
                    // Content type or part uri is malformed so we have a bad signature. 
                    // Rethrow as XmlException so outer validation loop can catch it and return validation result. 
                    throw new XmlException(SR.Get(SRID.PartReferenceUriMalformed), ae);
                } 
            }

            // throw if we failed
            if (contentType.ToString().Length <= 0) 
                throw new XmlException(SR.Get(SRID.PartReferenceUriMalformed));
 
            return uri; 
        }
 
        /// 
        /// Generates a Reference tag that contains a Relationship transform
        /// 
        /// manager 
        /// name of the relationship part
        /// current xml document 
        /// hash algorithm = digest method 
        /// relationshipSelectors that represent the relationships to sign 
        /// ContentType is known and part name can be derived from the relationship collection 
        private static XmlNode GenerateRelationshipSigningReference(
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc,
            HashAlgorithm hashAlgorithm, 
            Uri relationshipPartName,
            IEnumerable relationshipSelectors) 
        { 
            string relPartContentType = PackagingUtilities.RelationshipPartContentType.ToString();
 
            // 
            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) 

            //  
            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);

            //  or
            //  
            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 = 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);

            //  
            reference.AppendChild(GenerateDigestMethod(manager, xDoc));
 
            //  - 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; 
        }
 
        private static XmlNode GeneratePartSigningReference( 
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc, 
            HashAlgorithm hashAlgorithm,
            Uri partName)
        {
            PackagePart part = manager.Package.GetPart(partName); 

            //  
            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]; 

                // 
                XmlElement transforms = xDoc.CreateElement(XTable.Get(XTable.ID.TransformsTagName), SignedXml.XmlDsigNamespaceUrl);
 
                // 
                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);
            } 

            //  
            reference.AppendChild(GenerateDigestMethod(manager, xDoc)); 

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

            return reference; 
        } 

        private static XmlNode GenerateDigestMethod( 
            PackageDigitalSignatureManager manager,
            XmlDocument xDoc)
        {
            //  
            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; 
        }

        private static XmlNode GenerateDigestValueNode(XmlDocument xDoc, HashAlgorithm hashAlgorithm, Stream s, String transformName)
        { 
            // 
            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; 
        }


        //Returns the sorted PackageRelationship collection from a given collection of PackageRelationshipSelectors 
        //Note: All the selectors in the given selector collection are assumed to be for the same Part/PackageRoot
        //This method should be called for a part/packageroot 
        private static IEnumerable GetRelationships( 
            PackageDigitalSignatureManager manager,
            IEnumerable relationshipSelectorsWithSameSource) 
        {
            SortedDictionary
                relationshipsDictionarySortedById = new SortedDictionary(StringComparer.Ordinal);
 
            foreach (PackageRelationshipSelector relationshipSelector in relationshipSelectorsWithSameSource)
            { 
                // loop and accumulate and group them by owning Part 
                foreach (PackageRelationship r in relationshipSelector.Select(manager.Package))
                { 
                    // add relationship
                    if(!relationshipsDictionarySortedById.ContainsKey(r.Id))
                        relationshipsDictionarySortedById.Add(r.Id, r);
                } 
            }
            return relationshipsDictionarySortedById.Values; 
        } 

        //------------------------------------------------------ 
        //
        //  Private Members
        //
        //------------------------------------------------------ 
        const string _contentTypeQueryStringPrefix = "?ContentType=";
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK