DocumentSignatureManager.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 / DocumentSignatureManager.cs / 1 / DocumentSignatureManager.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: 
//    DocumentSignatureManager is an internal API for Mongoose to deal with Digital Signatures.
// 
// History:
// 05/03/05 - [....] created
// 07/26/05 - [....] added shared trace switch and method
//--------------------------------------------------------------------------- 

using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Globalization; 
using System.IO.Packaging;
using System.Reflection;
using System.Security;
using System.Security.Cryptography; 
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions; // For Friend Access and elevations 
using System.Threading; 
using System.Windows.TrustUI;
using System.Windows.Forms; 
using System.Windows.Interop;
using System.Windows.Threading;

using MS.Internal.Documents.Application; 
using MS.Internal.PresentationUI;
 
namespace MS.Internal.Documents 
{
    ///  
    /// DocumentSignatureManager is a internal Avalon class used to expose the DigSig Document API
    /// 
    [FriendAccessAllowed]
    internal sealed class DocumentSignatureManager 
    {
        #region Constructors 
        //----------------------------------------------------- 
        //
        //  Constructors 
        //
        //-----------------------------------------------------

        ///  
        /// The constructor
        ///  
        ///  
        /// Critical
        ///  1) Sets critical for set property DigitalSignatureProvider, which 
        ///     is the basis for trust decisions.
        ///  2) Sets _changeLog to an empty list.
        /// 
        [SecurityCritical] 
        private DocumentSignatureManager(IDigitalSignatureProvider digSigProvider)
        { 
            if (digSigProvider != null) 
            {
                DigitalSignatureProvider = digSigProvider; 
            }
            else
            {
                throw new ArgumentNullException("digSigProvider"); 
            }
 
            _changeLog = new List(); 

            _digSigSigResources = new Dictionary(); 

            DocumentRightsManagementManager rightsManagementManager =
                DocumentRightsManagementManager.Current;
 
            if(rightsManagementManager != null)
            { 
                rightsManagementManager.RMPolicyChange += 
                    new DocumentRightsManagementManager.RMPolicyChangeHandler(OnRMPolicyChanged);
                rightsManagementManager.Evaluate(); 
            }

            // notify the documentmanager when the signatures change
            SignaturesChanged += DocumentManager.OnModify; 
        }
 
        #endregion Constructors 

        #region Public Event 
        //------------------------------------------------------
        //
        //  Public Event
        // 
        //-----------------------------------------------------
 
        public event EventHandler SignaturesChanged; 
        public event SignatureStatusChangeHandler SignatureStatusChange;
 
        #endregion Public Event

        #region Internal Methods
        //------------------------------------------------------ 
        //
        //  Internal Methods 
        // 
        //------------------------------------------------------
 
        /// 
        /// Forces an Evaluate which will result in SignatureStatus and
        /// SignaturePolicy event being fired.
        ///  
        /// 
        /// Critical 
        ///  1) Sets a SecurityCritical property (DigitalSignature.SignatureState) 
        /// TreatAsSafe
        ///  1) We are setting the SignatureStatus to "Unverifiable" only in 
        ///     the case where the document does not comply to signing standards.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void Evaluate() 
        {
            Trace.SafeWrite( 
                Trace.Signatures, 
                "Evaluate called.");
 
            SignatureStatus calcSigStatus = SignatureStatus.Unknown;
            SignaturePolicy calcSigPolicy = SignaturePolicy.AllowSigning |
                                            SignaturePolicy.ModifyDocumentProperties;
 
            // If the document is not signed, we already know the signature
            // status of the document 
            if (!IsSigned) 
            {
                //There are no signatures applied to this document. 
                calcSigStatus = SignatureStatus.NotSigned;
            }

            // Check to see if the certificates have been validated 
            else if (!AreAllSignaturesVerified)
            { 
                calcSigStatus = SignatureStatus.Undetermined; 
                calcSigPolicy = SignaturePolicy.AllowNothing;
            } 

            // Otherwise we should look at all the signatures in the document
            else
            { 
                bool areAllSignaturesValid = true;
 
                // Verify that the document is signable before we continue. 
                if (!VerifySignability())
                { 
                    // If the document does not meet the signing criteria, the signatures are
                    // not considered valid.
                    areAllSignaturesValid = false;
 
                    // Walk the list of signatures applied to the package and set their state
                    // to "Unverifiable." 
                    foreach (DigitalSignature digitalSignature in DigitalSignatureProvider.Signatures) 
                    {
                        digitalSignature.SignatureState = SignatureStatus.Unverifiable; 
                    }
                }
                else
                { 
                    // Check all the signatures applied to the package to see
                    // if they are all valid. At this point the signatures should 
                    // all have been verified, and the certificates associated with 
                    // them should all have been validated.
                    foreach (DigitalSignature digitalSignature in DigitalSignatureProvider.Signatures) 
                    {
                        bool valid =
                            (digitalSignature.SignatureState == SignatureStatus.Valid) &&
                            (GetCertificateStatusFromTable(digitalSignature) == CertificatePriorityStatus.Ok); 

                        if (valid) 
                        { 
                            // Add the restrictions on the policy imposed by the
                            // new signature only if it is valid. 
                            calcSigPolicy =
                                AddRestrictionsFromSignature(calcSigPolicy, digitalSignature);
                        }
 
                        areAllSignaturesValid &=
                            (valid || 
                            (digitalSignature.SignatureState == SignatureStatus.NotSigned)); 
                    }
 
                    // If the policy does not allow modifying document properties and the properties have been
                    // changed, then the signatures have been invalidated.
                    if (!IsAllowedByPolicy(calcSigPolicy, SignaturePolicy.ModifyDocumentProperties) &&
                        !DocumentProperties.Current.VerifyPropertiesUnchanged()) 
                    {
                        areAllSignaturesValid = false; 
 
                        // Walk the list of signatures applied to the package and set their state
                        // to "Invalid" if necessary. 
                        foreach (DigitalSignature digitalSignature in DigitalSignatureProvider.Signatures)
                        {
                            if (digitalSignature.IsDocumentPropertiesRestricted)
                            { 
                                digitalSignature.SignatureState = SignatureStatus.Invalid;
                            } 
                        } 
                    }
                } 

                if (areAllSignaturesValid)
                {
                    calcSigStatus = SignatureStatus.Valid; 
                }
                else 
                { 
                    calcSigStatus = SignatureStatus.Invalid;
                } 
            }

            Invariant.Assert(
                calcSigStatus != SignatureStatus.Unknown, 
                "We should have determined a signature status by now.");
 
            //Fire the events. 
            OnSignatureStatusChange(calcSigStatus);
            _signaturePolicy.Value = calcSigPolicy; 
        }

