CryptoSession.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / CryptoSession.cs / 1 / CryptoSession.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace Microsoft.InfoCards
{ 
    using System;
    using System.Collections; 
    using System.Collections.Specialized; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.Runtime.InteropServices;
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 
    using System.Security.Principal; 
    using System.ServiceModel.Security;
    using System.Threading; 
    using Microsoft.InfoCards.Diagnostics;
    using IDT=Microsoft.InfoCards.Diagnostics.InfoCardTrace;
    using System.IO;
 
    using System.Xml;
 
    // 
    // Summary:
    // This class manages a cryptography session associated with a specific token issued by the service. 
    //
    // Remarks:
    // Whenever a token is issued by the service a session id corresponding to an instance of this class is also
    // issued.  When Indigo or the client app needs to sign proof tokens with the private keys of a particular info 
    // card they can use the session id passed out with the token in order to do so.  The CryptoSession is disposed
    // whenever the token expires, or the client process to which the token was issued exits. 
    // 
    internal abstract class CryptoSession
    { 
        public static readonly TimeSpan MaxSessionLifetime = new TimeSpan( 1, 0, 0 );//1 hour

        class CryptoSessionDictionary : HandleDictionary { }
 
        //
        // NOTE!!!!!!!!!! 
        // This enum must match up with the HandleType enum in clients RpcInfoCardCryptoHandle class. 
        // NOTE!!!!!!!!!!
        // 
        protected enum SessionType
        {
            Asymmetric = 1,
            Symmetric = 2, 
            Transfrom = 3,
            Hash = 4 
        }; 

        const int m_MaxSessionCount = Int32.MaxValue / 2; 

        static CryptoSessionDictionary s_sessionCollection = new CryptoSessionDictionary();
        static object s_syncRoot = new Object();
 
        Process m_process;                      // The client process that owns this session.
        int m_sessionid;                        // A unique id for this instance. 
        EventHandler m_processExitHandler;      // The callback for client process exit. 
        EventHandler m_serviceStoppingHandler;  // The callback for service process stopping.
        System.Threading.Timer m_timer;         // The timer that goes off when this session expires. 
        bool m_isDisposed;
        object m_syncRoot;
        WindowsIdentity m_identity;             // Stores the client identity.
 
        DateTime m_expiration;
 
        SessionType m_type; 

        // 
        // Summary:
        // Constructs a new CryptoSession.
        //
        // Parameters: 
        // process    - The process to which the token was issued.
        // expiration - The session expiration time. 
        // identity   - The identity of the client. 
        // key        - The private key associated with the infocard from which the token was issued.
        // 
        protected CryptoSession( Process process,
                                 DateTime expiration,
                                 WindowsIdentity identity,
                                 object key, 
                                 SessionType type )
        { 
            IDT.Assert( null != key, "null key passed in to CryptoSession ctor" ); 

            // 
            // Make our own process object so that we can control it's lifetime.
            //
            try
            { 
                m_process = ProcessMonitor.GetProcessById( process.Id );
            } 
            catch ( ArgumentException e ) 
            {
                // 
                // The client process is gone.  The user must have cancelled.
                //
                throw IDT.ThrowHelperError( new ProcessExitedException( SR.GetString( SR.ServiceClientProcessExited, process.Id ), e ) );
            } 

            m_syncRoot = new object(); 
            m_identity = identity; 

            m_expiration = expiration; 

            m_type = type;

            lock ( s_syncRoot ) 
            {
                int sessionid; 
 
                try
                { 
                    sessionid = s_sessionCollection.GetNewHandle();
                }
                catch ( IndexOutOfRangeException e )
                { 
                    throw IDT.ThrowHelperError( new ServiceBusyException( SR.GetString( SR.ServiceTooManyCryptoSessions, s_sessionCollection.MaxSize ), e ) );
                } 
                bool success = false; 
                try
                { 
                    m_processExitHandler = new EventHandler( OnProcessExit );
                    m_process.Exited += m_processExitHandler;

                    // 
                    // Make sure the process hasn't exited before we hooked into
                    // the event. 
                    // 
                    if ( process.HasExited || m_process.HasExited )
                    { 
                        throw IDT.ThrowHelperError( new ProcessExitedException( SR.GetString( SR.ServiceProcessHasExited ) ) );
                    }

                    TimeSpan sessionLifeTime = expiration - DateTime.UtcNow; 

                    if( sessionLifeTime > MaxSessionLifetime ) 
                    { 
                        sessionLifeTime = MaxSessionLifetime;
                    } 

                    m_timer = new System.Threading.Timer( IDT.ThunkCallback(new TimerCallback(OnTimeout)),
                                                          null, // no state
                                                          sessionLifeTime, 
                                                          new TimeSpan( 0, 0, 0, 0, -1 ) );
 
                    // 
                    // Add event handler to be notified when service is stopping.
                    // 
                    m_serviceStoppingHandler = new EventHandler( OnServiceStopping );
                    InfoCardService.Stopping += m_serviceStoppingHandler;

                    s_sessionCollection[ sessionid ] = this; 
                    m_sessionid = sessionid;
                    success = true; 
                } 
                finally
                { 
                    if( !success )
                    {
                        s_sessionCollection.Remove( sessionid );
                    } 
                }
            } 
        } 

        protected uint ProcessId 
        {
            get { return ( uint )m_process.Id; }
        }
 
        protected Process ProcessObj
        { 
            get { return m_process; } 
        }
 
        protected WindowsIdentity Identity
        {
            get { return m_identity; }
        } 

        protected SecurityIdentifier ClientSid 
        { 
            get { return m_identity.User; }
        } 

        protected DateTime Expiration
        {
            get { return m_expiration; } 
        }
 
        // 
        // Summary:
        //  Serializes the CryptoSession to a BinaryWriter 
        //
        public void Write( BinaryWriter bwriter )
        {
            bwriter.Write( ( int )m_type ); 
            bwriter.Write( m_sessionid );
            bwriter.Write( m_expiration.ToFileTime() ); 
            OnWrite( bwriter ); 
        }
 
        //
        // Summary:
        // Called by the timer when this session has timed out.
        // 
        private void OnTimeout( object state )
        { 
            Dispose(); 
        }
 
        //
        // Summary
        // Called by the Process.Exited event when the client process exits.
        // 
        // Remarks
        // The event is raised from a thread running as system. 
        // 
        // Parameters
        // sender - Specifies sender of event. 
        // e      - Specifies event arguments.
        //
        private void OnProcessExit( object sender, EventArgs e )
        { 
            DisposeAsClient();
        } 
 
        //
        // Summary 
        // Handles service stopping event.
        //
        // Remarks
        // The event is raised from a thread running as system. 
        //
        // Parameters 
        // sender - Specifies sender of event. 
        // e      - Specifies event arguments.
        // 
        private void OnServiceStopping( object sender, EventArgs e )
        {
            DisposeAsClient();
        } 

        // 
        // Summary 
        // Impersonates the client before disposing.
        // 
        private void DisposeAsClient()
        {
            try
            { 
                //
                // Impersonate the client before disposing as the cryptographic 
                // context uses the security context of the caller. 
                //
                WindowsImpersonationContext context = m_identity.Impersonate(); 

                try
                {
                    Dispose(); 
                }
                finally 
                { 
                    context.Undo();
                } 
            }
            catch( Exception )
            {
                throw; 
            }
        } 
 
        protected void ThrowIfDisposed()
        { 
            if ( m_isDisposed )
            {
                throw IDT.ThrowHelperError( new ObjectDisposedException( "CryptoSession " + m_sessionid ) );
            } 
        }
 
        // 
        // Summary:
        //  Called when it is time to Dispose 
        //
        protected virtual void OnDispose() { }

        // 
        // Summary:
        //  Called when it is time to Serialize. 
        // 
        protected virtual void OnWrite( BinaryWriter bwriter ) { }
 
        //
        // Summary:
        //  Removes any references to this cryptosession from the global table, stops listening for timers and stops
        //  listening for process exit. 
        public void Dispose()
        { 
            IDT.TraceDebug( "disposing a cryptosession object" ); 
            bool didDispose = false;
 
            lock ( m_syncRoot )
            {
                if ( !m_isDisposed )
                { 
                    m_isDisposed = true;
                    didDispose = true; 
 
                    //
                    // Remove service stopping event handler from registered handlers. 
                    //
                    if( null != m_serviceStoppingHandler )
                    {
                        InfoCardService.Stopping -= m_serviceStoppingHandler; 
                        m_serviceStoppingHandler = null;
                    } 
 
                    if ( null != m_process )
                    { 
                        if ( null != m_processExitHandler )
                        {
                            m_process.Exited -= m_processExitHandler;
                            m_processExitHandler = null; 
                        }
 
                        m_process = null; 
                    }
 
                    if ( null != m_timer )
                    {
                        m_timer.Dispose();
                        m_timer = null; 
                    }
 
                    OnDispose(); 
                }
            } 

            if ( didDispose )
            {
                lock ( s_syncRoot ) 
                {
                    s_sessionCollection.Remove( m_sessionid ); 
                } 
            }
        } 

        //
        // Summary:
        //  Creates a CryptoSession object corresponding to the type of key passed in. 
        //
        static public CryptoSession Create( Process process, 
                                            DateTime expiration, 
                                            WindowsIdentity identity,
                                            RSACryptoServiceProvider key ) 
        {
            return new AsymmetricCryptoSession( process, expiration, identity, key );
        }
 
        //
        // Summary: 
        //  Creates a CryptoSession object corresponding to the type of key passed in. 
        //
        static public CryptoSession Create( Process process, 
                                            DateTime expiration,
                                            WindowsIdentity identity,
                                            byte[ ] key )
        { 
            return new SymmetricCryptoSession( process, expiration, identity, key );
        } 
 
        //
        // Summary: 
        //  Looks up an existing CryptoSession based on sessionid and processid.
        //
        static public CryptoSession Find( int sessionId, uint processId, SecurityIdentifier clientSid )
        { 
            CryptoSession session;
 
            lock ( s_syncRoot ) 
            {
                if ( s_sessionCollection.ContainsHandle( sessionId ) ) 
                {
                    session = s_sessionCollection[ sessionId ];
                }
                else 
                {
                    throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.ServiceUnknownCryptoSessionId ) ) ); 
                } 

                if ( session.ProcessId != processId ) 
                {
                    throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.ServiceUnknownCryptoSessionId ) ) );
                }
 
                if ( session.ClientSid != clientSid )
                { 
                    throw IDT.ThrowHelperError( new CommunicationException( SR.GetString( SR.ServiceUnknownCryptoSessionId ) ) ); 
                }
            } 

            return session;
        }
 
    }
 
    // 
    // Summary:
    //  A strictly Asymmetric CryptoSession.  Wraps an RSACryptoServiceProvider. 
    //
    internal class AsymmetricCryptoSession : CryptoSession
    {
        RSACryptoServiceProvider m_provider; 

        public AsymmetricCryptoSession( Process process, 
                                        DateTime expirationTime, 
                                        WindowsIdentity identity,
                                        RSACryptoServiceProvider key ) 
        : base( process, expirationTime, identity, key, CryptoSession.SessionType.Asymmetric )
        {
            //
            // due to the fact the handles must be closed as the user, 
            // we can not let finialization dispose these objects.
            // 
            // Since we will own the reference to the RSACryptoServiceProvider 
            // we do not need to duplicate it
            // 
            m_provider = key;
        }

        protected override void OnWrite( BinaryWriter bwriter ) 
        {
            bwriter.Write( m_provider.KeySize ); 
            Utility.SerializeString( bwriter, m_provider.KeyExchangeAlgorithm ); 
            Utility.SerializeString( bwriter, m_provider.SignatureAlgorithm );
        } 

        protected override void OnDispose()
        {
            m_provider.Clear(); 

            // 
            // Dispose this explicitly, as the keys are created using 
            //  the user's identity.  If the finallizer gets it, it will throw
            //  becuase it always runs as LSA. 
            //
            ((IDisposable)m_provider).Dispose();
            m_provider = null;
        } 

        // 
        // Summary: 
        //  Encrypts a buffer of data.
        // 
        // Paramters:
        //  inData  - The data to encyrpt.
        //
        // Returns: 
        //  Returns a buffer of encrypted data.
        // 
        public byte[] Encrypt(  bool fOAEP, byte[] inData ) 
        {
            ThrowIfDisposed(); 

            return m_provider.Encrypt( inData, fOAEP );
        }
 
        //
        // Summary: 
        //  Decrypts a buffer of data. 
        //
        // Paramters: 
        //  inData  - The data to decyrpt.
        //
        // Returns:
        //  Returns a buffer of decrypted data. 
        //
        public byte[] Decrypt( bool fOAEP, byte[] inData ) 
        { 
            ThrowIfDisposed();
 
            return m_provider.Decrypt( inData, fOAEP );
        }

        // 
        // Summary:
        //  Signs a hash. 
        // 
        // Parameters:
        //  hash        - The hash to sign. 
        //  hashAlgOid  - A string OID that identifies the algorithm used to create the hash.
        //
        // Returns:
        //  Returns a signature. 
        //
        public byte[] SignHash( byte[] hash, string hashAlgOid ) 
        { 
            ThrowIfDisposed();
 
            return m_provider.SignHash( hash, hashAlgOid );
        }

        // 
        // Summary:
        //  Verifies that a hash and signature match. 
        // 
        // Parameters:
        //  hash        - The hash to sign. 
        //  hashAlgOid  - A string OID that identifies the algorithm used to create the hash.
        //  sig         - A signature that should match the hash.
        //
        // Returns: 
        //  true if the hash and signature match, otherwise false.
        // 
        public bool VerifyHash( byte[] hash, string hashAlgOid, byte[] sig ) 
        {
            ThrowIfDisposed(); 

            return m_provider.VerifyHash( hash, hashAlgOid, sig );
        }
    } 

    // 
    // Summary: 
    //  A strictly SymmetricCryptoSession.  Currently wraps a RijndaelManaged instance.
    // 
    internal class SymmetricCryptoSession : CryptoSession
    {
        public enum Direction
        { 
            Encrypt = 1,
            Decrypt = 2 
        }; 

        SymmetricAlgorithm m_alg; 

        public SymmetricCryptoSession( Process process,
                                       DateTime expiration,
                                       WindowsIdentity identity, 
                                       byte[] key )
        : base( process, expiration, identity, key, CryptoSession.SessionType.Symmetric ) 
        { 
            m_alg = new RijndaelManaged();
            m_alg.Key = key; 
        }

        protected override void OnDispose()
        { 
            m_alg.Clear();
            // 
            // Dispose this explicitly, as the keys are created using 
            //  the user's identity.  If the finallizer gets it, it will throw
            //  becuase it always runs as LSA. 
            //
            ((IDisposable)m_alg).Dispose();
            m_alg = null;
        } 

        protected override void OnWrite(BinaryWriter bwriter) 
        { 
            bwriter.Write( m_alg.KeySize );
            bwriter.Write( m_alg.BlockSize ); 
            bwriter.Write( m_alg.FeedbackSize );
        }

        public byte[] GenerateDerivedKey( string algorithmUri, 
                                   byte[] label,
                                   byte[] nonce, 
                                   int derivedKeyLength, 
                                   int offset)
        { 
            if( algorithmUri == SecurityAlgorithms.Psha1KeyDerivation ||
                algorithmUri == SecurityAlgorithms.Psha1KeyDerivationDec2005 )
            {
                return new Psha1DerivedKeyGenerator( m_alg.Key ).GenerateDerivedKey( label, nonce, derivedKeyLength, offset ); 
            }
            else 
            { 
                throw IDT.ThrowHelperWarning( new InfoCardArgumentException( SR.GetString( SR.ServiceUnsupportedKeyDerivationAlgorithm, algorithmUri ) ) );
            } 
        }

        //
        // Summary: 
        //  Wraps the CreateDecryptor/CreateEncryptor of an AsymmetricAlgorithm, and returns a TransformCryptoSession.
        // 
        public TransformCryptoSession GetCryptoTransform( CipherMode  mode, 
                                                          PaddingMode padding,
                                                          int         feedbackSize, 
                                                          Direction   direction,
                                                          byte[] iv )
        {
            m_alg.Mode = mode; 
            m_alg.Padding = padding;
            m_alg.IV = iv; 
 
            ICryptoTransform icrypto;
 
            if ( Direction.Encrypt == direction )
            {
                icrypto = m_alg.CreateEncryptor();
            } 
            else
            { 
                icrypto = m_alg.CreateDecryptor(); 
            }
 
            return new TransformCryptoSession( ProcessObj,
                                               Expiration,
                                               Identity,
                                               icrypto ); 
        }
 
        // 
        // Summary:
        //  Returns a HashCryptoSession based on the key held by this session. 
        //
        public HashCryptoSession GetKeyedHash()
        {
            KeyedHashAlgorithm keyedHashAlgorithm = new HMACSHA1( m_alg.Key ); 
            keyedHashAlgorithm.Initialize();
 
            return new HashCryptoSession( ProcessObj, 
                                          Expiration,
                                          Identity, 
                                          keyedHashAlgorithm );
        }
    }
 
    //
    // Summary: 
    //  Wraps an ICryptoTransform and exports it from the service. 
    //
    internal class TransformCryptoSession : CryptoSession 
    {
        ICryptoTransform m_icrypto;

        public TransformCryptoSession( Process process, 
                                       DateTime expiration,
                                       WindowsIdentity identity, 
                                       ICryptoTransform icrypto ) 
        : base( process, expiration, identity, icrypto, CryptoSession.SessionType.Transfrom )
        { 
            m_icrypto = icrypto;
        }

        protected override void OnDispose() 
        {
            m_icrypto.Dispose(); 
        } 

        protected override void OnWrite(BinaryWriter bwriter) 
        {
            bwriter.Write( m_icrypto.InputBlockSize );
            bwriter.Write( m_icrypto.OutputBlockSize );
            bwriter.Write( m_icrypto.CanTransformMultipleBlocks ); 
            bwriter.Write( m_icrypto.CanReuseTransform );
        } 
 
        //
        // Summary: 
        //  Simple wrapper for the the ICryptoTransform.TransformBlock method.
        //
        public int TransformBlock( byte[] inData, out byte[] outData )
        { 
            int count;
 
            outData = new byte[ m_icrypto.OutputBlockSize ]; 

            count = m_icrypto.TransformBlock( inData, 0, inData.Length, outData, 0 ); 

            return count;
        }
 
        //
        // Summary: 
        //  Simple wrapper for the the ICryptoTransform.TransformFinalBlock method. 
        //
        public byte[] TransformFinalBlock( byte[] inData ) 
        {
            return m_icrypto.TransformFinalBlock( inData, 0, inData.Length );
        }
    } 

    // 
    // Summary: 
    //  Wraps a KeyedHashAlgorithm.
    // 
    internal class HashCryptoSession : CryptoSession
    {
        KeyedHashAlgorithm m_hash;
 
        public HashCryptoSession( Process process,
                                  DateTime expiration, 
                                  WindowsIdentity identity, 
                                  KeyedHashAlgorithm hash )
        : base( process, expiration, identity, hash, CryptoSession.SessionType.Hash ) 
        {
            m_hash = hash;
        }
 
        protected override void OnDispose()
        { 
            m_hash.Clear(); 

            // 
            // Dispose this explicitly, as the keys are created using
            //  the user's identity.  If the finallizer gets it, it will throw
            //  becuase it always runs as LSA.
            // 
            ((IDisposable)m_hash).Dispose();
            m_hash = null; 
        } 

        protected override void OnWrite(BinaryWriter bwriter) 
        {
            bwriter.Write( m_hash.HashSize );
            bwriter.Write( m_hash.InputBlockSize );
            bwriter.Write( m_hash.OutputBlockSize ); 
            bwriter.Write( m_hash.CanTransformMultipleBlocks );
            bwriter.Write( m_hash.CanReuseTransform ); 
        } 

        // 
        // Summary:
        //  Uses the KeyedHashAlgorithm.TransformBlock method to implement the equivalent of the
        //  KeyedHashAlgorithm.HashCore method.
        // 
        public void HashCore( byte[] inData )
        { 
            m_hash.TransformBlock( inData, 0, inData.Length, null, 0 ); 
        }
 
        //
        // Summary:
        //  Uses the KeyedHashAlgorithm.TransformFinalBlock method to implement the equivalent of the
        //  KeyedHashAlgorithm.HashFinal method.  This method differs from the HashFinal method in the fact 
        //  that it takes the final buffer as input.
        // 
        public byte[] HashFinal( byte[] inData ) 
        {
            try 
            {
                m_hash.TransformFinalBlock( inData, 0, inData.Length );
            }
            finally 
            {
                m_hash.Initialize(); 
            } 

            return m_hash.Hash; 
        }
    }
}

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