XmlSignatureManifest.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Packaging / XmlSignatureManifest.cs / 1305600 / 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;
using MS.Internal.WindowsBase; 
 
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