        /// 
        /// If the document is signed, this function verifies the signatures and 
        /// validates all the associated certificates.
        ///  
        ///  
        /// This function performs all the signature verification that must
        /// happen on the main thread. This includes loading the signatures and 
        /// verifying the hashes. Certificate validation can and does happen on
        /// a background thread.
        /// 
        ///  
        /// Critical
        ///  1) Calls StartCertificateStatusCheck 
        /// TreatAsSafe 
        ///  1) The list of certificates passed to the status check comes from
        ///     the critical for set provider. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void VerifySignatures()
        { 
            if (AreAllSignaturesVerified)
            { 
                // If the certificates have already been verified, exit 
                return;
            } 
            else if (!IsSigned)
            {
                // If the document isn't signed there is no certificate
                // validation to do, and we can initialize the (empty) 
                // certificate status table for later use
                _certificateStatusTable = 
                    new Dictionary(); 
            }
            else 
            {
                Trace.SafeWrite(
                    Trace.Signatures,
                    "Document loading complete; verifying signatures."); 

                // Once the document has finished loading, we can safely verify all 
                // the signatures in the package (i.e. compare hashes) 
                DigitalSignatureProvider.VerifySignatures();
 
                // Retrieve and save all the certificates used
                IList certificateList =
                    DigitalSignatureProvider.GetAllCertificates();
 
                StartCertificateStatusCheck(certificateList);
            } 
        } 

        ///  
        /// ShowSignatureSummary:  Displays the DigSig Summary dialog.
        /// 
        /// 
        /// Critical 
        ///  1) Elevation to show a top level window.
        ///  2) This method references the critical RootBrowserWindow property. 
        /// TreatAsSafe 
        ///  1) The window is a blessed internal window that uses purely Windows
        ///     Forms rather than Avalon. 
        ///  2) The RootBrowserWindow is not leaked beyond this method, and is
        ///     passed only to a WinForms dialog.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void ShowSignatureSummaryDialog()
        { 
            IList sigResList = GetSignatureResourceList(false /*requestsOnly*/); 

            SignatureSummaryDialog dialog = null; 
            System.Windows.Forms.IWin32Window parentWindow =
                DocumentApplicationDocumentViewer.Instance.RootBrowserWindow;

            (new UIPermission(UIPermissionWindow.AllWindows)).Assert(); //BlessedAssert 
            try
            { 
                dialog = new SignatureSummaryDialog( 
                    sigResList,
                    this, 
                    false /*Sig Request Dialog*/);
                    dialog.ShowDialog(parentWindow);
            }
            finally 
            {
                UIPermission.RevertAssert(); 
 
                if (dialog != null)
                { 
                    dialog.Dispose();
                }
            }
        } 

        ///  
        /// RequestSigners:  Displays the DigSig Request Signature dialog. 
        /// 
        ///  
        ///     Critical - 1) Elevation to show a top level window.
        ///                2) Elevates for unmanaged code access for showing messageboxes on error
        ///                3) This method references the critical RootBrowserWindow property.
        ///     TreatAsSafe - 1) The window is a blessed internal window that uses purely Windows Forms rather than Avalon. 
        ///                   2) Unmanaged code elevation is only for MessageBox.Show call (which internally calls
        ///                      the Win32 MessageBox API.  This should be pretty safe. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal void ShowSignatureRequestSummaryDialog() 
        {
            //Check to see if package is Read Only or signed (we can't added request to a signed
            //document.
            //If the document does not meet the signing criteria, we alert the user and return. 
            if (!VerifySignability())
            { 
                System.Windows.MessageBox.Show( 
                    SR.Get(SRID.DigitalSignatureMessageDocumentNotSignable),
                    SR.Get(SRID.DigitalSignatureMessageDocumentNotSignableTitle), 
                    System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Exclamation);
            }
            else if (IsSigningAllowed && !IsSigned) 
            {
                IList sigResList = GetSignatureResourceList(true /*requestsOnly*/); 
 
                SignatureSummaryDialog dialog = null;
                System.Windows.Forms.IWin32Window parentWindow = 
                    DocumentApplicationDocumentViewer.Instance.RootBrowserWindow;

                (new UIPermission(UIPermissionWindow.AllWindows)).Assert(); //BlessedAssert
                try 
                {
                    //Create and show the Summary Dialog in the Request signature mode. 
                    dialog = new SignatureSummaryDialog( 
                        sigResList,
                        this, 
                        true /*Sig Request Dialog*/);
                        dialog.ShowDialog(parentWindow);
                }
                finally 
                {
                    UIPermission.RevertAssert(); 
 
                    if (dialog != null)
                    { 
                        dialog.Dispose();
                    }
                }
            } 
            else
            { 
                if (!IsSigningAllowed) 
                {
                    System.Windows.MessageBox.Show( 
                        SR.Get(SRID.DigitalSignatureWarnErrorRMSigningMessage),
                        SR.Get(SRID.DigitalSignatureWarnErrorSigningErrorTitle),
                        System.Windows.MessageBoxButton.OK,
                        System.Windows.MessageBoxImage.Exclamation 
                        );
                } 
                else 
                {
                    System.Windows.MessageBox.Show( 
                        SR.Get(SRID.DigitalSignatureWarnErrorReadOnlyNoMoreRequest),
                        SR.Get(SRID.DigitalSignatureWarnErrorSigningErrorTitle),
                        System.Windows.MessageBoxButton.OK,
                        System.Windows.MessageBoxImage.Exclamation 
                        );
                } 
            } 
        }
 
        /// 
        /// Display the signing dialog parented from the root browser window
        /// without an accompanying signature request.
        ///  
        /// 
        /// Critical 
        ///  1) Calls SecurityCritical property RootBrowserWindow on 
        ///     DocumentApplicationDocumentViewer to get a handle to the root
        ///     browser window 
        ///  2) Calls critical method ShowSigningDialog(IntPtr)
        /// TreatAsSafe
        ///  1) The handle is passed only to a critical method.
        ///  2) The IntPtr passed to ShowSigningDialog comes from a critical 
        ///     property that is a known source.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void ShowSigningDialog()
        { 
            ShowSigningDialog(
                DocumentApplicationDocumentViewer.Instance.RootBrowserWindow.Handle);
        }
 
        /// 
        /// Display the signing dialog without an accompanying signature request. 
        ///  
        /// A handle to the parent window for the
        /// signing dialog 
        /// 
        /// Critical
        ///  1) Calls critical method ShowSigningDialog(IntPtr,
        ///     DigitalSignature) with an IntPtr that comes from an argument 
        ///     to this method.
        ///  
        [SecurityCritical] 
        internal void ShowSigningDialog(IntPtr parentWindow)
        { 
            ShowSigningDialog(
                parentWindow,
                null /*DigitalSignature digitalSignatureRequest*/);
        } 

