DigitalSignatureProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / TrustUi / MS / Internal / documents / DigitalSignatureProvider.cs / 1 / DigitalSignatureProvider.cs

                            //------------------------------------------------------------------------------ 
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved. 
//
//  
// 
// 
// History: 
// 05/11/05: [....]: Created.
// 01/17/06: [....]: Refactored 
//-----------------------------------------------------------------------------

using System;
using System.Collections; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.IO; 
using System.IO.Packaging;
using System.Net; 
using System.Security;              // For elevations
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;  // For elevations
using System.Windows.TrustUI; 
using System.Windows.Xps.Packaging;
 
using MS.Internal.PresentationUI;   // For FriendAccessAllowed 

namespace MS.Internal.Documents 
{
    /// 
    /// DigitalSignatureProvider is used to connect DRP to Xps dig sig
    ///  
    [FriendAccessAllowed]
    internal class DigitalSignatureProvider : IDigitalSignatureProvider 
    { 
        #region Constructors
        //----------------------------------------------------- 
        //
        //  Constructors
        //
        //----------------------------------------------------- 

        ///  
        /// The constructor 
        /// 
        /// The package whose signatures this provider 
        /// will manipulate
        /// 
        /// Critical
        ///  1) Setting critical for set property XpsDocument from package 
        ///     passed in as a parameter
        ///  2) Setting critical for set property FixedDocument from FixedDocumentSequence 
        ///  
        [SecurityCritical]
        public DigitalSignatureProvider(Package package) 
        {
            if (package != null)
            {
                XpsDocument = new XpsDocument(package); 
                FixedDocumentSequence = XpsDocument.FixedDocumentSequenceReader;
                if (FixedDocumentSequence == null) 
                { 
                    throw new ArgumentException(SR.Get(SRID.DigitalSignatureNoFixedDocumentSequence));
                } 
                // We only want to save the first fixed document since all
                // XPS Viewer signature definitions will be added to the first
                // fixed document.
                FixedDocument = 
                    FixedDocumentSequence.FixedDocuments[0];
            } 
            else 
            {
                throw new ArgumentNullException("package"); 
            }
        }
        #endregion Constructors
 
        #region IDigitalSignatureProvider
        //------------------------------------------------------ 
        // 
        //  IDigitalSignatureProvider
        // 
        //-----------------------------------------------------