        ///  
        /// Display the signing dialog.  This method optionally takes a SignatureRequest. 
        /// The actual signing operation will take place in a callback from the dialog.
        ///  
        /// The request to be associated
        /// with the signature (can be null)
        /// A handle to the window that will be the
        /// parent of the signing dialog 
        /// 
        /// Critical 
        ///  1) Calls SecurityCritical method ShowCertificatePickerDialog 
        ///  2) Elevates for UIPermissions to display a signing dialog
        ///  3) Creates DigitalSignature instances and sets properties on them 
        ///  4) Creates a SigningDialog which has a critical constructor
        ///  5) Parents a dialog off an IntPtr passed in as an argument and
        ///     uses the IntPtr under an assert.
        ///  6) Elevates for KeyContainerPermission to access PrivateKey 
        /// TreatAsSafe
        ///  0) The parameter that was passed is a trusted DigitalSignature. 
        ///     This is because a security critical code path was required to 
        ///     create it since the constructor is critical. Also the properties
        ///     were set in a critical code path since the set accessor on all 
        ///     the properties is also critical.
        ///  1) The selection dialog is Win32 based and provided by the system.
        ///     The certificate returned will always be user selected and
        ///     accessible by the user. 
        ///  2) The dialog that is invoked is a blessed dialog implemented in
        ///     WinForms to prevent spoofing from the Avalon content/application. 
        ///  3) The DigitalSignature instance is created and properties set 
        ///     based on internal resources.
        ///  4) We are supplying the SigningDialog a trusted certificate that 
        ///     was selected by the user so this is safe.
        ///  5) The PrivateKey value is only placed in a local variable and not
        ///     leaked anywhere else.
        /// NotSafe 
        ///  1) The IntPtr should only come from trusted code.
        ///  
        [SecurityCritical] 
        internal void ShowSigningDialog(
            IntPtr parentWindow, 
            DigitalSignature digitalSignatureRequest)
        {
            // First check if signing is allowed by RM.  If not, show an error
            // dialog and exit. 
            if (!IsSigningAllowed)
            { 
                System.Windows.MessageBox.Show( 
                    SR.Get(SRID.DigitalSignatureWarnErrorRMSigningMessage),
                    SR.Get(SRID.DigitalSignatureWarnErrorSigningErrorTitle), 
                    System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Exclamation);

                return; 
            }
 
            // If the document does not meet the signing criteria, we alert the user and return. 
            if (!VerifySignability())
            { 
                System.Windows.MessageBox.Show(
                    SR.Get(SRID.DigitalSignatureMessageDocumentNotSignable),
                    SR.Get(SRID.DigitalSignatureMessageDocumentNotSignableTitle),
                    System.Windows.MessageBoxButton.OK, 
                    System.Windows.MessageBoxImage.Exclamation);
 
                return; 
            }
 
            // Check the signature policy to see if a new signature will invalidate an
            // existing signature.
            if (IsSigned && !IsSigningAllowedByPolicy)
            { 
                System.Windows.MessageBoxResult dialogResult = System.Windows.MessageBox.Show(
                    SR.Get(SRID.DigitalSignatureMessageActionInvalidatesSignature), 
                    SR.Get(SRID.DigitalSignatureMessageSignNowTitle), 
                    System.Windows.MessageBoxButton.YesNo,
                    System.Windows.MessageBoxImage.Exclamation); 

                if (dialogResult == System.Windows.MessageBoxResult.No)
                {
                    return; 
                }
            } 
 
            // Check to see if user is trying to add another signature when no
            // request spot are available.  If there are no request spots warn user. 
            if (IsSigned && !HasRequests)
            {
                System.Windows.MessageBoxResult dialogResult = System.Windows.MessageBox.Show(
                    SR.Get(SRID.DigitalSignatureMessageSignNoPending), 
                    SR.Get(SRID.DigitalSignatureMessageSignNowTitle),
                    System.Windows.MessageBoxButton.YesNo, 
                    System.Windows.MessageBoxImage.Exclamation); 

                if (dialogResult == System.Windows.MessageBoxResult.No) 
                {
                    return;
                }
            } 
            // Check to see if user is trying to add another signature when
            // request spot are available but they aren't using it.  If there are 
            // no request spots warn user. 
            else if (IsSigned && HasRequests && digitalSignatureRequest == null)
            { 
                System.Windows.MessageBoxResult dialogResult = System.Windows.MessageBox.Show(
                    SR.Get(SRID.DigitalSignatureMessageSignPending),
                    SR.Get(SRID.DigitalSignatureMessageSignNowTitle),
                    System.Windows.MessageBoxButton.YesNo, 
                    System.Windows.MessageBoxImage.Exclamation);
 
                if (dialogResult == System.Windows.MessageBoxResult.No) 
                {
                    return; 
                }
            }

            // Check to see if we are signing a request. 
            if (digitalSignatureRequest == null)
            { 
                //This is not a signing request.  Now Check 
                //to see if document has already been signed.  If it has been signed
                //then we don't want to allow user to define intent/location (definition) 
                //on the signing dialog.  To prevent this we will create an empty
                //DigitalSignatureRequest.
                if (IsSigned)
                { 
                    digitalSignatureRequest = new DigitalSignature();
                } 
                else 
                {
                    // The document hasn't yet been signed -- warn the user that he/she 
                    // should add signature requests before signing and give the user the option
                    // to cancel
                    System.Windows.MessageBoxResult dialogResult = System.Windows.MessageBox.Show(
                        SR.Get(SRID.DigitalSignatureMessageAddRequestsBeforeSigning), 
                        SR.Get(SRID.DigitalSignatureMessageAddRequestsBeforeSigningTitle),
                        System.Windows.MessageBoxButton.YesNo, 
                        System.Windows.MessageBoxImage.Exclamation); 

                    // If the user canceled, stop the signing process. 
                    if (dialogResult == System.Windows.MessageBoxResult.No)
                    {
                        return;
                    } 
                }
            } 
 
            // Get certificate selection from the user.  The requestAgain flag is set to
            // true if we need to prompt the user for another selection.  This happens only 
            // if the user selects a smart card certificate but doesn't insert the card.
            bool requestAgain;
            X509Certificate2 x509Certificate2;
 
            do
            { 
                requestAgain = false; 

                // Show certificate picker dialog 
                x509Certificate2 = ShowCertificatePickerDialog(parentWindow);

                // If the certificate is null, the user cancelled the selection, so exit.
                if (x509Certificate2 == null) 
                {
                    return; 
                } 

                // Check if we can retrieve the private key.  This will alert us of the case 
                // in which the user has selected a smart card certificate but selected
                // cancel when asked to insert the card by throwing a CryptoGraphicException.
                // If the user selects a non-smart card certificate, or selects a smart card
                // certificate and inserts the smart card, no exception will be thrown. 
                (new KeyContainerPermission(KeyContainerPermissionFlags.AllFlags)).Assert(); //BlessedAssert
                try 
                { 
                    // We access the PrivateKey only to test if it can be retrieved -- the
                    // actual contents are never used. 
                    AsymmetricAlgorithm testKey = x509Certificate2.PrivateKey;
                }
                catch (CryptographicException)
                { 
                    // In this case the user selected a smart card key but did not insert
                    // the smart card.  We should redisplay the certificate picker to allow 
                    // the user to select a different key. 
                    requestAgain = true;
                } 
                finally
                {
                    KeyContainerPermission.RevertAssert();
                } 
            } while (requestAgain);
 
            SigningDialog dialog = null; 
            (new UIPermission(UIPermissionWindow.AllWindows)).Assert(); //BlessedAssert
            try 
            {
                dialog = new SigningDialog(
                    x509Certificate2,
                    digitalSignatureRequest, 
                    this);
                dialog.ShowDialog(NativeWindow.FromHandle(parentWindow)); 
            } 
            finally
            { 
                UIPermission.RevertAssert();

                if (dialog != null)
                { 
                    dialog.Dispose();
                } 
            } 
        }
 
        /// 
        /// Gets a List of SignatureResources.
        /// 
        internal IList GetSignatureResourceList(bool requestsOnly) 
        {
            //Clear the map. 
            _digSigSigResources.Clear(); 

            IList signResourcesList = new List(); 

            //Loop through all DigSigs
            foreach (DigitalSignature digSig in DigitalSignatureProvider.Signatures)
            { 
                SignatureResources sigResources;
 
                //Is this signature a request signature? 
                bool notSigned = digSig.SignatureState == SignatureStatus.NotSigned;
 
                //Filter out signed DigitalSignature if requester wants request signatures only
                if (!requestsOnly || notSigned)
                {
                    //Use the SignatureResourceHelper to get the strings to display 
                    //in the ListBox
                    sigResources = SignatureResourceHelper.GetResources( 
                        digSig, 
                        GetCertificateStatusFromTable(digSig));
 
                    //Add to map and to list.
                    _digSigSigResources.Add(sigResources, digSig);
                    signResourcesList.Add(sigResources);
                } 
            }
 
            return signResourcesList; 
        }
 
        /// 
        /// Signs the document with the given digital signature. This function
        /// blocks the UI until the signing operation is complete.
        ///  
        /// 
        /// Critical 
        ///  1) This method uses the securitycritical field _certificateStatusTable 
        ///     to set CertificatePriorityStatus.
        ///  2) Calls critical method UndoChanges. 
        ///  3) Accesses critical field _changeLog.
        /// TreatAsSafe
        ///  1) The certificate whose status is added to the table is critical
        ///     for set in DigitalSignature. 
        ///  2) UndoChanges is called only if the save fails.
        ///  3) The change log is only modified to clear it after the save 
        ///     operation has successfully completed. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal bool SignDocument(DigitalSignature digSig, Form parentDialog, bool isSaveAs)
        {
            bool rtn = false;
 
            //First place this new DigSig's Cert in the CertStatus Table as CertificatePriorityStatus.Ok
            //since user has selected this cert to use for signing.  We will not be checking the status of 
            //this cert since the user selected it for signing. 
            if (_certificateStatusTable != null && !_certificateStatusTable.ContainsKey(digSig.Certificate))
            { 
                _certificateStatusTable.Add(digSig.Certificate, CertificatePriorityStatus.Ok);
            }

            //Show the progress dialog 
            ProgressDialog dialog =
                ProgressDialog.CreateThreaded( 
                    SR.Get(SRID.SigningProgressTitle), 
                    SR.Get(SRID.SigningProgressLabel)).Form;
 
            try
            {
                //Need to check if this is the first Signature applied to this document.  If so then
                //we need to create a SignatureDefinition before we can sign. 
                if (!IsSigned && digSig.GuidID == null)
                { 
                    digSig.GuidID = DigitalSignatureProvider.AddRequestSignature(digSig); 
                    _changeLog.Add(new ChangeLogEntity((Guid)digSig.GuidID, true));
                } 

                //Sign XPS document
                try
                { 
                    DigitalSignatureProvider.SignDocument(digSig);
                } 
                catch (CryptographicException e) 
                {
                    // Close the progress dialog 
                    ProgressDialog.CloseThreaded(dialog);

                    // If the exception thrown was a result of the user cancelling
                    // the operation (i.e. cancelling a smartcard PIN prompt) 
                    // then we will return silently; otherwise we'll display the exception
                    // message to the user since it typically indicates a smartcard failure 
                    // of some sort that the user can take action on, rather than something 
                    // that is catastrophic.
                    if (GetErrorCode(e) != SCARD_W_CANCELLED_BY_USER) 
                    {
                        System.Windows.MessageBoxResult dialogResult = System.Windows.MessageBox.Show(
                            String.Format(
                                CultureInfo.CurrentCulture, 
                                SR.Get(SRID.DigitalSignatureWarnErrorGeneric),
                                e.Message), 
                            SR.Get(SRID.DigitalSignatureWarnErrorSigningErrorTitle), 
                            System.Windows.MessageBoxButton.OK,
                            System.Windows.MessageBoxImage.Exclamation); 
                    }

                    UndoChanges();
                    return false; 
                }
            } 
            finally 
            {
                // Close the progress dialog 
                ProgressDialog.CloseThreaded(dialog);
            }

            _changeLog.Add(new ChangeLogEntity((Guid)digSig.GuidID, false)); 

            //Since we're signing the document, signatures have changed; raise the 
            //SignaturesChanged event before saving takes place. 
            RaiseSignaturesChanged();
 
            //The signing is complete, now lets save the package.
            //Save XPS document to file
            DocumentManager docManager = DocumentManager.CreateDefault();
            if (docManager != null) 
            {
                if (isSaveAs) 
                { 
                    rtn = docManager.SaveAs(null);
                } 
                else
                {
                    rtn = docManager.Save(null);
                } 

                if (!rtn) 
                { 
                    UndoChanges();
                } 
                else
                {
                    // if we succeeded in signing and saving
                    // the changes are 'committed' now, so 
                    // clear the changelog.
                    _changeLog.Clear(); 
                } 
            }
 
            // If the operation succeeded, re-evaluate signature status
            if (rtn)
            {
                // If there are any signatures that will be invalidated by a 
                // new signature, mark those signatures as invalid
                if (!IsSigningAllowedByPolicy) 
                { 
                    foreach (DigitalSignature signature in DigitalSignatureProvider.Signatures)
                    { 
                        if (!signature.Equals(digSig) &&
                            signature.IsAddingSignaturesRestricted)
                        {
                            signature.SignatureState = SignatureStatus.Invalid; 
                        }
                    } 
                } 

                Evaluate(); 
            }

            return rtn;
        } 