        /// 
        /// See IDigitalSignatureProvider 
        /// 
        ///  
        /// Critical - get: get_Signatures is defined in a non-APTCA assembly. 
        /// TreatAsSafe - get: returning whether an xps document is signed or not is considered safe.
        ///  
        bool IDigitalSignatureProvider.IsSigned
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                return XpsDocument.Signatures.Count > 0; 
            } 
        }
 
        /// 
        /// See IDigitalSignatureProvider
        /// 
        /// Critical - get: Modifies Critical For Set values for _isSignableCacheValid 
        ///            and _isSignableCache as a result of querying the IsSignable
        ///            property. 
        /// TreatAsSafe - get: This is a safe action -- the cached values are used to 
        ///               cache the result of IsSignable, and this is where that's done.
        ///               Calling IsSignable itself is considered safe. 
        /// 
        /// 
        bool IDigitalSignatureProvider.IsSignable
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            { 
                if (!_isSignableCacheValid.Value)
                { 
                    _isSignableCache.Value = XpsDocument.IsSignable;
                    _isSignableCacheValid.Value = true;
                }
 
                return _isSignableCache.Value;
            } 
        } 

        ///  
        /// See IDigitalSignatureProvider
        /// 
        bool IDigitalSignatureProvider.HasRequests
        { 
            get
            { 
                bool rtn = false; 

                foreach (DigitalSignature digitalSignature in ((IDigitalSignatureProvider)this).Signatures) 
                {
                    if (digitalSignature.SignatureState == SignatureStatus.NotSigned)
                    {
                        rtn = true; 
                        break;
                    } 
                } 

                return rtn; 
            }
        }

        ///  
        /// See IDigitalSignatureProvider
        ///  
        ///  
        /// Critical
        ///  1) We elevate a few permissions in order to be able to sign the 
        ///     document. These elevations include Open and Sign on the
        ///     KeyContainerPermission, OpenStore and EnumerateCertificates on
        ///     the StorePermission, and file read/write to write the signatures
        ///     back to the package. 
        ///  2) We set the XpsDigitalSignature property on the DigitalSignature
        ///  3) The list of signatures is modified, in this case to add the 
        ///     supplied signature. 
        /// TreatAsSafe
        ///  1) The actual signing of the document is safe since it is based on 
        ///     user input, uses a certificate selected by the user via a Win32
        ///     certificate picker, and uses a DigitalSignature instance that was
        ///     constructed via critical code (enforced by a critical constructor).
        ///     The elevations here are local and limited to gaining the minimum 
        ///     functionality required to sign the document.
        ///  2) Setting the XpsDigitalSignature property is safe because we are 
        ///     assigning to it the value we get from the signing operation, 
        ///     which is safe as above.
        ///  3) The DigitalSignature we are adding to the list is guaranteed to 
        ///     have been created by critical code.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        void IDigitalSignatureProvider.SignDocument(DigitalSignature digitalSignature) 
        {
            AssertIsSignable(); 
 
            XpsDigSigPartAlteringRestrictions reachRestrictions = XpsDigSigPartAlteringRestrictions.None;
 

            if (digitalSignature.IsDocumentPropertiesRestricted)
            {
                reachRestrictions |= XpsDigSigPartAlteringRestrictions.CoreMetadata; 
            }
 
            // If additional signatures should invalidate this signature, we 
            // need to sign the signature origin part
            if (digitalSignature.IsAddingSignaturesRestricted) 
            {
                reachRestrictions |= XpsDigSigPartAlteringRestrictions.SignatureOrigin;
            }
 
            // a null guid means there was no associated spot, so create a guid
            if (digitalSignature.GuidID == null) 
            { 
                digitalSignature.GuidID = Guid.NewGuid();
            } 

            //
            // Build up the required permisson set and assert
            // 
            FileIOPermission filePerm = new FileIOPermission(PermissionState.None);
            // This is actually required to create a stream within a stream.  We elevated for read/write in a different 
            // place to actually open the stream for read/write.  It appears that creating another stream pointing into 
            // the same package requires read/write permissions again.
            filePerm.AllFiles = FileIOPermissionAccess.Read | FileIOPermissionAccess.Write | FileIOPermissionAccess.PathDiscovery; 

            PermissionSet perms = new PermissionSet(PermissionState.None);
            perms.AddPermission(new KeyContainerPermission(KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Sign));
            perms.AddPermission(new StorePermission(StorePermissionFlags.OpenStore | StorePermissionFlags.EnumerateCertificates)); 
            perms.AddPermission(filePerm);
 
            XpsDigitalSignature xpsDigitalSignature = null; 

            perms.Assert();  //Blessed 
            try
            {
                xpsDigitalSignature =
                    XpsDocument.SignDigitally( 
                        digitalSignature.Certificate,
                        true, 
                        reachRestrictions, 
                        (Guid)digitalSignature.GuidID,
                        false  /* don't re-verify IsSignable, we've already done it */ 
                        );
            }
            finally
            { 
                PermissionSet.RevertAssert();
            } 
 
            if (xpsDigitalSignature != null)
            { 
                // Fill in relevant fields from the XPS signature
                digitalSignature.XpsDigitalSignature = xpsDigitalSignature;
                digitalSignature.SignatureState = SignatureStatus.Valid;
                digitalSignature.SignedOn = xpsDigitalSignature.SigningTime; 

                // Save the simple name from the certificate as the subject name 
                // in the signature 
                digitalSignature.SubjectName =
                    digitalSignature.Certificate.GetNameInfo( 
                        X509NameType.SimpleName,
                        false /* don't include issuer name */);

                // Add the new signature to the list (if it isn't already there). 
                // That is a possibility since the first signature in a document
                // is always added as a signature definition and a signature. 
                if (!DigitalSignatureList.Contains(digitalSignature)) 
                {
                    DigitalSignatureList.Add(digitalSignature); 
                }
            }
        }
 
        /// 
        /// See IDigitalSignatureProvider 
        ///  
        /// 
        /// Critical 
        ///  1) The list of signatures is modified, in this case to add the
        ///     supplied signature request.
        /// TreatAsSafe
        ///  1) The DigitalSignature we are adding to the list is guaranteed to 
        ///     have been created by critical code.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        Guid IDigitalSignatureProvider.AddRequestSignature(DigitalSignature digitalSignature)
        { 
            AssertIsSignable();

            // Create guid used for signature ID
            Guid guidID = Guid.NewGuid(); 

            // Create a new SignatureDefinition 
            XpsSignatureDefinition xpsSignatureDefinition = new XpsSignatureDefinition(); 

            // Use the digSig to setup the SignatureDefinition. 
            xpsSignatureDefinition.RequestedSigner = digitalSignature.SubjectName;
            xpsSignatureDefinition.Intent = digitalSignature.Reason;
            xpsSignatureDefinition.SigningLocale = digitalSignature.Location;
            xpsSignatureDefinition.SignBy = digitalSignature.SignedOn; 

            // Use our new guid to setup the ID 
            xpsSignatureDefinition.SpotId = guidID; 

            // Add the signature definition to the document 
            FixedDocument.AddSignatureDefinition(xpsSignatureDefinition);
            FixedDocument.CommitSignatureDefinition();

            // Set the signature's status to Not Signed before adding to our list 
            digitalSignature.SignatureState = SignatureStatus.NotSigned;
 
            // Add the new signature to our list of signatures and definitions 
            DigitalSignatureList.Add(digitalSignature);
 
            return guidID;
        }

        ///  
        /// See IDigitalSignatureProvider
        ///  
        ///  
        /// Critical
        ///  1) The list of signatures is modified, in this case to remove the 
        ///     signature request with the given GUID.
        /// 
        [SecurityCritical]
        void IDigitalSignatureProvider.RemoveRequestSignature(Guid spotId) 
        {
            AssertIsSignable(); 
 
            XpsSignatureDefinition definition = FindSignatureDefinition(spotId);
            if (definition != null) 
            {
                FixedDocument.RemoveSignatureDefinition(definition);
                FixedDocument.CommitSignatureDefinition();
            } 

            // Loop through the signature list and remove the entry for the 
            // requested signature 
            foreach (DigitalSignature signature in DigitalSignatureList)
            { 
                if (signature.GuidID == spotId)
                {
                    // We only want to remove unsigned signature definitions
                    // (requested signatures) and not actual signatures. 
                    if (signature.SignatureState == SignatureStatus.NotSigned)
                    { 
                        DigitalSignatureList.Remove(signature); 
                    }
 
                    // It is safe to remove an element from the list that we're
                    // currently enumerating because we stop enumerating as soon
                    // as we find the element we're looking for.
                    break; 
                }
            } 
        } 

        ///  
        /// See IDigitalSignatureProvider
        /// 
        /// 
        /// Critical 
        ///  1) The list of signatures is modified, in this case to remove the
        ///     signature with the given GUID. 
        ///  2) Properties on a signature may be modified to update its state 
        ///     when the signature is removed from the document.
        ///  
        [SecurityCritical]
        void IDigitalSignatureProvider.UnsignDocument(Guid id)
        {
            AssertIsSignable(); 

            foreach (DigitalSignature signature in DigitalSignatureList) 
            { 
                if (signature.GuidID == id)
                { 
                    // Remove the associated XpsDigitalSignature from the
                    // document
                    if (signature.XpsDigitalSignature != null)
                    { 
                        XpsDocument.RemoveSignature(signature.XpsDigitalSignature);
                        signature.XpsDigitalSignature = null; 
                    } 

                    // Check if the document contains a signature definition 
                    // corresponding to this signature
                    bool matchesDefinition = (FindSignatureDefinition(id) != null);

                    // If the signature matches a signature definition in the 
                    // document, mark the signature as NotSigned (i.e. an
                    // unsigned request) but leave it in the list 
                    if (matchesDefinition) 
                    {
                        signature.SignatureState = SignatureStatus.NotSigned; 
                    }
                    else
                    {
                        // Remove the signature from the list 
                        DigitalSignatureList.Remove(signature);
                    } 
 
                    // It is safe to remove an element from the list that we're
                    // currently enumerating because we stop enumerating as soon 
                    // as we find the element we're looking for.
                    break;
                }
            } 
        }
 
        ///  
        /// See IDigitalSignatureProvider
        ///  
        /// 
        /// Critical
        ///  1) Setting critical property DigitalSignatureList
        ///  2) Setting Critical property SignatureState on a DigitalSignature 
        ///     object
        /// TreatAsSafe 
        ///  1) The list comes directly from the critical for set package. This 
        ///     is guaranteed because the list is generated by the critical
        ///     function GetSignaturesFromPackage. 
        ///  2) The value comes from the verification of the corresponding XPS
        ///     signature, and the corresponding signature comes from a
        ///     critical for set property on the DigitalSignature.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        void IDigitalSignatureProvider.VerifySignatures() 
        { 
            // If we haven't yet retrieved signatures from the package, do so
            if (DigitalSignatureList == null) 
            {
                DigitalSignatureList = GetSignaturesFromPackage();
            }
 
            // Verify each XPS digital signature from the map
            // This will update the status of the signatures in the list also 
            foreach (DigitalSignature signature in DigitalSignatureList) 
            {
 
                if (signature.XpsDigitalSignature != null)
                {
                    signature.SignatureState =
                        VerifyXpsDigitalSignature(signature.XpsDigitalSignature); 
                }
            } 
        } 

        ///  
        /// See IDigitalSignatureProvider
        /// 
        IList IDigitalSignatureProvider.GetAllCertificates()
        { 
            List certificateList = new List();
 
            foreach (DigitalSignature signature in ((IDigitalSignatureProvider)this).Signatures) 
            {
                X509Certificate2 certificate = signature.Certificate; 

                if (certificate != null && !certificateList.Contains(certificate))
                {
                    certificateList.Add(certificate); 
                }
            } 
 
            return certificateList;
        } 

        /// 
        /// See IDigitalSignatureProvider
        ///  
        IDictionary IDigitalSignatureProvider.GetCertificateStatus(
            IList certificates) 
        { 
            Dictionary certificateStatusTable =
                new Dictionary(); 

            foreach (X509Certificate2 certificate in certificates)
            {
                certificateStatusTable.Add( 
                    certificate,
                    GetCertificateStatus(certificate)); 
            } 

            return certificateStatusTable; 
        }

        /// 
        /// Returns a Read Only collection of our Digital Signatures. 
        /// 
        ///  
        /// Critical 
        ///  1) Setting critical property DigitalSignatureList
        ///  2) Accesses DigitalSignatureList to create a read-only list of 
        ///     signatures
        /// TreatAsSafe
        ///  1) The list comes directly from the critical for set package. This
        ///     is guaranteed because the list is generated by the critical 
        ///     function GetSignaturesFromPackage.
        ///  2) DigitalSignatureList is critical to prevent unauthorized code 
        ///     from writing to the list. Wrapping it in a ReadOnlyCollection 
        ///     and returning that wrapper ensures that this condition is met.
        ///  
        ReadOnlyCollection IDigitalSignatureProvider.Signatures
        {
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            {
                // If we have not yet read signatures from the package, load them 
                if (DigitalSignatureList == null) 
                {
                    DigitalSignatureList = GetSignaturesFromPackage(); 
                }

                if (_readOnlySignatureList.Value == null)
                { 
                    _readOnlySignatureList.Value =
                        new ReadOnlyCollection(DigitalSignatureList); 
                } 

                return _readOnlySignatureList.Value; 
            }
        }

        #endregion IDigitalSignatureProvider 

        #region Private Methods 
        //------------------------------------------------------ 
        //
        //  Private Methods 
        //
        //------------------------------------------------------

        ///  
        /// Returns a list of all the DigitalSignature objects from the package.
        ///  
        /// A list of DigitalSignature objects 
        /// 
        /// Critical 
        ///  1) Modifies critical properties on a DigitalSignature structure.
        ///  2) Calls a critical method GetDigSigFromXpsDigSig().
        ///  3) Calls critical method GetDigSigFromSignatureDefinition()
        /// TreatAsSafe 
        ///  1) The DigitalSignature structures that contain Guids that match
        ///     a signature spot that exists in the XPS package are replicated 
        ///     into the DigitalSignatures that the provider knows about.  These signatures 
        ///     were already created by another viewer of the document and are valid
        ///     since they were signed within the container.  We are simply packaging 
        ///     them up into our DigitalSignature instances for our use.
        ///  2) This critical call is what actually constructs the DigitalSignature
        ///     given a XpsDigitalSignature and is therefore safe for the same reasons
        ///     as #1 since the XpsDigitalSignature is a signature coming from a signed 
        ///     package.
        ///  3) This action is also safe, since it constructs a DigitalSignature 
        ///     from an XpsSignatureDefinition that is also from a package. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private IList GetSignaturesFromPackage()
        {
            IList signatureList = new List();
 
            // This will contain a mapping of GUIDs to signature definitions so
            // that we can easily look up the signature definition (if any) that 
            // corresponds with a signature 
            IDictionary signatureDefinitionMap =
                new Dictionary(); 

            // This will contain a list of all the signature definitions that do
            // not have an associated GUID, which means that they have to be
            // requested signatures 
            IList requestedSignatureList =
                new List(); 
 
            // Enumerate all the signature definitions in all of the fixed
            // documents in the XPS document to generate the map of GUIDs to 
            // signature definitions

            foreach (IXpsFixedDocumentReader fixedDocument in FixedDocumentSequence.FixedDocuments)
            { 
                ICollection documentSignatureDefinitionList =
                    fixedDocument.SignatureDefinitions; 
 
                if (documentSignatureDefinitionList != null)
                { 
                    // Add each signature definition to either the GUID map or
                    // the list of requested signatures
                    foreach (XpsSignatureDefinition signatureDefinition in documentSignatureDefinitionList)
                    { 
                        // If the signature definition has a GUID, add it to the map
                        if (signatureDefinition.SpotId != null) 
                        { 
                            signatureDefinitionMap.Add(signatureDefinition.SpotId.Value, signatureDefinition);
                        } 
                        // If it does not have a GUID it cannot match a signature yet,
                        // so add it to the list of requested signatures
                        else
                        { 
                            requestedSignatureList.Add(signatureDefinition);
                        } 
                    } 
                }
            } 

            // Now loop through all the XpsDigitalSignatures, matching them with
            // signature definitions by GUID to get the signature fields that
            // are only found in signature definitions. 
            foreach (XpsDigitalSignature xpsDigitalSignature in XpsDocument.Signatures)
            { 
                // Convert the XPS signature into our format 
                DigitalSignature digitalSignature =
                    ConvertXpsDigitalSignature(xpsDigitalSignature); 

                // Check if the signature corresponds to a definition by seeing
                // if the GUID is in the signature definition map
                bool definitionFound = 
                    xpsDigitalSignature.Id.HasValue &&
                    signatureDefinitionMap.ContainsKey(xpsDigitalSignature.Id.Value); 
 
                // If the signature corresponds to a signature definition, copy
                // fields from the corresponding definition 
                if (definitionFound)
                {
                    XpsSignatureDefinition signatureDefinition =
                        signatureDefinitionMap[xpsDigitalSignature.Id.Value]; 

                    // Copy SignatureDefinition fields 
                    digitalSignature.Reason = signatureDefinition.Intent; 
                    digitalSignature.Location = signatureDefinition.SigningLocale;
 
                    // Now that we have found a signature that matches this
                    // signature definition, it can no longer match any other
                    // signatures by GUID and we can remove it from the map.
                    signatureDefinitionMap.Remove(xpsDigitalSignature.Id.Value); 
                }
 
                signatureList.Add(digitalSignature); 
            }
 
            // What is left over in the signatureDefinitionMap are definitions
            // that don't have matching XpsDigSigs.  Add these as requested
            // signatures.
            foreach (XpsSignatureDefinition signatureDefinition in signatureDefinitionMap.Values) 
            {
                //Add this request signature to our list. 
                signatureList.Add(ConvertXpsSignatureDefinition(signatureDefinition)); 
            }
 
            // Add all the definitions we already knew were requested signatures
            foreach (XpsSignatureDefinition definition in requestedSignatureList)
            {
                //Add this request signature to our list. 
                signatureList.Add(ConvertXpsSignatureDefinition(definition));
            } 
 
            return signatureList;
        } 

        /// 
        /// Maps an XpsDigitalSignature to our DigitalSignature.
        ///  
        /// The signature to convert
        /// A DigitalSignature that corresponds to the signature 
        /// passed in as a parameter 
        /// 
        /// Critical 
        ///  1) Creates a DigitalSignature instance from the XpsDigitalSignature
        ///     input.
        /// 
        [SecurityCritical] 
        private static DigitalSignature ConvertXpsDigitalSignature(XpsDigitalSignature xpsDigitalSignature)
        { 
            DigitalSignature digitalSignature = new DigitalSignature(); 

            digitalSignature.XpsDigitalSignature = xpsDigitalSignature; 

            X509Certificate2 x509Certificate2 =
                xpsDigitalSignature.SignerCertificate as X509Certificate2;
 
            digitalSignature.SignatureState = SignatureStatus.Unknown;
 
            // Copy simple fields if cert isn't null.  If it is null then the 
            // cert wasn't embedded into container so don't copy cert related
            // fields. 
            if (x509Certificate2 != null)
            {
                digitalSignature.Certificate = x509Certificate2;
                digitalSignature.SignedOn = xpsDigitalSignature.SigningTime; 

                // save the simple name from the certificate as the subject name 
                // in the signature 
                digitalSignature.SubjectName =
                    x509Certificate2.GetNameInfo( 
                        X509NameType.SimpleName,
                        false  /* don't include issuer name */);
            }
 
            digitalSignature.IsDocumentPropertiesRestricted =
                xpsDigitalSignature.DocumentPropertiesRestricted; 
 
            // If the signature origin part is signed, adding new signatures
            // will invalidate this signature 
            digitalSignature.IsAddingSignaturesRestricted =
                xpsDigitalSignature.SignatureOriginRestricted;

            //These fields come from a Signature Definition. 
            digitalSignature.Reason = string.Empty;
            digitalSignature.Location = string.Empty; 
 
            return digitalSignature;
        } 

        /// 
        /// Maps an XpsSignatureDefinition to our DigitalSignature.
        ///  
        /// The signature definition to
        /// convert 
        /// A DigitalSignature representing a requested signature with 
        /// signature status NotSigned
        ///  
        /// Critical
        ///  1) Creates a DigitalSignature instance from the
        ///     XpsSignatureDefinition input.
        ///  
        [SecurityCritical]
        private static DigitalSignature ConvertXpsSignatureDefinition(XpsSignatureDefinition signatureDefinition) 
        { 
            //Create new DigSig.  This is a request and will have the status NotSigned.
            DigitalSignature digitalSignature = new DigitalSignature(); 
            digitalSignature.SignatureState = SignatureStatus.NotSigned;

            //set fields using the definition.
            digitalSignature.SubjectName = signatureDefinition.RequestedSigner; 
            digitalSignature.Reason = signatureDefinition.Intent;
            digitalSignature.SignedOn = signatureDefinition.SignBy; 
            digitalSignature.Location = signatureDefinition.SigningLocale; 
            digitalSignature.GuidID = signatureDefinition.SpotId;
 
            return digitalSignature;
        }

        ///  
        /// Verifies a given XPS digital signature.
        ///  
        /// This computes and checks the hashes of all the package 
        /// parts, so it may take a long time to complete.
        /// The XPS signature to verify 
        /// The status of the signature
        private static SignatureStatus VerifyXpsDigitalSignature(XpsDigitalSignature xpsDigitalSignature)
        {
            SignatureStatus status = SignatureStatus.Unknown; 

            //Verify signature and map to DRPs SignatureStatus enum. 
            switch (xpsDigitalSignature.Verify()) 
            {
                case VerifyResult.Success: 
                    {
                        status = SignatureStatus.Valid;
                        break;
                    } 

                case VerifyResult.NotSigned: 
                    { 
                        status = SignatureStatus.NotSigned;
                        break; 
                    }

                default:
                    { 
                        status = SignatureStatus.Invalid;
                        break; 
                    } 
            }
 
            return status;
        }

        ///  
        /// Gets the CertificateStatus for a specific certificate.
        ///  
        ///  
        ///     Critical - Need to assert for SecurityPermissions to call into XpsDigitalSignature::VerifyCertificate.
        ///     TreatAsSafe - Data retrieved under elevation is only CertificatePriorityStatus info for Cert 
        ///                   passed in.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private static CertificatePriorityStatus GetCertificateStatus(X509Certificate2 certificate) 
        {
            //Default status is the most severe error:  Corrupted 
            CertificatePriorityStatus certificatePriorityStatus = CertificatePriorityStatus.Corrupted; 
            X509ChainStatusFlags x509ChainStatusFlags;
 
            // The following permissions are nessessary to call the VerifyCertificate method.
            PermissionSet perms = new PermissionSet(PermissionState.None);

            // Permission needed for X509Chain::Build method. 
            perms.AddPermission(new WebPermission(PermissionState.Unrestricted));
            perms.AddPermission(new StorePermission(StorePermissionFlags.AddToStore | 
                                                    StorePermissionFlags.EnumerateCertificates | 
                                                    StorePermissionFlags.OpenStore));
 
            perms.Assert();  //BlessedAssert
            try
            {
                // Use the static VerifyCertificate method on XpsDigitalSignature 
                // to verify the certificate
                x509ChainStatusFlags = XpsDigitalSignature.VerifyCertificate(certificate); 
            } 
            finally
            { 
                PermissionSet.RevertAssert();
            }

            //Strip out all known flags (minus Cyclic and NotSignatureValid).  What is left are any unknown flags 
            //and flags that convert to Corrupted.
            X509ChainStatusFlags x509RemainingFlags = (x509ChainStatusFlags ^ _x509NonCorruptedFlags) & 
                                                     ~(_x509NonCorruptedFlags); 

            //x509ChainStatusFlags is a flag we want to convert to a CertificatePriorityStatus. 
            //First we need to make sure there are no unknown flags.  If there is an unknown
            //flag we assume that it is the worst possible error and leave CertificateStatus
            //set to Corrupted.  Leaving out Cyclic and NotSignatureValid since they also convert
            //to Corrupted. 
            if (x509RemainingFlags == X509ChainStatusFlags.NoError)
            { 
                //The following flags convert to CannotBeVerified 
                if ((x509ChainStatusFlags & _x509CannotBeVerifiedFlags) != X509ChainStatusFlags.NoError)
                { 
                    certificatePriorityStatus = CertificatePriorityStatus.CannotBeVerified;
                }
                //The following flags convert to IssuerNotTrusted
                else if ((x509ChainStatusFlags & _x509IssuerNotTrustedFlags) != X509ChainStatusFlags.NoError) 
                {
                    certificatePriorityStatus = CertificatePriorityStatus.IssuerNotTrusted; 
                } 
                //The following flags convert to Revoked
                else if ((x509ChainStatusFlags & _x509RevokedFlags) != X509ChainStatusFlags.NoError) 
                {
                    certificatePriorityStatus = CertificatePriorityStatus.Revoked;
                }
                //The following flags convert to Expired 
                else if ((x509ChainStatusFlags & _x509ExpiredFlags) != X509ChainStatusFlags.NoError)
                { 
                    certificatePriorityStatus = CertificatePriorityStatus.Expired; 
                }
                //The following flags are all considered Igorable 
                else
                {
                    certificatePriorityStatus = CertificatePriorityStatus.Ok;
                } 
            }
 
            return certificatePriorityStatus; 
        }
 
        /// 
        /// Returns a signature definition in the document that matches a GUID.
        /// 
        /// The GUID to match 
        /// The corresponding signature definition, if one exists.
        ///  
        private XpsSignatureDefinition FindSignatureDefinition(Guid id) 
        {
            XpsSignatureDefinition definition = null; 

            // Loop through our collection of definitions and find the matching
            // GUID. We only need to look at the fixed document we have saved
            // (and not the other documents in the sequence) since we always 
            // save signature definitions to that fixed document.
            foreach (XpsSignatureDefinition signatureDefinition in FixedDocument.SignatureDefinitions) 
            { 
                if (signatureDefinition.SpotId == id)
                { 
                    definition = signatureDefinition;
                    break;
                }
            } 

            return definition; 
        } 

        ///  
        /// Sanity check that the content is signable, and that the check for this
        /// has been done prior to calling Signing-related methods.
        /// 
        private void AssertIsSignable() 
        {
            // We assert that _isSignableCacheValid is true here -- 
            // we don't want to block on calling XpsDocument.IsSignable so we 
            // require calling code do that work prior to invoking SignDocument.
            Invariant.Assert(_isSignableCacheValid.Value); 

            // Assert that the document is actually signable.  We should never
            // get here if it's not.
            Invariant.Assert(_isSignableCache.Value); 
        }
 
        #endregion Private Methods 

        #region Private Properties 
        //-----------------------------------------------------
        //
        //  Private Properties
        // 
        //------------------------------------------------------
 
        ///  
        /// Gets or sets the XPS document from which to read signatures.
        ///  
        /// 
        /// This property exposes a critical for set field. It exists to keep
        /// the code clean and not need to write ".Value" in all the places
        /// this is used. 
        /// 
        private XpsDocument XpsDocument 
        { 
            get
            { 
                return _xpsDocument.Value;
            }

            [SecurityCritical] 
            set
            { 
                _xpsDocument.Value = value; 
            }
        } 

        /// 
        /// Gets or sets the fixed document to which to write signature
        /// definitions. 
        /// 
        ///  
        /// This property exposes a critical for set field. It exists to keep 
        /// the code clean and not need to write ".Value" in all the places
        /// this is used. 
        /// 
        private IXpsFixedDocumentReader FixedDocument
        {
            get 
            {
                return _fixedDocument.Value; 
            } 

            [SecurityCritical] 
            set
            {
                _fixedDocument.Value = value;
            } 
        }
 
        ///  
        /// Gets or sets the fixed document sequence
        ///  
        /// 
        /// This property exposes a critical for set field. It exists to keep
        /// the code clean and not need to write ".Value" in all the places
        /// this is used. 
        /// 
        private IXpsFixedDocumentSequenceReader FixedDocumentSequence 
        { 
            get
            { 
                return _fixedDocumentSequence.Value;
            }

            [SecurityCritical] 
            set
            { 
                _fixedDocumentSequence.Value = value; 
            }
        } 

        /// 
        /// Gets or sets the list of all the signatures in the package.
        ///  
        /// 
        /// Critical 
        ///  1) We do not want to allow the list to be modified, so that the 
        ///     data it contains can be trusted.
        ///  
        private IList DigitalSignatureList
        {
            [SecurityCritical]
            get 
            {
                return _digitalSignatureList; 
            } 

            [SecurityCritical] 
            set
            {
                _digitalSignatureList = value;
            } 
        }
        #endregion Private Properties 
 
        #region Private Fields
        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //----------------------------------------------------- 

        ///  
        /// The XPS document from which to read signatures. 
        /// 
        ///  
        /// Critical for set
        ///  1) The signatures and content in the document are read using this
        ///     reference. Since we present that information to the user for
        ///     trust decisions, we protect this reference to ensure that it is 
        ///     not altered by untrusted code.
        ///  
        SecurityCriticalDataForSet _xpsDocument; 

        ///  
        /// The fixed document sequence to which to write signature definitions.
        /// 
        /// 
        /// Critical for set 
        ///  1) The FixedDocuments are read using this reference which in turn
        ///     allows accesss to signature definitions. That information might be used for trust 
        ///     decisions, so we protect the reference to ensure it is not 
        ///     altered by untrusted code.
        ///  
        SecurityCriticalDataForSet _fixedDocumentSequence;

        /// 
        /// The fixed document to which to write signature definitions. 
        /// 
        ///  
        /// Critical for set 
        ///  1) The signature definitions in the document are written and read
        ///     using this reference. That information might be used for trust 
        ///     decisions, so we protect the reference to ensure it is not
        ///     altered by untrusted code.
        /// 
        SecurityCriticalDataForSet _fixedDocument; 

        ///  
        /// A list of all the signatures in the package. 
        /// 
        ///  
        /// Critical
        ///  1) The list is critical to ensure that it is changed only by
        ///     trusted code (functions on this class) and not directly.
        ///  
        [SecurityCritical]
        IList _digitalSignatureList; 
 
        /// 
        /// A cached read-only version of the signature list. This is a wrapper 
        /// around _digitalSignatureList that is intended to be passed out by
        /// the Signatures property.
        /// 
        ///  
        /// Critical for set
        ///  1) This cached value is used for trust decisions. 
        ///  
        SecurityCriticalDataForSet> _readOnlySignatureList;
 
        //Contains all known flags that don't convert to Corrupted.
        //(All flags except Cyclic and NotSignatureValid).  We will be looking for unknown flags using this
        //and if any exist then status will be set to Corrupted.
        ///  
        ///     Critical - data is used for UI decision making
        ///  
        [SecurityCritical] 
        private const X509ChainStatusFlags _x509NonCorruptedFlags =
                                                    X509ChainStatusFlags.HasExcludedNameConstraint | 
                                                    X509ChainStatusFlags.HasNotDefinedNameConstraint |
                                                    X509ChainStatusFlags.HasNotPermittedNameConstraint |
                                                    X509ChainStatusFlags.HasNotSupportedNameConstraint |
                                                    X509ChainStatusFlags.InvalidBasicConstraints | 
                                                    X509ChainStatusFlags.InvalidExtension |
                                                    X509ChainStatusFlags.InvalidNameConstraints | 
                                                    X509ChainStatusFlags.InvalidPolicyConstraints | 
                                                    X509ChainStatusFlags.NoIssuanceChainPolicy |
                                                    X509ChainStatusFlags.PartialChain | 
                                                    X509ChainStatusFlags.UntrustedRoot |
                                                    X509ChainStatusFlags.Revoked |
                                                    X509ChainStatusFlags.NotTimeValid |
                                                    X509ChainStatusFlags.NoError | 
                                                    X509ChainStatusFlags.CtlNotSignatureValid |
                                                    X509ChainStatusFlags.CtlNotTimeValid | 
                                                    X509ChainStatusFlags.CtlNotValidForUsage | 
                                                    X509ChainStatusFlags.NotTimeNested |
                                                    X509ChainStatusFlags.NotValidForUsage | 
                                                    X509ChainStatusFlags.OfflineRevocation |
                                                    X509ChainStatusFlags.RevocationStatusUnknown;

        //Create variable that contains all known flags that convert to CannotBeVerified. 
        /// 
        ///     Critical - data is used for UI decision making 
        ///  
        [SecurityCritical]
        private const X509ChainStatusFlags _x509CannotBeVerifiedFlags = 
                                                    X509ChainStatusFlags.HasExcludedNameConstraint |
                                                    X509ChainStatusFlags.HasNotDefinedNameConstraint |
                                                    X509ChainStatusFlags.HasNotPermittedNameConstraint |
                                                    X509ChainStatusFlags.HasNotSupportedNameConstraint | 
                                                    X509ChainStatusFlags.InvalidBasicConstraints |
                                                    X509ChainStatusFlags.InvalidExtension | 
                                                    X509ChainStatusFlags.InvalidNameConstraints | 
                                                    X509ChainStatusFlags.InvalidPolicyConstraints |
                                                    X509ChainStatusFlags.NoIssuanceChainPolicy; 

        //Create variable that contains all known flags that convert to IssuerNotTrusted.
        /// 
        ///     Critical - data is used for UI decision making 
        /// 
        [SecurityCritical] 
        private const X509ChainStatusFlags _x509IssuerNotTrustedFlags = 
                                                    X509ChainStatusFlags.PartialChain |
                                                    X509ChainStatusFlags.UntrustedRoot; 

        //Create variable that contains all known flags that convert to Revoked.
        /// 
        ///     Critical - data is used for UI decision making 
        /// 
        [SecurityCritical] 
        private const X509ChainStatusFlags _x509RevokedFlags = 
                                                    X509ChainStatusFlags.Revoked;
 
        //Create variable that contains all known flags that convert to Expired.
        /// 
        ///     Critical - data is used for UI decision making
        ///  
        [SecurityCritical]
        private const X509ChainStatusFlags _x509ExpiredFlags = 
                                                    X509ChainStatusFlags.NotTimeValid; 

        ///  
        /// Cached value for the IsSignable property
        /// 
        ///     Critical for set
        ///         - cached data is used for UI decision making and policy enforcement 
        ///           (Determined by the result of XPSDocument.IsSignable)
        ///  
        ///  
        private SecurityCriticalDataForSet _isSignableCache;
        private SecurityCriticalDataForSet _isSignableCacheValid; 

        #endregion Private Fields
    }
} 

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