        ///  
        /// Displays a signing dialog off the given parent window, optionally 
        /// using the fields from the signature request corresponding to the
        /// SignatureResources argument. This is called by the Signature Summary 
        /// dialog.
        /// 
        /// An optional SignatureResources
        /// object that corresponds to a signature request. 
        /// The parent window for the signing dialog
        ///  
        ///  
        /// Critical
        ///  1) Takes an IntPtr argument and passes it to critical code. 
        /// 
        [SecurityCritical]
        internal void OnSign(SignatureResources? signatureResources, IntPtr parentWindow)
        { 
            //Nothing was highlighted in the dialog. So this isn't a request signature.
            if (signatureResources == null) 
            { 
                ShowSigningDialog(parentWindow);
            } 
            else
            {
                //Something was highlighted.  Need to see if it was a request or regular Sig.
 
                DigitalSignature digSig = _digSigSigResources[signatureResources.Value];
 
                if (digSig.SignatureState == SignatureStatus.NotSigned) 
                {
                    //We are signing a request. 
                    ShowSigningDialog(parentWindow, digSig);
                }
                else
                { 
                    //A regular signature was highlighted so just sign document.
                    ShowSigningDialog(parentWindow); 
                } 
            }
        } 

        /// 
        /// Uses the CLR's X509CertificateUI class to display the Windows
        /// certificate view dialog for the certificate associated with a given 
        /// signature.
        ///  
        /// The digital signature associated 
        /// with the certificate
        /// The window off which to parent the dialog 
        /// 
        /// 
        /// Critical
        ///  1) Asserts for UnmanagedCode permissions to display the certificate 
        ///     dialog modally using the IntPtr handle passed in as an argument.
        ///     The overload of DisplayCertificate we use requires this assert. 
        ///  
        [SecurityCritical]
        internal void OnCertificateView( 
            SignatureResources signatureResources,
            IntPtr parentWindow)
        {
            DigitalSignature digSig = _digSigSigResources[signatureResources]; 
            X509Certificate2 certificate = null;
 
            if (digSig != null) 
            {
                certificate = digSig.Certificate; 
            }

            if (certificate != null)
            { 
                (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert(); //BlessedAssert
                try 
                { 
                    X509Certificate2UI.DisplayCertificate(certificate, parentWindow);
                } 
                finally
                {
                    SecurityPermission.RevertAssert();
                } 
            }
        } 
 
        /// 
        /// OnSummaryAdd. 
        /// 
        /// Critical - Makes use of critical RootBrowserWindow property.
        /// TreatAsSafe - Uses it to parent a safe WinForms dialog.
        ///  
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void OnSummaryAdd() 
        {
            RequestedSignatureDialog requestSignatureDialog = new RequestedSignatureDialog(this); 
            requestSignatureDialog.ShowDialog(DocumentApplicationDocumentViewer.Instance.RootBrowserWindow);
            requestSignatureDialog.Dispose();
        }
 
        /// 
        /// OnSummaryDelete. This function is called from the signature summary 
        /// dialog when the Delete button is clicked to remove a signature 
        /// request.
        ///  
        /// The resources of the request to
        /// delete
        /// 
        /// Critical 
        ///  1) Removes a signature definition by calling critical function
        ///     RemoveRequestSignature. 
        ///  
        [SecurityCritical]
        internal void OnSummaryDelete(SignatureResources signatureResources) 
        {
            //Get the corresponding DigSig
            DigitalSignature digSig = _digSigSigResources[signatureResources];
 
            //Now lets delete the DigSig (SigDefinition).
            DigitalSignatureProvider.RemoveRequestSignature((Guid)digSig.GuidID); 
 
            //Fire SignatureChanged event to reflect the removed request.
            RaiseSignaturesChanged(); 
        }

        /// 
        /// OnAddRequestSignature.  Called from Request dialog. 
        /// 
        ///  
        /// Critical 
        ///  1) Sets properties on a DocumentSignature instance using input
        ///     parameters. 
        /// 
        [SecurityCritical]
        internal void OnAddRequestSignature(SignatureResources sigResources, DateTime dateTime)
        { 
            //Use the SignatureResource to create Request Digitalsignature.
            DigitalSignature digSigRequest = new DigitalSignature(); 
 
            //Assign fields.
            digSigRequest.SignatureState = SignatureStatus.NotSigned; 
            digSigRequest.SubjectName = sigResources._subjectName;
            digSigRequest.Reason = sigResources._reason;
            digSigRequest.Location = sigResources._location;
            digSigRequest.SignedOn = dateTime; 

            Guid spotId = DigitalSignatureProvider.AddRequestSignature(digSigRequest); 
 
            digSigRequest.GuidID = spotId;
 
            // A request has been added, so the signatures have changed.
            RaiseSignaturesChanged();
        }
 
        /// 
        /// HasCertificate.  Check to see if this signatureResources has a corresponding cert. 
        ///  
        internal bool HasCertificate(SignatureResources signatureResources)
        { 
            bool rtn = false;

            //Find corresponding digSig
            DigitalSignature digSig = _digSigSigResources[signatureResources]; 

            //If this is a request signature it won't have a cert. This can also 
            //happen if the signature is invalid because it is missing a cert. 
            if (digSig.Certificate != null)
            { 
                rtn = true;
            }

            return rtn; 
        }
 
        ///  
        /// Initialize the singleton DocumentSignatureManager.
        ///  
        /// The provider with which to initialize the
        /// signature manager
        /// 
        /// Critical 
        ///  1) Calls the critical constructor for DocumentSignatureManager with
        ///     a parameter passed in as an argument to this function 
        ///  
        [SecurityCritical]
        internal static void Initialize(IDigitalSignatureProvider provider) 
        {
            System.Diagnostics.Debug.Assert(
                _singleton == null,
                "DocumentSignatureManager initialized twice."); 

            if (_singleton == null) 
            { 
                _singleton = new DocumentSignatureManager(provider);
            } 
        }

        #endregion Internal Methods
 
        #region Internal Properties
        //----------------------------------------------------- 
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------

        internal static DocumentSignatureManager Current
        { 
            get { return _singleton; }
        } 
 
        /// 
        /// Whether or not the document contains any signatures. 
        /// 
        internal bool IsSigned
        {
            get { return DigitalSignatureProvider.IsSigned; } 
        }
 
        ///  
        /// Whether or not the document meets the signing criteria.
        /// The first call to this may take a significant amount of time; 
        /// Subsequent calls will return a cached value.
        /// 
        internal bool IsSignable
        { 
            get
            { 
                return DigitalSignatureProvider.IsSignable; 
            }
        } 

        /// 
        /// Whether or not the document contains any signature requests.
        ///  
        internal bool HasRequests
        { 
            get { return DigitalSignatureProvider.HasRequests; } 
        }
 
        #endregion Internal Properties

        #region Internal Delegate
        //----------------------------------------------------- 
        //
        //  Internal Delegate 
        // 
        //-----------------------------------------------------
 
        internal delegate void SignatureStatusChangeHandler(object sender,
                                                            SignatureStatusEventArgs args
                                                         );
 
        #endregion Internal Delegate
 
        #region Private Methods 
        //-----------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        /// 
        /// Displays the cert picker dialog. 
        ///  
        /// 
        /// Critical 
        ///  1) Method elevates for OpenStore and EnumerateCerticates on
        ///     StorePermissions which is used to get the user certificates for
        ///     selection by the user. The certificate that is selected within
        ///     the certificate picker dialog is returned to the caller of this 
        ///     method.
        ///  
        [SecurityCritical] 
        private static X509Certificate2 ShowCertificatePickerDialog(IntPtr parentWindow)
        { 
            X509Certificate2 x509cert = null;

            // look for appropriate certificates
            X509Store store = new X509Store(StoreLocation.CurrentUser); 
            X509Certificate2Collection collection = null;
 
            (new StorePermission(StorePermissionFlags.OpenStore | StorePermissionFlags.EnumerateCertificates)).Assert(); //BlessedAssert 
            try
            { 
                store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
                collection = (X509Certificate2Collection)store.Certificates;
            }
            finally 
            {
                StorePermission.RevertAssert(); 
            } 

            // narrow down the choices 
            // timevalid
            collection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, true /*validOnly*/);

            // intended for signing (or no intent specified) 
            collection = collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false /*validOnly*/);
 
            // remove certs that don't have private key 
            // work backward so we don't disturb the enumeration
            for (int i = collection.Count - 1; i >= 0; i--) 
            {
                if (!collection[i].HasPrivateKey)
                {
                    collection.RemoveAt(i); 
                }
            } 
 
            // any suitable certificates available?
            if (collection.Count > 0) 
            {
                collection = X509Certificate2UI.SelectFromCollection(
                    collection,
                    SR.Get(SRID.CertSelectionDialogTitle), 
                    SR.Get(SRID.CertSelectionDialogMessage),
                    X509SelectionFlag.SingleSelection, 
                    parentWindow); 

                if (collection.Count > 0) 
                {
                    x509cert = collection[0];   // return the first one
                }
            } 
            else
            { 
                System.Windows.MessageBox.Show( 
                    SR.Get(SRID.DigitalSignatureWarnErrorRMSigningMessageNoCerts),
                    SR.Get(SRID.DigitalSignatureWarnErrorSigningErrorTitle), 
                    System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Exclamation);
            }
 
            return x509cert;
        } 
 
        /// 
        /// Add restrictions to a signature policy based on the additional 
        /// restrictions imposed by a given signature
        /// 
        /// The original signature policy
        /// The signature from which to add restrictions 
        /// The new signature policy
        private static SignaturePolicy AddRestrictionsFromSignature(SignaturePolicy calcSigPolicy, DigitalSignature digSig) 
        { 
            if (digSig.IsDocumentPropertiesRestricted &&
                IsAllowedByPolicy(calcSigPolicy, SignaturePolicy.ModifyDocumentProperties)) 
            {
                calcSigPolicy ^= SignaturePolicy.ModifyDocumentProperties;
            }
 
            if (digSig.IsAddingSignaturesRestricted &&
                IsAllowedByPolicy(calcSigPolicy, SignaturePolicy.AllowSigning)) 
            { 
                calcSigPolicy ^= SignaturePolicy.AllowSigning;
            } 

            return calcSigPolicy;
        }
 
        /// 
        /// Checks if an action (represented by a SignaturePolicy) is allowed 
        /// by the given signature policy. 
        /// 
        /// The signature policy 
        /// The action to check
        /// True if the action is allowed by the policy
        private static bool IsAllowedByPolicy(SignaturePolicy policy, SignaturePolicy action)
        { 
            return ((policy & action) == action);
        } 
 
        /// 
        /// StartCertificateStatusCheck starts thread to get Certificate status. 
        /// Only call once at loadtime.
        /// 
        /// The list of certificates to validate
        ///  
        /// Critical
        ///  1) Sets the CertificateList passed to the certificate validation 
        ///     thread, which is critical since it is the basis for the status 
        ///     table.
        ///  
        [SecurityCritical]
        private void StartCertificateStatusCheck(IList certificateList)
        {
            // First get a callback setup to call the Evaluate method using 
            // this thread.  After the worker thread gets the certificate
            // status and sets the private field it will set the dispatcher 
            // operation's priority to Background so the Evaluate method gets 
            // called when the time comes.
            DispatcherOperation dispatcherOperation = Dispatcher.CurrentDispatcher.BeginInvoke( 
                DispatcherPriority.Inactive,
                new DispatcherOperationCallback(delegate(object notused)
                {
                    Trace.SafeWrite( 
                        Trace.Signatures,
                        "Dispatcher callback. Setting document loaded flag to true."); 
 
                    // Now that the certs have been verified evaluate the DigSig
                    // state of the document. 
                    Evaluate();
                    return null;
                }),
                null); 

            CertificateValidationThreadInfo threadInfo = 
                new CertificateValidationThreadInfo(); 

            threadInfo.CertificateList = certificateList; 
            threadInfo.Operation = dispatcherOperation;

            Trace.SafeWrite(
                Trace.Signatures, 
                "Kicking off certificate validation thread");
 
            // Pass certificate validation work off so UI doesn't block. 

            // There are no concurrency issues here because the only work being 
            // done by the work item is the validation of a list of
            // certificates. Accessing the signatures on the document could
            // cause a concurrency problem. This is why we read the signatures
            // and certificates in this thread before passing only the 
            // certificates to the worker thread.
 
            System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(CertificateStatusCheckWorkItem), threadInfo); 
        }
 
        /// 
        /// CertificateStatusCheckThreadProc.  This is a worker thread used to call into the DigitalSignatureProvider
        /// to verify the all certificates used to sign the document.  This method takes an unknown amount of time
        /// (default of 15 second timeout per cert).  Once the work has been done then we set the waiting 
        /// dispatcherOperation to status background so it will call the Evaluate method.
        ///  
        ///  
        /// Critical
        ///  1) Sets SecurityCritical field _certificateStatusTable. 
        /// TreatAsSafe
        ///  1) The status table is set from a function specifically for this
        ///     purpose defined on the critical for set provider. The list that
        ///     we pass to the function is critical, so it comes from a trusted 
        ///     source.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private void CertificateStatusCheckWorkItem(object stateInfo)
        { 
            CertificateValidationThreadInfo threadInfo = (CertificateValidationThreadInfo)stateInfo;

            Trace.SafeWrite(
                Trace.Signatures, 
                "Starting certificate validation in thread.");
 
            // XPSDocumentCertificateStatus can take an undetermined amount of 
            // time. If timeouts occur then each Cert could take 15 secs each
            // by default and more if admin has changed defaults. 
            _certificateStatusTable =
                DigitalSignatureProvider.GetCertificateStatus(threadInfo.CertificateList);

            Trace.SafeWrite( 
                Trace.Signatures,
                "Done with certificate validation. Starting dispatcher operation."); 
 
            // The DispatcherOperation was passed to this thread so the
            // DispatcherPriority could be set to Background, and the operation 
            // that will run can call the Evaluate method.
            threadInfo.Operation.Priority = DispatcherPriority.Background;
        }
 
        /// 
        /// Gets the CertificateStatus for a specific x509Certificate from the 
        /// cached dictionary of certificates and their status. 
        /// 
        ///  
        /// Critical
        ///  1) This method uses the securitycritical field _certificateStatusTable
        ///     to get CertificatePriorityStatus
        /// TreatAsSafe 
        ///  1) This method only returns the status of certificates contained
        ///     within the Xps Document. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private CertificatePriorityStatus GetCertificateStatusFromTable(DigitalSignature digitalSignature) 
        {
            CertificatePriorityStatus certificatePriorityStatus = CertificatePriorityStatus.Corrupted;

            if (digitalSignature == null) 
            {
                throw new ArgumentNullException("digitalSignature"); 
            } 

            // Signature requests and invalid signatures with missing certificates 
            // both get the certificate status NoCertificate
            if (digitalSignature.SignatureState == SignatureStatus.NotSigned ||
                digitalSignature.Certificate == null)
            { 
                certificatePriorityStatus = CertificatePriorityStatus.NoCertificate;
            } 
            // If the certificate status table is null, the certificates are 
            // still being verified
            else if (_certificateStatusTable == null) 
            {
                certificatePriorityStatus = CertificatePriorityStatus.Verifying;
            }
            else 
            {
                Invariant.Assert( 
                    _certificateStatusTable.ContainsKey(digitalSignature.Certificate), 
                    "The certificate was not found in the certificate status table.");
 
                certificatePriorityStatus = _certificateStatusTable[digitalSignature.Certificate];
            }

            return certificatePriorityStatus; 
        }
 
        ///  
        /// OnSignatureStatusChange.
        ///  
        /// 
        /// This sends an event to update the UI which displays whether or not
        /// a document is signed, which may be used for a trust decision by the
        /// user. However, since the UI is currently displayed in an Avalon 
        /// control, making the events themselves critical does not add any
        /// protection. 
        ///  
        private void OnSignatureStatusChange(SignatureStatus newStatus)
        { 
            SignatureStatusEventArgs args = new SignatureStatusEventArgs(
                newStatus,
                SignatureResourceHelper.GetDocumentLevelResources(newStatus));
 
            RaiseSignatureStatusChange(args);
        } 
 
        /// 
        /// RaiseSignatureStatusChange. 
        /// 
        private void RaiseSignatureStatusChange(SignatureStatusEventArgs args)
        {
            if (SignatureStatusChange != null) 
            {
                SignatureStatusChange(this, args); 
            } 
        }
 
        /// 
        /// Raises the SignaturesChanged event
        /// 
        private void RaiseSignaturesChanged() 
        {
            if (SignaturesChanged != null) 
            { 
                SignaturesChanged(this, EventArgs.Empty);
            } 
        }

        /// 
        /// Handles the RMPolicyChanged event fired by the RMManager. 
        /// 
        ///  
        ///  
        ///
        ///     Critical    - Updates _allowSign, which is marked SecurityCriticalDataForSet, with 
        ///                   data obtained in the event arguments.
        ///     TreatAsSafe - The args have to be created and passed from critical code.  In
        ///                   addition the actual RMPolicy value is protected within the args from
        ///                   write. 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private void OnRMPolicyChanged(object sender, DocumentRightsManagementManager.RightsManagementPolicyEventArgs args) 
        {
            if (args != null) 
            {
                if ((args.RMPolicy & RightsManagementPolicy.AllowSign) == RightsManagementPolicy.AllowSign)
                {
                    _allowSign.Value = true; 
                }
                else 
                { 
                    _allowSign.Value = false;
                } 
            }
            else
            {
                throw new ArgumentNullException("args"); 
            }
        } 
 
        /// 
        /// VerifySignability checks the XpsDocument.IsSignable property, which 
        /// may take a significant amount of time to complete.  Because of this
        /// it will display a progress dialog to alert the user while the operation
        /// is pending.
        ///  
        /// 
        private bool VerifySignability() 
        { 
            bool result;
 
            //Show the Progress dialog
            ProgressDialog dialog =
                ProgressDialog.CreateThreaded(
                    SR.Get(SRID.ValidationProgressTitle), 
                    SR.Get(SRID.ValidationProgressLabel)).Form;
 
            try 
            {
                //Check the IsSignable property, which can take a significant portion of time... 
                result = IsSignable;
            }
            // Close the progress dialog in the event of any exception.  This prevents the
            // dialog from remaining open when the error page appears.  We cannot use a finally 
            // block here because in the case of an uncaught exception the unhandled exception
            // handler will get the exception (and show the error page) before the block runs. 
            catch 
            {
                ProgressDialog.CloseThreaded(dialog); 
                throw;
            }

            // Close the progress dialog 
            ProgressDialog.CloseThreaded(dialog);
 
            return result; 
        }
 
        /// 
        /// Uses reflection to get the protected HResult out of a CryptographicException,
        /// since it's not polite enough to make it publicly accessible to begin with.
        ///  
        /// Critical:
        ///     1) Asserts for Reflection permissions to access the HResult field of the 
        ///        incoming CryptographicException which is protected instead of public. 
        /// TreatAsSafe:
        ///     1) Only accesses and returns the HResult field, which is not critical data. 
        /// 
        /// 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private int GetErrorCode(CryptographicException ce)
        { 
            int error = 0; 

            (new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)).Assert(); //BlessedAssert 
            try
            {
                // Get the protected "HResult" field from the CryptographicException
                Type t = typeof(CryptographicException); 
                PropertyInfo p = t.GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance);
                error = (int)p.GetValue(ce, null); 
            } 
            finally
            { 
                ReflectionPermission.RevertAssert();
            }

            return error; 
        }
 
        ///  
        /// Un-does the changes in the current changelog and clears the changelog.
        /// Called when a signing or saving operation fails.  This method is critical 
        /// because clearing the changelog at inopportune times could put us in an
        /// inconsistent state.
        /// 
        /// Critical: 
        ///     1) Accesses and modifies critical _changeLog field
        ///     2) Calls critical RemoveRequestSignature and UnsignDocument methods 
        ///        on DigitalSignatureProvider. 
        /// 
        ///  
        [SecurityCritical]
        private void UndoChanges()
        {
            foreach (ChangeLogEntity entry in _changeLog) 
            {
                if (entry.IsSignatureRequest) 
                { 
                    DigitalSignatureProvider.RemoveRequestSignature(entry.Id);
                } 
                else
                {
                    DigitalSignatureProvider.UnsignDocument(entry.Id);
                } 
            }
 
            _changeLog.Clear(); 
        }
 
        #endregion Private Methods

        #region Private Properties
        //----------------------------------------------------- 
        //
        //  Private Properties 
        // 
        //------------------------------------------------------
 
        /// 
        /// Gets whether or not all signatures on the document have had their
        /// certificates validated.
        ///  
        /// 
        /// This simply goes through all the signatures on the document and 
        /// ensures that they are all represented in the status table. This is 
        /// a safe way to check whether all signatures are verified because the
        /// status table is critical. 
        /// 
        /// 
        /// Critical
        ///  1) Accesses critical member variable _certificateStatusTable. 
        ///  2) Can be used to make security decisions.
        /// TreatAsSafe 
        ///  1) The table is not modified. 
        ///  2) The decisions are made based on the critical certificate status
        ///     table. 
        /// 
        private bool AreAllSignaturesVerified
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                if (_certificateStatusTable == null) 
                {
                    return false; 
                }

                foreach (DigitalSignature signature in DigitalSignatureProvider.Signatures)
                { 
                    if (signature.Certificate != null &&
                        !_certificateStatusTable.ContainsKey(signature.Certificate)) 
                    { 
                        return false;
                    } 
                }

                return true;
            } 
        }
 
        ///  
        /// The IDigitalSignatureProvider associated with this instance of the
        /// signature manager. 
        /// 
        /// 
        /// Critical for set
        ///  1) This is a wrapper around a critical for set variable. 
        /// 
        private IDigitalSignatureProvider DigitalSignatureProvider 
        { 
            get
            { 
                return _digitalSignatureProvider.Value;
            }

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

        /// 
        /// Whether or not the current Rights Management policy allows signing.
        /// This is a convenience wrapper around critical for set data 
        /// _allowSign.
        ///  
        private bool IsSigningAllowed 
        {
            get 
            {
                return _allowSign.Value;
            }
        } 

        ///  
        /// Returns true if (as indicated by the current signature policy) any 
        /// additional signatures will not invalidate existing ones.
        ///  
        private bool IsSigningAllowedByPolicy
        {
            get
            { 
                return IsAllowedByPolicy(_signaturePolicy.Value, SignaturePolicy.AllowSigning);
            } 
        } 

        #endregion Private Properties 

        #region Private Fields
        //------------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        private static DocumentSignatureManager _singleton; 

        /// 
        /// The IDigitalSignatureProvider associated with this instance of the
        /// digital signature manager. 
        /// 
        ///  
        /// This data is critical for set because trust decisions are made on 
        /// data returned from this object. For example, whether or not a
        /// document is signed is determined through this. 
        /// 
        private SecurityCriticalDataForSet _digitalSignatureProvider;

        private IDictionary _digSigSigResources; 
        private SecurityCriticalDataForSet _allowSign;
 
        private SecurityCriticalDataForSet _signaturePolicy; 

        ///  
        /// The change log that is used to roll back signatures on failure.
        /// 
        /// 
        /// We do not want to allow the list to be modified because we use the 
        /// log to determine which signatures and requests to remove, and
        /// removing signatures or definitions is a critical operation. 
        ///  
        [SecurityCritical]
        private List _changeLog; 

        /// Dictionary that stores the status of each certificate used
        /// in signatures in the document
        ///  
        /// Critical
        ///  1) We are marking this critical so that we are guaranteed that all 
        ///     callers that modify this instance are in a trusted code path. 
        /// 
        [SecurityCritical] 
        private IDictionary _certificateStatusTable;

        /// 
        /// Constant for CryptographicException HResult corresponding to user-cancellation 
        /// of smart-card signing.
        ///  
        private const int SCARD_W_CANCELLED_BY_USER = -2146434962; 

        #endregion Private Fields 

        #region Nested Class
        //------------------------------------------------------
        // 
        //  Nested Class
        // 
        //----------------------------------------------------- 

        ///  
        /// A struct representing data passed to the thread that validates a
        /// list of certificates
        /// 
        private struct CertificateValidationThreadInfo 
        {
            ///  
            /// The list of certificates to validate 
            /// 
            ///  
            /// Critical
            ///  1) The certificate status table is expected to be set from the
            ///     elements of this list.
            ///  
            [SecurityCritical]
            internal IList CertificateList; 
 
            /// 
            /// A handle to a dispatcher operation that will evaluate the 
            /// document's signature status after the certificates have all been
            /// validated
            /// 
            internal DispatcherOperation Operation; 
        }
 
        ///  
        /// SignatureStatusEventArgs, object used when firing SigStatus change.
        ///  
        /// 
        /// This is used to determine what the UI shows and may be the basis for
        /// a trust decision by the user. However, it is not useful to make
        /// this class critical because the actual UI controls are in Avalon and 
        /// can be modified directly.
        ///  
        public class SignatureStatusEventArgs : EventArgs 
        {
            #region Constructors 
            //-----------------------------------------------------
            //
            //  Constructors
            // 
            //-----------------------------------------------------
 
            ///  
            /// The constructor
            ///  
            /// signature status
            /// Resources containing other information
            /// relevant to the document signature status
            public SignatureStatusEventArgs( 
                SignatureStatus signatureStatus,
                DocumentStatusResources statusResources) 
            { 
                _signatureStatus = signatureStatus;
                _statusResources = statusResources; 
            }

            #endregion Constructors
 
            #region Public Properties
            //------------------------------------------------------ 
            // 
            //  Public Properties
            // 
            //-----------------------------------------------------

            /// 
            /// Property to get the SigStatus 
            /// 
            public SignatureStatus SignatureStatus 
            { 
                get { return _signatureStatus; }
            } 

            /// 
            /// Property to get the StatusResources
            ///  
            public DocumentStatusResources StatusResources
            { 
                get { return _statusResources; } 
            }
 
            #endregion Public Properties

            #region Private Fields
            //------------------------------------------------------ 
            //
            //  Private Fields 
            // 
            //------------------------------------------------------
 
            private SignatureStatus _signatureStatus;
            private DocumentStatusResources _statusResources;

            #endregion Private Fields 
        }
 
        ///  
        /// Each instance represents the addition of either a request or a
        /// signature (determined by IsSignatureRequest) along with the unique 
        /// id for the item (Id).
        /// 
        private struct ChangeLogEntity
        { 
            #region Constructors
            //----------------------------------------------------------------- 
            // Constructors 
            //------------------------------------------------------------------
 
            internal ChangeLogEntity(Guid id, bool isSignatureRequest)
            {
                _id = id;
                _isSignatureRequest = isSignatureRequest; 
            }
            #endregion Constructors 
 
            #region Internal Properties
            //----------------------------------------------------------------- 
            // Internal Properties
            //-----------------------------------------------------------------

            public Guid Id 
            {
                get { return _id; } 
            } 

            public bool IsSignatureRequest 
            {
                get { return _isSignatureRequest; }
            }
            #endregion Internal Properties 

            #region Private Fields 
            //----------------------------------------------------------------- 
            // Private Fields
            //------------------------------------------------------------------ 
            private Guid _id;
            private bool _isSignatureRequest;
            #endregion Private Fields
        } 

        #endregion Nested Class 
    } 
}

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