InfoCard.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 / InfoCard.cs / 2 / InfoCard.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
//
// Presharp uses the c# pragma mechanism to supress its warnings. 
// These are not recognised by the base compiler so we need to explictly
// disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp 
// for details. 
//
#pragma warning disable 1634, 1691      // unknown message, unknown pragma 

internal enum RequireAppliesToStatus : byte
{
    NotPresent = 0, 
    Optional = 1,
    Required = 2 
}; 

namespace Microsoft.InfoCards 
{
    using System;
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.IO;
    using System.Security; 
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Xml; 
    using System.Xml.Schema;
    using System.Xml.Serialization; 
    using System.ServiceModel; 

    using Microsoft.InfoCards.Diagnostics; 
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace;

    //
    // Summary 
    // This is the primary "ticket" information the user receives from the issuer. It service
    // the service to retrieve security tokens from the associated token factory on behalf of 
    // the user. It includes display data (name, logo, category), issuer information 
    // authentication information allowing the system to present the user's credentials to the
    // associated token factory. The class also includes accessor's for retrieving associated 
    // collections including supported claims and ledger entries.
    //
    // Remarks
    // 
    internal class InfoCard : IXmlSerializable
    { 
        // 
        // Row numbers start at 1. 0 will never be valid
        // 
        const Int32 InvalidRow = 0;

        //
        // Random value used to mark the start/end of serialized object. 
        //
        const byte Marker = 29; 
 
        //
        // Used to verify the serialized version of the InfoCard 
        //
        const byte Version = 1;

        // 
        // Size of RSA subject keys in bits
        // 
        public const int KeySize = 2048; 

        // 
        // Size of InfoCard MasterKey in bytes
        //
        public const int MasterKeySize = 32;
 
        //
        // Size of InfoCard Salt in bytes 
        // 
        public const int SaltSize = 16;
 
        enum PinAction : byte
        {
            NoPin = 0,
            PinSame = 1, 
            PinAdded = 2,
            PinRemoved = 3, 
            PinChanged = 4 
        };
 



        InfoCardClaimCollection m_claims; 
        DateTime m_expiresOn = DateTime.MaxValue;
        UInt32 m_epoch = 0; 
        Uri m_id; 
        DateTime m_issuedOn = DateTime.MinValue;
        bool m_isImported = false; 
        DateTime m_installedOn = DateTime.Now;
        string m_issuerName = String.Empty;
        string m_language = String.Empty;
        LedgerEntryCollection m_ledger; 
        byte[ ] m_logo;
        string m_mimeType = String.Empty; 
        string m_name = String.Empty; 
        DateTime m_lastUpdate = DateTime.MinValue;
        Int32 m_rowId = InvalidRow; 
        StoreConnection m_storeConnection;
        Int32 m_backgroundColor;
        string[ ] m_tokenTypes;
        RequireAppliesToStatus m_requireAppliesTo = RequireAppliesToStatus.NotPresent; 
        byte[ ] m_pinHash;
        bool m_isSelfIssued = false; 
        byte[ ] m_salt = null; 
        InfoCardMasterKey m_masterKey;
        string m_privacyPolicyLink = String.Empty; 
        byte[ ] m_issuerIdentifierAsBytes;
        Uri m_issuer;
        uint m_privacyPolicyVersion;
        string m_pin = String.Empty; 
        string m_oldPin = String.Empty;
        PinAction m_pinAction = PinAction.NoPin; 
        InfocardExtendedInformationCollection m_extendedInformation; 
        bool m_readIssuerInformation = false;
        RPIdentityRequirement m_rpStrongIdentityRequired; 

        List m_creationParameters;

        // 
        // Summary
        // Create an instance of the InfoCard class in the initial state. 
        // 
        // Remarks
        // We will support this since it may be needed to build an instance piece meal. 
        // Other methods that require the object to be complete (e.g. Serialize) will need to call
        // ThrowIfNotComplete() to verify that all required fields have been populated.
        //
 
        //
        // Consider for future -- see postponed bug 40840 
        // Avoid piecemeal construction of InfoCard -- which would prevent construction of 
        // incomplete InfoCards
        // 
        public InfoCard()
        {
            m_lastUpdate = DateTime.UtcNow;
        } 

 
        // 
        // Summary
        // Create an instance of the InfoCard to be used to retrieve the card from the store. 
        //
        public InfoCard( Uri id )
        {
            m_id = id; 
        }
 
        // 
        // Summary
        // Create an instance of the InfoCard class from a previously serialized stream. 
        //
        // Remarks
        // This method will primarily be called when an updated intance of an infocard is returned from the
        // agent process via RPC. 
        //
        // Parameters 
        // stream - binary stream conforming to the serialization format supported by this class. See Serialize/Deserialize method 
        //          for more details.
        // 
        public InfoCard( Stream stream )
        {
            Deserialize( stream );
        } 

        public string[ ] TokenTypes 
        { 
            set { m_tokenTypes = value; }
        } 

        public List CreationParameters
        {
            get 
            {
                if( null == m_creationParameters ) 
                { 
                    m_creationParameters = new List();
                } 
                return m_creationParameters;
            }
        }
        public InfoCardClaimCollection GetClaims() 
        {
            if( null == m_claims ) 
            { 
                if( null == m_id )
                { 
                    IDT.Assert( null != m_id, "m_id" );
                }

                m_claims = new InfoCardClaimCollection( m_id ); 

                if( null != m_storeConnection ) 
                { 
                    m_claims.Get( m_storeConnection );
                } 
            }

            return m_claims;
        } 

        public static IssuerInformation GetIssuerInformation( string xml ) 
        { 
            IssuerInformation info = new IssuerInformation();
 
            if( !string.IsNullOrEmpty( xml ) )
            {
                try
                { 
                    info.ReadIssuerInformation( InfoCardSchemas.CreateReader( xml ) );
                } 
                catch( Exception e ) 
                {
                    if( IDT.IsFatal( e ) ) 
                    {
                        throw;
                    }
                    else 
                    {
                        throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.ServiceUnableToDeserializeInfoCardStream ), e ) ); 
                    } 
                }
            } 

            return info;
        }
 
        public InfocardExtendedInformationCollection GetExtendedInformation()
        { 
            if( null == m_extendedInformation ) 
            {
                IDT.Assert( null != m_id, "m_id" ); 

                m_extendedInformation = new InfocardExtendedInformationCollection( m_id );

                if( null != m_storeConnection ) 
                {
                    m_extendedInformation.Get( m_storeConnection ); 
                } 
            }
 
            return m_extendedInformation;
        }

        public RPIdentityRequirement GetRPIdentityRequirement() 
        {
 
            if( null == m_rpStrongIdentityRequired ) 
            {
                m_rpStrongIdentityRequired = new RPIdentityRequirement( m_id, false ); 

                if( null != m_storeConnection )
                {
                    m_rpStrongIdentityRequired.Get( m_storeConnection ); 
                }
            } 
 
            return m_rpStrongIdentityRequired;
 
        }

        public void AddClaim( InfoCardClaim claim )
        { 
            IDT.Assert( null != claim, "null claim" );
            GetClaims().Add( claim ); 
        } 

        public void AddLedgerEntry( LedgerEntry entry ) 
        {
            IDT.Assert( null != entry, "null ledger entry" );
            GetLedger().Add( entry );
        } 

        public DateTime ExpiresOn 
        { 
            get { return m_expiresOn; }
            set { m_expiresOn = value; } 
        }

        public UInt32 Epoch
        { 
            get { return m_epoch; }
            set { m_epoch = value; } 
        } 

        public Uri Id 
        {
            get { return m_id; }
            set { m_id = value; }
        } 

        public DateTime IssuedOn 
        { 
            get { return m_issuedOn; }
            set { m_issuedOn = value; } 
        }

        public string IssuerName
        { 
            get { return m_issuerName; }
            set { m_issuerName = value; } 
        } 

        public byte[ ] IssuerIdentifierAsBytes 
        {
            get { return m_issuerIdentifierAsBytes; }
            set { m_issuerIdentifierAsBytes = value; }
        } 

        public Uri Issuer 
        { 
            set { m_issuer = value; }
        } 

        public string Language
        {
            get { return m_language; } 
            set { m_language = value; }
        } 
 
        public RequireAppliesToStatus RequireAppliesto
        { 
            get { return m_requireAppliesTo; }
            set { m_requireAppliesTo = value; }
        }
 
        public bool IsSelfIssued
        { 
            get { return m_isSelfIssued; } 
            set { m_isSelfIssued = value; }
        } 

        public string PrivacyPolicyLink
        {
            get { return m_privacyPolicyLink; } 
            set { m_privacyPolicyLink = value; }
        } 
 
        public uint PrivacyPolicyVersion
        { 
            get { return m_privacyPolicyVersion; }
        }

        public LedgerEntryCollection GetLedger() 
        {
            if( null == m_ledger ) 
            { 
                IDT.Assert( null != m_id, "m_id is null" );
 
                m_ledger = new LedgerEntryCollection( m_id );

                if( null != m_storeConnection )
                { 
                    m_ledger.Get( m_storeConnection );
                } 
            } 

            return m_ledger; 

        }

        public StoreConnection Connection 
        {
            set { m_storeConnection = value; } 
        } 

        // 
        // Summary
        // Trys to retrieve the ledger entry for the specified recipient.
        //
        // Parameters 
        // connection          - Specifies store connection.
        // recipientIdentifier - Specifies recipient identifier. 
        // 
        // Returns
        // Returns ledger entry if one found otherwise null. 
        //
        public LedgerEntry TryGetLedgerEntry( StoreConnection connection, string recipientIdentifier )
        {
            LedgerEntry entry = null; 

            IDT.Assert( null != connection, "The store connection cannot be null." ); 
            IDT.Assert( false == string.IsNullOrEmpty( recipientIdentifier ), "A recipient identifier must be specified." ); 

            // 
            // Query ledger member first.
            //
            if( null != m_ledger )
            { 
                if( m_ledger.ContainsKey( recipientIdentifier ) )
                { 
                    entry = m_ledger[ recipientIdentifier ]; 
                }
            } 

            //
            // If not found in ledger member then query store.
            // 
            if( null == entry )
            { 
                DataRow row = connection.GetSingleRow( 
                    new QueryParameter(
                        SecondaryIndexDefinition.ObjectTypeIndex, (Int32)StorableObjectType.LedgerEntry ), 
                    new QueryParameter(
                        SecondaryIndexDefinition.ParentIdIndex, GlobalId.DeriveFrom( m_id.ToString() ) ),
                    new QueryParameter(
                        SecondaryIndexDefinition.RecipientIdIndex, recipientIdentifier ) ); 

                if( null != row ) 
                { 
                    entry = new LedgerEntry( new MemoryStream( row.GetDataField() ), connection );
                } 
            }

            return entry;
        } 

        // 
        // Summary 
        // Creates ledger entry for specified recipient.
        // 
        // Parameters
        // recipient - Specifies the recipient.
        //
        // Returns 
        // Returns the new ledger entry.
        // 
        public LedgerEntry CreateLedgerEntry( Recipient recipient, string immediateTokenRecipientOrganizationIdentifier ) 
        {
            IDT.Assert( null != recipient, "A recipient must be specified." ); 

            if( null == m_ledger )
            {
                IDT.Assert( null != m_id, "The card identifier must be defined." ); 

                m_ledger = new LedgerEntryCollection( Id ); 
            } 

            LedgerEntry entry = LedgerEntry.NewLedgerEntry( Id, recipient, Key, immediateTokenRecipientOrganizationIdentifier ); 

            m_ledger.Add( entry );

            return entry; 
        }
 
        // 
        // Summary
        // Checks and updates the ledger entry. 
        //
        // Parameters
        // entry - Ledger entry to be updated
        // immediateTokenRecipientOrgId - Specifies the immediate token recipient Id. 
        //
        // 
        public void CheckAndUpdateLedgerEntry( LedgerEntry entry, string immediateTokenRecipientOrgId ) 
        {
            if( entry.CheckAndUpdateSubjectKey( immediateTokenRecipientOrgId, this.Key ) ) 
            {
                if( null == m_ledger )
                {
                    IDT.Assert( null != this.Id, "The card identifier must be defined." ); 

                    m_ledger = new LedgerEntryCollection( this.Id ); 
                } 
                //
                // Update the ledger entry in the collection 
                //
                if( m_ledger.ContainsKey( entry.Recipient.RecipientId ) )
                {
                    m_ledger[ entry.Recipient.RecipientId ] = entry; 
                }
                else 
                { 
                    m_ledger.Add( entry );
                } 
            }
        }

        public byte[ ] Logo 
        {
            get { return m_logo; } 
            set { m_logo = value; } 
        }
 
        public string LogoMimeType
        {
            get { return m_mimeType; }
            set { m_mimeType = value; } 
        }
 
        public string Name 
        {
            get { return m_name; } 
            set { m_name = value; }
        }

        public DateTime LastUpdate 
        {
            get { return m_lastUpdate; } 
            set { m_lastUpdate = value; } 
        }
 
        public Int32 BackgroundColor
        {
            get { return m_backgroundColor; }
            set { m_backgroundColor = value; } 
        }
 
        public byte[ ] HashSalt 
        {
            set { m_salt = value; } 
            get { return m_salt; }
        }

        public string[ ] SupportedClaimTypes 
        {
            get 
            { 
                List supportedClaimTypes = new List();
 
                foreach( string key in GetClaims().Keys )
                {
                    if( !IsSelfIssued || !String.IsNullOrEmpty( GetClaims()[ key ].Value ) )
                    { 
                        supportedClaimTypes.Add( key );
                    } 
                } 
                return supportedClaimTypes.ToArray();
            } 
        }

        public bool IsImported
        { 
            set { m_isImported = value; }
        } 
 
        public DateTime InstalledOn
        { 
            set { m_installedOn = value; }
        }

        public bool IsPinProtected 
        {
            get { return ( null == m_pinHash ) ? false : ( m_pinHash.Length > 0 ); } 
        } 

        public string Pin 
        {
            get { return m_pin; }
        }
 
        //
        // Summary 
        //   Read this infocard's masterkey from the store 
        //
        // Returns 
        //   connection - the store connection object
        //
        public InfoCardMasterKey GetMasterKey( StoreConnection connection )
        { 
            IDT.Assert( null != connection, "Store connection should not be null" );
            m_masterKey = new InfoCardMasterKey( m_id ); 
            m_masterKey.Get( connection ); 

            return m_masterKey; 
        }

        public void Decrypt()
        { 
            IDT.Assert( null != m_masterKey, "The GetMasterKey must be called before using this method." );
 
            // 
            // Decrypt the masterkey and claims
            // 
            PinProtectionHelper pinHelper = m_masterKey.GetPinHelper( m_pin );
            m_masterKey.Decrypt( pinHelper );

            GetClaims().Decrypt( pinHelper ); 
        }
 
        // 
        // Summary:
        //   Retrieve the infocard masterkey. 
        //
        public byte[ ] Key
        {
            get 
            {
                return ( null == m_masterKey ) ? null : m_masterKey.Key; 
            } 
        }
 
        //
        // Summary:
        //   Use this function to clear the bytes of the masterkey buffer
        // 
        public void ClearSensitiveData()
        { 
            // 
            // Expect masterkey to be null for read only requests
            // 
            if( null != m_masterKey )
            {
                Array.Clear( m_masterKey.Key, 0, m_masterKey.Key.Length );
            } 
        }
 
        // 
        // Summary
        //   Generate salt for the Infocard. To be used for 
        //   setting infocard properties piece meal
        //
        // Returns
        //   The generated salt 
        //
        public static byte[ ] GenerateSalt() 
        { 
            byte[ ] salt = new byte[ SaltSize ];
            RNGCryptoServiceProvider prov = new RNGCryptoServiceProvider(); 
            prov.GetBytes( salt );
            return salt;
        }
 

        public void ThrowIfNotComplete() 
        { 
            if( !IsComplete() )
            { 
                throw IDT.ThrowHelperError( new SerializationIncompleteException( this.GetType() ) );
            }
        }
 
        //
        // Summary 
        // Provides an indication of whether the required members of the InfoCard class 
        // all properly specified.
        // 
        // Remarks
        // This function is useful to determine if the object is ready to be persisted.
        // If an object is not complete or contains nulls for certain values the serialization
        // code will not work. 
        //
        // Returns 
        // true     - object is complete 
        // false    - object is incomplete
        // 
        public bool IsComplete()
        {
            //
            // Verify that the infocard has been populated. 
            //
            bool complete = ( 
                   !string.IsNullOrEmpty( m_language ) && 
                   null != m_id &&
                   null != m_issuer && 
                   !Utility.ArrayIsNullOrEmpty( m_tokenTypes ) &&  // Card is expected to have at least one token type
                   null != m_privacyPolicyLink &&
                   !Utility.ArrayIsNullOrEmpty( m_salt ) &&
                   m_epoch > 0 && 
                   DateTime.MinValue != m_issuedOn &&
                   DateTime.MinValue != m_expiresOn && 
                   DateTime.MinValue != m_lastUpdate ); 

            if( !IsSelfIssued ) 
            {
                complete = complete && CreationParameters.Count > 0 && null != m_issuerIdentifierAsBytes;
            }
 
            return complete;
        } 
 
        //
        // Summary: 
        // Private function, only to be used by GetPrivate/PublicCryptography
        //
        //
        private RSACryptoServiceProvider GetPrivateKeyPairRsaProvider( string recipientIdentifier ) 
        {
            // 
            // Perform a lookup to get the LedgerEntry associated with this recipient 
            //
            LedgerEntry entry = TryGetLedgerEntry( m_storeConnection, recipientIdentifier ); 
            IDT.Assert( null != entry, "null ledger" );

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider( InfoCard.KeySize );
            rsa.ImportCspBlob( entry.SubjectKey ); 

            return rsa; 
        } 

        // 
        // Summary
        // Generates and returns an instance of an RSACryptoProvider for signing
        // using the pair-wise key associated with the recipient whose recipientIdentifier is
        // specified. 
        //
        // Remarks 
        // The RSA key pair is retrieved from the LedgerEntry associated with the specified 
        // recipient.
        // 
        // Parameters
        // recipientIdentifier - a unique identifier to identify the recipient
        //
        // Returns 
        // An RSACryptoServiceProvider containing the pair-wise key pair from the ledger entry.
        // Includes private key info. 
        // 
        public RSACryptoServiceProvider GetPrivateCryptography( string recipientIdentifier )
        { 
            RSACryptoServiceProvider rsa = GetPrivateKeyPairRsaProvider( recipientIdentifier );
            return rsa;
        }
 
        //
        // Summary 
        // Generates and returns an instance of an RSACryptoProvider for signing 
        // using the pair-wise key associated with the recipient whose recipientIdentifier is
        // specified. 
        //
        // Remarks
        // The RSA key pair is retrieved from the LedgerEntry associated with the specified
        // recipient. 
        //
        // Parameters 
        // recipientIdentifier - a unique identifier to identify the recipient 
        //
        // Returns 
        // An RSACryptoServiceProvider containing the pair-wise key pair from the ledger entry.
        // Only has public key info.
        //
        public RSACryptoServiceProvider GetPublicCryptography( string recipientIdentifier ) 
        {
            RSACryptoServiceProvider rsa = GetPrivateKeyPairRsaProvider( recipientIdentifier ); 
 
            //
            // Recreate it with just the public part 
            //
            rsa.ImportCspBlob( rsa.ExportCspBlob( false ) );
            IDT.Assert( rsa.PublicOnly, "GetPublicCryptography returns a public only rsa" );
            return rsa; 
        }
 
        // 
        // Summary
        // Write binary sequence of instance members to the provided stream. 
        //
        // Remarks
        // This method will verify that the instance has been fully populated by calling
        // ThrowIfNotComplete() to confirm that all required fields have been populated. 
        // All members are serialized using fixed length (or counted) types in little-endian format (e.g. Int64).
        // Strings are serialized using a counted array of unicode characters. 
        // 
        // Parameters
        // stream - binary stream conforming to the serialization format supported by this class. 
        //
        private void Serialize( System.IO.Stream stream )
        {
            // 
            // Make sure that we don't serialize an incomplete object. Serializing null values will result in a
            // serialization exception or a corrupt signature. 
            // 
            ThrowIfNotComplete();
 
            //
            // Setup a BinaryWriter to serialize the bytes of each member to the provided stream
            //
            System.IO.BinaryWriter writer = new BinaryWriter( stream, Encoding.Unicode ); 

            // 
            // Write each member to binary stream 
            //
            writer.Write( Version ); 
            writer.Write( (Int64)m_expiresOn.ToFileTimeUtc() );
            writer.Write( m_epoch );
            Utility.SerializeUri( writer, m_id );
            writer.Write( (Int64)m_issuedOn.ToFileTimeUtc() ); 
            writer.Write( m_isImported );
            writer.Write( (Int64)m_installedOn.ToFileTimeUtc() ); 
            writer.Write( m_isSelfIssued ); 
            Utility.SerializeUri( writer, m_issuer );
            Utility.SerializeString( writer, m_issuerName ); 
            Utility.SerializeBytes( writer, m_issuerIdentifierAsBytes );
            Utility.SerializeString( writer, m_language );
            Utility.SerializeBytes( writer, m_logo );
            Utility.SerializeString( writer, m_mimeType ); 
            Utility.SerializeString( writer, m_name );
            writer.Write( (Int64)m_lastUpdate.ToFileTimeUtc() ); 
            writer.Write( m_backgroundColor ); 
            writer.Write( (byte)m_requireAppliesTo );
            Utility.SerializeString( writer, m_privacyPolicyLink ); 
            writer.Write( m_privacyPolicyVersion );
            Utility.SerializeBytes( writer, m_pinHash );
            Utility.SerializeBytes( writer, m_salt );
            writer.Write( (Int32)m_tokenTypes.Length ); 
            for( int i = 0; i < m_tokenTypes.Length; i++ )
            { 
                Utility.SerializeString( writer, m_tokenTypes[ i ] ); 
            }
 
            //
            // Serialize the list of identity provider end point information.
            // Note: This list will be empty on self issued cards
            // 
            writer.Write( ( null == m_creationParameters ? (Int32)0 : m_creationParameters.Count ) );
            if( null != m_creationParameters ) 
            { 
                for( int i = 0; i < m_creationParameters.Count; i++ )
                { 
                    m_creationParameters[ i ].Serialize( writer );
                }
            }
 
            //
            // We will never serialize the pins out of the service. These must be supplied by the 
            // service in order to unlock pin protected cards. 
            //
            Utility.SerializeString( writer, String.Empty ); 
            Utility.SerializeString( writer, String.Empty );

            writer.Write( (byte)m_pinAction );
 
            writer.Write( Marker );
        } 
 
        public void AgentSerialize(
            System.IO.Stream stream, 
            bool initCalcAttributesForGetToken,
            InfoCardPolicy policy,
            StoreConnection storeConnection,
            CultureInfo userCulture ) 
        {
 
            // 
            // Serialize the infocard
            // 
            this.Serialize( stream );

            //
            // Consider for future -- see bug 38733 -- If we have the context object in place 
            // we do not need to do this
            // 
 
            //
            // The store connection has to always be set before 
            // any information is retrieved from the store. Don't call GetClaims()
            // or GetExtendedInformation() before doing the step below.
            //
            m_storeConnection = storeConnection; 
            GetRPIdentityRequirement().Serialize( stream );
 
            GetExtendedInformation().Serialize( stream ); 
            string issuerInformation = GetExtendedInformation().GetIssuerInformationElement();
 
            InfoCard.GetIssuerInformation( issuerInformation ).Serialize( stream );


            // 
            // Serialize the claims. Claims must already have been populated
            // 
            InfoCardClaimCollection claimCollection = GetClaims(); 

 
            //
            // Add the ppid claim here
            //
            if( null != policy && IsSelfIssued ) 
            {
                CultureInfo backup = System.Threading.Thread.CurrentThread.CurrentUICulture; 
 
                //
                // Change the culture before reading the claim strings 
                //
                try
                {
                    System.Threading.Thread.CurrentThread.CurrentUICulture = userCulture; 

                    string ppidStr = Utility.CreatePpid( 
                                                 Convert.FromBase64String( policy.ImmediateTokenRecipient.GetOrganizationPPIDIdentifier() ), 
                                                 m_id );
 
                    claimCollection.Add( new InfoCardClaim(
                        InfoCardConstants.PPIDClaimsUri,
                        ppidStr,
                        InfoCardConstants.ClaimsDescription( InfoCardConstants.PPID ), 
                        InfoCardConstants.ClaimDisplayTag( InfoCardConstants.PPID ) ) );
                } 
                finally 
                {
                    System.Threading.Thread.CurrentThread.CurrentUICulture = backup; 
                }

            }
 
            //
            // Now serialize all the claims 
            // 
            claimCollection.AgentSerialize( stream );
 
            BinaryWriter writer = new BinaryWriter( stream, System.Text.Encoding.Unicode );

            //
            // Serialize the calculated attributes 
            //
            if( initCalcAttributesForGetToken ) 
            { 
                writer.Write( DoesCardMatchPolicySet( policy ) );
                writer.Write( CardMatchesPolicyRequiredIssuer( policy ) ); 
                writer.Write( HasCardBeenUsedBefore( policy.Recipient.GetIdentifier(), storeConnection ) );
                writer.Write( HaveRequestedClaimsChanged( policy, storeConnection ) );
                writer.Write( WillSendAppliesToInRst( policy ) );
                writer.Write( DoesCardSupportAnyOptionalClaims( policy ) ); 
                writer.Write( DoesCardMatchNonClaimPolicyRequirements( policy ) );
 
            } 
            else
            { 
                writer.Write( false );
                writer.Write( false );
                writer.Write( false );
                writer.Write( false ); 
                writer.Write( false );
                writer.Write( false ); 
                writer.Write( false ); 
            }
 
            writer.Flush();

        }
 
        //
        // Summary: 
        // Copy the metadata of a card to another card 
        //
        // Parameters: 
        // card - card from from which data should be copied
        //
        public void CopyMetaData( InfoCard card )
        { 
            this.m_salt = new byte[ card.HashSalt.Length ];
            Array.Copy( card.HashSalt, 0, this.m_salt, 0, card.HashSalt.Length ); 
 
            this.m_pinHash = new byte[ card.m_pinHash.Length ];
            Array.Copy( card.m_pinHash, 0, this.m_pinHash, 0, card.m_pinHash.Length ); 
        }

        //
        // Summary: 
        // Return true if this card can support any of the optional claims in the policy
        // 
        // Parameters: 
        // policy - Pointer to the incoming policy.
        // 
        bool DoesCardSupportAnyOptionalClaims( InfoCardPolicy policy )
        {
            List optionalClaims = new List( policy.OptionalClaims );
 
            foreach( string s in this.GetClaims().Keys )
            { 
                if( optionalClaims.Contains( s ) ) 
                {
                    return true; 
                }
            }
            return false;
 

        } 
        // 
        // Summary:
        // Return true if appliesTo is to be sent in the RST 
        //
        // Parameters:
        // policy - Pointer to the incoming policy.
        // 
        bool WillSendAppliesToInRst( InfoCardPolicy policy )
        { 
            AppliesToBehaviorDecision decision = AppliesToBehaviorDecisionTable.GetAppliesToBehaviorDecisionForPolicyMatch( policy, this.RequireAppliesto ); 
            if( AppliesToBehaviorDecision.SendCustomAppliesTo == decision
                || AppliesToBehaviorDecision.SendRPAppliesTo == decision ) 
            {
                return true;
            }
            else 
            {
                return false; 
            } 
        }
 


        //
        // Summary 
        // Populates the instance members from a binary stream of serialized data.
        // 
        // Remarks 
        // This method will be used to support the construction of an instance of
        // an InfoCard class after marshalling from the database or from the UI Agent. 
        // All members are serialized using fixed length (or counted) types in little-endian format (e.g. Int64).
        // Strings are serialized using a counted array of unicode characters.
        //
        // Parameters 
        // stream - binary stream conforming to the serialization format supported by this class.
        // 
        // 
        // Notes
        // Making this private. Use constructor instead of calling this directly. 
        //
        private void Deserialize( System.IO.Stream stream )
        {
            // 
            // Populate each member from the stream
            // 
            BinaryReader reader = new InfoCardBinaryReader( stream, Encoding.Unicode ); 
            //
            // Check the version 
            //
            if( InfoCard.Version != reader.ReadByte() )
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.ServiceCardWrongVersion ) ); 
            }
 
            m_expiresOn = DateTime.FromFileTimeUtc( (long)reader.ReadInt64() ); 
            m_epoch = reader.ReadUInt32();
            m_id = new System.Uri( Utility.DeserializeString( reader ) ); 
            m_issuedOn = DateTime.FromFileTimeUtc( (long)reader.ReadInt64() );

            m_isImported = reader.ReadBoolean();
            m_installedOn = DateTime.FromFileTimeUtc( (long)reader.ReadInt64() ); 

            m_isSelfIssued = reader.ReadBoolean(); 
            m_issuer = Utility.DeserializeUri( reader ); 
            m_issuerName = Utility.DeserializeString( reader );
 
            int keyLen = reader.ReadInt32();
            m_issuerIdentifierAsBytes = reader.ReadBytes( keyLen );

            m_language = Utility.DeserializeString( reader ); 

            int logoLen = reader.ReadInt32(); 
            IDT.Assert( 0 <= logoLen && logoLen < Constants.Maxima.LogoLength, "logo length out of range {0}", logoLen ); 
            m_logo = reader.ReadBytes( logoLen );
 
            m_mimeType = Utility.DeserializeString( reader );
            m_name = Utility.DeserializeString( reader );
            m_lastUpdate = DateTime.FromFileTimeUtc( (long)reader.ReadInt64() );
            m_backgroundColor = reader.ReadInt32(); 
            m_requireAppliesTo = (RequireAppliesToStatus)reader.ReadByte();
            m_privacyPolicyLink = Utility.DeserializeString( reader ); 
            m_privacyPolicyVersion = reader.ReadUInt32(); 

            int hashLen = reader.ReadInt32(); 
            IDT.Assert( 0 <= hashLen && hashLen < Constants.Maxima.PinHashLength, "pin hash out fo range {0}", hashLen );
            m_pinHash = reader.ReadBytes( hashLen );

            int saltLen = reader.ReadInt32(); 
            IDT.Assert( 0 <= saltLen && saltLen < Constants.Maxima.SaltLength, "salt length out of range {0}", saltLen );
            m_salt = reader.ReadBytes( saltLen ); 
 
            Int32 tokenTypeCount = reader.ReadInt32();
            IDT.Assert( Constants.Maxima.TokenTypes > tokenTypeCount, "too many token types" ); 
            m_tokenTypes = new String[ tokenTypeCount ];
            for( int i = 0; i < tokenTypeCount; i++ )
            {
                m_tokenTypes[ i ] = Utility.DeserializeString( reader ); 
            }
 
            Int32 creationParamCount = reader.ReadInt32(); 
            IDT.Assert( 0 <= creationParamCount && creationParamCount < Constants.Maxima.CreationParameters, "creation parametes out of range {0}", creationParamCount );
 
            for( int i = 0; i < creationParamCount; i++ )
            {
                TokenCreationParameter parameter = new TokenCreationParameter();
                parameter.Deserialize( reader ); 
                CreationParameters.Add( parameter );
            } 
 
            m_pin = Utility.DeserializeString( reader );
            m_oldPin = Utility.DeserializeString( reader ); 
            m_pinAction = (PinAction)reader.ReadByte();


            // 
            // Validate the end of the buffer
            // 
            if( Marker != reader.ReadByte() ) 
            {
                IDT.Assert( false, "malformed stream detected" ); 
            }

            //
            // Just a correctness check 
            //
            ThrowIfNotComplete(); 
        } 

 
        //
        // Summary
        // This function is invoked by the RemoteTokenFactory (before RST to IP/STS)
        // to figure out which claims we'll request from the IP/STS 
        //
        // Arguments 
        //  policy           - the incoming recipient policy 
        //  discloseOptional - Specifies whether optional claims are to be disclosed.
        // 
        public Dictionary GetClaimsToBeDisclosed( InfoCardPolicy policy, bool discloseOptional )
        {
            Dictionary claimsToBeDisclosed =
                new Dictionary( policy.RequiredClaims.Length ); 

            for( int i = 0; i < policy.RequiredClaims.Length; i++ ) 
            { 
                claimsToBeDisclosed.Add( policy.RequiredClaims[ i ], false );
            } 

            //
            // Only disclose optional claims if user has chosen to disclose optional claims.
            // 
            if( discloseOptional )
            { 
                for( int i = 0; i < policy.OptionalClaims.Length; i++ ) 
                {
                    // 
                    // If optional claim in policy present in card, that means we'll send to the IP/STS
                    // Therefore, such a claim is also a disclosed claim
                    //
                    string optUri = policy.OptionalClaims[ i ]; 
                    if( this.GetClaims().ContainsKey( optUri ) )
                    { 
                        // 
                        // Track optional claim by passing in true as 2nd arg
                        // 
                        claimsToBeDisclosed.Add( policy.OptionalClaims[ i ], true );
                    }
                }
            } 

            return claimsToBeDisclosed; 
        } 

 
        //
        // Summary
        //  Find if the card matches a given policy
        // 
        // Parameters
        //   policy - Policy of the RP 
        // 
        // Return
        //  True if card matches the policy requirements, false otherwise. 
        //
        public bool DoesCardMatchPolicySet( InfoCardPolicy policy )
        {
            IDT.TraceDebug( " Matching card {0} for token policy requirements", m_name ); 
            IDT.Assert( null != policy, "null policy" );
            bool hasRequiredClaims = true; 
 
            List supportedClaims = new List( this.SupportedClaimTypes );
 
            if ( null != policy.RequiredClaims )
            {
                foreach ( string policyClaim in policy.RequiredClaims )
                { 
                    //
                    // If a required claim is not found in the claims supported by the card 
                    // set the card as not matching requirements 
                    //
                    if ( !supportedClaims.Contains( policyClaim ) ) 
                    {
                        //
                        // For self issued cards, do not include PPID claim as a search criteria
                        // This is because the PPID claim is not stored as a part of the infocard claims 
                        // list, but it is generated on demand by the local STS.
                        // 
                        if ( !(IsSelfIssued && InfoCardConstants.PPIDClaimsUri == policyClaim) ) 
                        {
                            hasRequiredClaims = false; 
                            break;
                        }
                    }
                } 
            }
            return ( hasRequiredClaims && DoesCardMatchNonClaimPolicyRequirements( policy ) ); 
        } 

 

        //
        // Summary
        //  Find if the given card matches a given policy, except for the claims requirement 
        //
        // Parameters 
        //   policy - Policy of the RP 
        //
        // Return 
        //  True if card matches the policy requirements other than claim requirements, false otherwise
        //
        public bool DoesCardMatchNonClaimPolicyRequirements( InfoCardPolicy policy )
        { 
            IDT.Assert( null != policy, "null policy" );
 
            // 
            // For a managed card if RP specifies AppliesTo and the card
            // does not specify RequireAppliesTo then the card does not match 
            //
            bool appliesTocheck = true;
            if( !this.IsSelfIssued
                && AppliesToBehaviorDecision.FailMatch == AppliesToBehaviorDecisionTable.GetAppliesToBehaviorDecisionForPolicyMatch( policy, this.RequireAppliesto ) ) 
            {
                appliesTocheck = false; 
            } 

            bool meetsIdentityRequirement = true; 
            if( GetRPIdentityRequirement().StrongIdentityRequired && !(policy.ImmediateTokenRecipient is X509RecipientIdentity) )
            {
                 meetsIdentityRequirement = false;
            } 

            // 
            // Self issued cards should not match policy if a managed card is required 
            //
            return ( !( IsSelfIssued && policy.RequiresManagedCard ) 
                     && CardMatchesPolicyTokenType( policy )
                     && CardMatchesPolicyRequiredIssuer( policy )
                     && appliesTocheck
                     && meetsIdentityRequirement ); 

 
        } 

 
        //
        // Summary
        //  Find if the requires claims are a subset of the claims last
        //  disclosed by the user. 
        //
        // Parameters 
        //   policy - Policy of the RP 
        //   connection - the store connection
        // 
        // Return
        //  True if the set of requested claims has changed and false otherwise
        //
        public bool HaveRequestedClaimsChanged( InfoCardPolicy policy, StoreConnection connection ) 
        {
            IDT.TraceDebug( "NeedApprovalForRequiredClaims: CardName={0}", m_name ); 
 
            IDT.Assert( null != m_id, "Null id" );
            IDT.Assert( null != policy, "null policy" ); 
            IDT.Assert( null != connection, "null connection" );

            LedgerEntry le = TryGetLedgerEntry( connection, policy.Recipient.GetIdentifier() );
 
            if( null == le )
            { 
                IDT.TraceDebug( "Claims have changed: no ledger entry. CardName={0}", m_name ); 
                return true;
            } 

            IList disclosedClaims = le.DisclosedClaims ?? new string[ 0 ];

            int count = 0; 
            if( null != policy.RequiredClaims )
            { 
                count = policy.RequiredClaims.Length; 
            }
 
            //
            // If |requiredClaims| > |disclosedClaims|, it's clearly not a subset.
            //
            if( count > disclosedClaims.Count ) 
            {
                IDT.TraceDebug( "Claims have changed: more required claims. CardName={0}", m_name ); 
                return true; 
            }
 
            //
            // Otherwise, each required claim must appear in disclosedClaims.
            //
            bool found = true; 
            foreach( string claim in policy.RequiredClaims )
            { 
                if( !disclosedClaims.Contains( claim ) ) 
                {
                    IDT.TraceDebug( "Claims have changed: new required claim. CardName={0} ClaimName={1}", m_name, claim ); 
                    found = false;
                    break;
                }
            } 

            if( found ) 
            { 
                IDT.TraceDebug( "Claims have not changed. CardName={0}", m_name );
            } 

            return !found;
        }
 
        //
        // Summary 
        //  Find if the card matches a the token type requirements of the IP 
        //
        // Parameters 
        //   policy - Policy of the RP
        //   connection - the store connection
        //
        // Return 
        //  True if card matches the policy requirements, false otherwise
        // 
        private bool CardMatchesPolicyTokenType( InfoCardPolicy policy ) 
        {
            // 
            // Check if card matches the token type requirement
            //
            IDT.TraceDebug( "Check if card matches token type requirement of policy" );
 
            if( String.IsNullOrEmpty( policy.OptionalRstParams.TokenType ) )
            { 
                IDT.TraceDebug( "No token type specified in policy" ); 
                return true;
            } 
            else
            {
                foreach( String type in m_tokenTypes )
                { 

                    if( type == policy.OptionalRstParams.TokenType ) 
                    { 
                        IDT.TraceDebug( " Type  in card {0} matches type {1} in policy ", type, policy.OptionalRstParams.TokenType );
                        return true; 
                    }
                    IDT.TraceDebug( " Type in card {0} does not match type {1} in policy ", type, policy.OptionalRstParams.TokenType );
                }
            } 
            return false;
 
        } 

 

        //
        // Summary
        //  Find if the card is issued by the issuer required by the RP 
        //
        // Parameters 
        //   policy - Policy of the RP 
        //
        // Return 
        //  True if card matches the policy requirements, false otherwise
        //
        private bool CardMatchesPolicyRequiredIssuer( InfoCardPolicy policy )
        { 
            //
            // Check if the card is issued by the issuer requested by the RP 
            // 
            if( null == policy.Issuer || null == policy.Issuer.Uri ||
                Utility.CompareUri( policy.Issuer.Uri, XmlNames.WSIdentity.AnonymousIssuerUriValue ) ) 
            {
                IDT.TraceDebug( " Card matches null or anonymous issuer policy. Name={0} ", m_name );
                return true;
            } 

            if( m_isSelfIssued && Utility.CompareUri( policy.Issuer.Uri, XmlNames.WSIdentity.SelfIssuerUriValue ) ) 
            { 
                IDT.TraceDebug( " Card matches self-issuer policy. Name={0} ", m_name );
                return true; 
            }

            if( !m_isSelfIssued && Utility.CompareUri( policy.Issuer.Uri, m_issuer ) )
            { 
                IDT.TraceDebug( " Card matches explicit issuer policy. Name={0}; Issuer={1} ", m_name, m_issuer );
                return true; 
            } 
            return false;
 
        }

        //
        // Summary 
        //  Find if the card has been used before with this recipient
        // 
        // Parameters 
        //   recipientId - RecipientId of the RP's cert.
        //   connection - the store connection 
        //
        // Return
        //  True if card has been used before, false otherwise
        // 
        public bool HasCardBeenUsedBefore( string recipientId, StoreConnection connection )
        { 
            return null != connection.GetSingleRow( 
                        QueryDetails.Identifiers,
                        new QueryParameter( SecondaryIndexDefinition.ObjectTypeIndex, 
                                           (Int32)StorableObjectType.LedgerEntry ),
                        new QueryParameter( SecondaryIndexDefinition.RecipientIdIndex,
                                            recipientId ),
                        new QueryParameter( SecondaryIndexDefinition.ParentIdIndex, 
                                            GlobalId.DeriveFrom( m_id.ToString() ) ) );
        } 
 

        // 
        // Summary
        // Retrieves an InfoCard from the store using the specified connection.
        //
        // Remarks 
        // The m_id must be populated for this call to work.
        // The m_rowId is cached as part of this call allowing 
        // subsequent database calls to be more efficient. 
        // The InfoCard will be retrieved from the roaming portion of the store.
        // 
        // Parameters
        // con - The connection to the InfoCard store to be used for the query.
        //
        public void Get( StoreConnection con ) 
        {
            IDT.Assert( null != m_id, "null id" ); 
            IDT.Assert( null != con, "null connection" ); 

            // 
            // Cache the connection to enable lazy retrieval of the ledger and claims
            //
            m_storeConnection = con;
 
            //
            // Retrieve the row for the object from the database 
            // 
            DataRow row = GetRow( con, QueryDetails.FullRow );
 
            //
            // Populate the infocard using the byte array
            //
            Deserialize( new MemoryStream( row.GetDataField() ) ); 

            // 
            // Update the row id from the database 
            //
            m_rowId = row.LocalId; 

        }

        // 
        // Summary
        // Updates or inserts the InfoCard instance into the roaming portion of the store using 
        // the specified connection. 
        //
        // Remarks 
        // The object must be complete for this operation to succeed.
        // The store global Id will be a hash of the URI of the card.
        //
        // Parameters 
        // con - The connection to the InfoCard store to be used for the query.
        // 
        public void Save( StoreConnection con ) 
        {
            ThrowIfNotComplete(); 
            IDT.Assert( null != con, "null connection" );


            IDT.TraceDebug( "CARD: Saving..." ); 
            IDT.TraceDebug( "CARD: {0}", this.ToString() );
 
            // 
            // Try and get the database header information to
            // see if this is an insert or update. 
            //
            // Note: The datafield is not part of the projection
            // in order to avoid unecessary decryption.
            // 
            DataRow row = TryGetRow( con, QueryDetails.FullHeader );
 
            bool masterKeyChanged = false; 

            if( null == row ) 
            {
                //
                // If this is a new card create a new master key
                // For an imported card from a store, the master key will already be present 
                //
                if( null == m_masterKey ) 
                { 
                    m_masterKey = InfoCardMasterKey.NewMasterKey( m_id );
                } 
                masterKeyChanged = true;
                row = new DataRow();
                row.ObjectType = (Int32)StorableObjectType.InfoCard;
                row.GlobalId = GlobalId.DeriveFrom( m_id.ToString() ); 
            }
 
 
            InfoCardClaimCollection plainTextClaims = null;
 

            switch( m_pinAction )
            {
                case PinAction.NoPin: 
                    {
                        // 
                        // No pin protection necessary: no action 
                        //
                        break; 
                    }
                case PinAction.PinSame:
                    {
                        // 
                        // A pin protected card has been saved, but the
                        // pin has not been changed. So simply encrypt the 
                        // claims with the key generated using the specified pin 
                        // and the key info from the master key in the store.
                        // 

                        //
                        // Save the unencrypted claims so we can return
                        // the object unencrypted 
                        //
                        plainTextClaims = m_claims.Clone(); 
 
                        GetMasterKey( con );
                        m_claims.Encrypt( m_masterKey.GetPinHelper( m_pin ) ); 
                        break;
                    }
                case PinAction.PinAdded:
                    { 
                        //
                        // New pin needs to be applied: 
                        // Generate a new key using the specified PIN 
                        // Encrypt the master key
                        // Encrypt the claims 
                        // Store the keyinfo and encrypted master key in the store.
                        // Store the encrypted claims in the store.
                        //
 
                        //
                        // Save the unencrypted claims so we can return 
                        // the object unencrypted 
                        //
                        plainTextClaims = m_claims.Clone(); 

                        GetMasterKey( con );
                        PinProtectionHelper pinHelper = new PinProtectionHelper( m_pin );
                        m_masterKey.Encrypt( pinHelper ); 
                        m_claims.Encrypt( pinHelper );
                        masterKeyChanged = true; 
                        break; 
                    }
                case PinAction.PinRemoved: 
                    {
                        //
                        // Pin needs to be removed:
                        // Decrypt the master key with the pin and 
                        // params from the stored master key
                        // Store the master key in the store 
                        // Store the claims in plain text 
                        //
                        GetMasterKey( con ); 
                        m_masterKey.Decrypt( m_masterKey.GetPinHelper( m_oldPin ) );
                        masterKeyChanged = true;
                        break;
                    } 
                case PinAction.PinChanged:
                    { 
                        // 
                        // A pin protected card had it's pin changed
                        // So decrypt the master key and then encrypt it and 
                        // the claims with the new pin
                        // Store the key info with the encrypted master key
                        // Store the encrypted claims
                        // 

                        // 
                        // Save the unencrypted claims so we can return 
                        // them unencrypted
                        // 
                        plainTextClaims = m_claims.Clone();

                        GetMasterKey( con );
                        m_masterKey.Decrypt( m_masterKey.GetPinHelper( m_oldPin ) ); 
                        PinProtectionHelper pinHelper = new PinProtectionHelper( m_pin );
                        m_masterKey.Encrypt( pinHelper ); 
                        m_claims.Encrypt( pinHelper ); 
                        masterKeyChanged = true;
                        break; 
                    }
                default:
                    break;
            } 

            if( masterKeyChanged ) 
            { 
                //
                // The master key was modified so save the changes 
                // to the store.
                //
                m_masterKey.Save( con );
            } 

            // 
            // Update the pin action to the appropriate value so that 
            // the agent has the proper default.
            // 
            m_pinAction = IsPinProtected ? PinAction.PinSame : PinAction.NoPin;

            //
            // Populate the index fields 
            //
            string[ ] issuer; 
            if( IsSelfIssued ) 
            {
                issuer = new String[ ] { XmlNames.WSIdentity.SelfIssuerUri }; 
            }
            else
            {
                // 
                // Calculate the array of  tuples
                // 
                issuer = new string[ CreationParameters.Count ]; 
                int i = 0;
                foreach( TokenCreationParameter param in CreationParameters ) 
                {
                    issuer[ i++ ] = param.Epr.Uri.ToString();
                }
            } 

            row.SetIndexValue( SecondaryIndexDefinition.ProductionServiceIndex, issuer ); 
 
            IDT.Assert( null != m_claims, "Must already be initialized at this point" );
 
            row.SetIndexValue( SecondaryIndexDefinition.SupportedClaimIndex, SupportedClaimTypes );

            if( CreationParameters.Count > 0 )
            { 
                object[ ] auth = new object[ CreationParameters.Count ];
                int i = 0; 
                foreach( TokenCreationParameter param in CreationParameters ) 
                {
                    auth[ i++ ] = (Int32)param.CredentialType; 
                }
                row.SetIndexValue( SecondaryIndexDefinition.SupportedAuthIndex, auth );
            }
 
            //
            // Populate the data object 
            // 
            MemoryStream ms = new MemoryStream();
            Serialize( ms ); 
            row.SetDataField( ms.ToArray() );

            //
            // Save the InfoCard row to the database 
            //
            con.Save( row ); 
 
            //
            // Update the row id in the object in case 
            // this was an insert.
            //
            m_rowId = row.LocalId;
 
            //
            // Save the extended card information in case it exists 
            // 
            if( null != m_extendedInformation )
            { 
                m_extendedInformation.Save( con );
            }

            // 
            // Write the claims collection row to the store
            // 
            m_claims.Save( con, m_isSelfIssued ); 

            // 
            // Restore the claims back to the plain text version
            // if necessary
            //
            if( null != plainTextClaims ) 
            {
                m_claims = plainTextClaims; 
            } 

            GetRPIdentityRequirement().Save( con ); 
        }


        // 
        // Summary
        // Creates a string containing the state of the InfoCard. 
        // 
        // Remarks
        // Members with a byte[] type are omitted. 
        //
        // Returns
        // string   - Multiline string with InfoCard state information.
        // 
        public override string ToString()
        { 
#if DEBUG 
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat( "Dumping InfoCard({0})\n", m_name ); 
            sb.AppendFormat( "Expires On:\t{0}\n", m_expiresOn.ToString() );
            sb.AppendFormat( "Epoch:\t\t{0}\n", m_epoch );
            sb.AppendFormat( "Id:\t\t{0}\n", m_id.ToString() );
            sb.AppendFormat( "Issued On:\t{0}\n", m_issuedOn.ToString() ); 
            sb.AppendFormat( "Issuer Key:\t{0}\n", "Omitted not implemented" );
            sb.AppendFormat( "Issuer Name:\t{0}\n", m_issuerName ); 
            sb.AppendFormat( "Key:\t\t{0}\n", "Omitted not implemented" ); 
            sb.AppendFormat( "Language:\t{0}\n", m_language );
            sb.AppendFormat( "Logo:\t\t{0}\n", "Omitted not implemented" ); 
            sb.AppendFormat( "Logo MimeType:\t{0}\n", m_mimeType );
            sb.AppendFormat( "Name:\t\t{0}\n", m_name );
            sb.AppendFormat( "Last Update:\t{0}\n", m_lastUpdate.ToString() );
            sb.AppendFormat( "BackGround Color:\t{0}\n", m_backgroundColor.ToString( CultureInfo.InvariantCulture ) ); 
            sb.AppendFormat( "RequireAppliesTo:\t{0}\n", m_requireAppliesTo.ToString() );
            sb.AppendFormat( "PrivacyNotice:\t{0}\n", m_privacyPolicyLink ); 
            sb.AppendFormat( "PrivacyNoticeVersion:\t{0}\n", m_privacyPolicyVersion ); 

            return sb.ToString(); 
#else
            return base.ToString();
#endif
        } 

 
        // 
        // Summary
        // Create a new card. 
        //
        // Remarks
        // This method will be called by the UI to create a new card. The information
        // that is not filled in, is supposed to be completed within the UI. 
        //
        public static InfoCard NewCard( CultureInfo userCulture ) 
        { 

            InfoCard card = new InfoCard(); 
            card.m_expiresOn = DateTime.MaxValue;
            card.m_epoch = 1;
            card.m_id = new Uri( "urn:uuid:" + Guid.NewGuid().ToString() );
            card.m_issuedOn = DateTime.UtcNow; 
            card.m_isImported = false;
            card.m_installedOn = DateTime.UtcNow; 
            card.m_isSelfIssued = true; 
            card.m_issuerName = SR.GetString( SR.SelfIssuedIssuerName );
            card.m_issuer = XmlNames.WSIdentity.SelfIssuerUriValue; 
            card.m_language = userCulture.TwoLetterISOLanguageName;
            card.m_logo = new byte[ 0 ];
            card.m_name = null;
            card.m_lastUpdate = DateTime.UtcNow; 
            card.m_backgroundColor = 0x00FFFFFF;
            card.m_requireAppliesTo = RequireAppliesToStatus.NotPresent; 
            card.m_salt = InfoCard.GenerateSalt(); 

            card.m_tokenTypes = new String[ ]{ XmlNames.Saml11.Namespace, 
                                               XmlNames.Saml11.AltNamespace };

            CultureInfo backup = System.Threading.Thread.CurrentThread.CurrentUICulture;
 
            //
            // Change the culture before reading the claim strings 
            // 
            try
            { 
                System.Threading.Thread.CurrentThread.CurrentUICulture = userCulture;

                for( int i = 0; i < InfoCardConstants.SelfIssuedClaimsUris.Length; i++ )
                { 
                    InfoCardClaim claim = new InfoCardClaim(
                        InfoCardConstants.SelfIssuedClaimsUris[ i ], 
                        null, 
                        InfoCardConstants.ClaimsDescription( InfoCardConstants.SelfIssuedClaimsUris[ i ] ),
                        InfoCardConstants.ClaimDisplayTag( InfoCardConstants.SelfIssuedClaimsUris[ i ] ) ); 
                    card.AddClaim( claim );
                }
            }
            finally 
            {
                System.Threading.Thread.CurrentThread.CurrentUICulture = backup; 
            } 

            IDT.TraceDebug( "CARD: InfoCard created. Follows:\n{0}", card ); 

            IDT.Assert( null == card.m_masterKey, "Card key is only populated during save" );

            return card; 
        }
 
 

        // 
        // Summary
        // Attempts to retrieve the specified row information from the store
        // using the specified connection.
        // 
        // Remarks
        // The m_id field must be populated for this method to succeed. 
        // 
        // Parameters
        // con      - The connection to the InfoCard store to be used for the query. 
        // details  - Identifies the projection (think columns) of data to be returned.
        //            Since the data field must be decrypted before returning avoid projecting it if possible.
        //
        // Returns 
        // Will always return a row. If a row is not found an exception will be thrown.
        // 
        protected DataRow GetRow( StoreConnection con, QueryDetails details ) 
        {
            IDT.Assert( null != con, " null connection" ); 

            DataRow row = TryGetRow( con, details );

            // 
            // Verify that an infocard row was returned
            // 
            IDT.Assert( null != row, "null row" ); 
            IDT.Assert( (Int32)StorableObjectType.InfoCard == row.ObjectType,
                        "Attempt to deserialize an incorrect object type {0}", 
                        row.ObjectType );

            return row;
        } 

        // 
        // Summary 
        // Attempts to retrieve the specified row information from the store
        // using the specified connection. 
        //
        // Remarks
        // The m_id field must be populated for this method to succeed.
        // Called by GetRow() 
        //
        // Parameters 
        // con      - The connection to the InfoCard store to be used for the query. 
        // details  - Identifies the projection (think columns) of data to be returned.
        //            Since the data field must be decrypted before returning avoid projecting it if possible. 
        //
        // Returns
        // Will return null if the row associated with the m_id is not found.
        // 
        protected DataRow TryGetRow( StoreConnection con, QueryDetails details )
        { 
            IDT.Assert( null != m_id, "null id" ); 
            IDT.Assert( null != con, "null connection" );
 
            //
            // Retrieve a single object from the database.
            //
            DataRow row = con.GetSingleRow( 
                                    details,
                                    new QueryParameter( SecondaryIndexDefinition.GlobalIdIndex, 
                                                        GlobalId.DeriveFrom( m_id.ToString() ) ) ); 

            return row; 
        }

        //
        // Summary 
        //  Read the infocard from the xml. The reader should be either at the
        //  InfoCard element or the RoamingInfoCard element. 
        // 
        // Parameters
        //   reader - The XmlReader to read data from 
        //
        public void ReadXml( XmlReader reader )
        {
 
            if( XmlNames.WSIdentity.RoamingInfoCardElement == reader.LocalName )
            { 
                ReadRoamingInfoCard( reader ); 
            }
            else if( XmlNames.WSIdentity.InfoCardElement == reader.LocalName ) 
            {
                ReadImportedInfoCard( reader );
            }
            else 
            {
                IDT.Assert( false, "Invalid element found. Did schema validation fail? Found {0}", reader.LocalName ); 
            } 

        } 

        public XmlSchema GetSchema()
        {
            return null; 
        }
 
        // 
        // Summary
        //  Write the infocard to xml. 
        //
        // Parameters
        //   writer - The XmlWriter to write the data to
        // 
        public void WriteXml( XmlWriter writer )
        { 
            ThrowIfNotComplete(); 

            writer.WriteStartElement( XmlNames.WSIdentity.RoamingInfoCardElement, XmlNames.WSIdentity.Namespace ); 


            writer.WriteStartElement( XmlNames.WSIdentity.InfoCardMetaDataElement, XmlNames.WSIdentity.Namespace );
            writer.WriteAttributeString( XmlNames.Xml.Language, XmlNames.Xml.Namespace, m_language ); 

            // 
            // infocard reference - card id and version 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.InfoCardRefElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteStartElement( XmlNames.WSIdentity.CardIdElement, XmlNames.WSIdentity.Namespace );
            writer.WriteString( m_id.AbsoluteUri );
            writer.WriteEndElement();
            writer.WriteStartElement( XmlNames.WSIdentity.CardVersionElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteString( m_epoch.ToString( CultureInfo.InvariantCulture ) );
            writer.WriteEndElement(); 
            writer.WriteEndElement(); 

            // 
            // card name
            //
            if( !String.IsNullOrEmpty( m_name ) )
            { 
                writer.WriteStartElement( XmlNames.WSIdentity.CardNameElement, XmlNames.WSIdentity.Namespace );
                writer.WriteString( m_name ); 
                writer.WriteEndElement(); 
            }
 

            //
            // card image
            // 
            if( null != m_logo && 0 != m_logo.Length )
            { 
                writer.WriteStartElement( XmlNames.WSIdentity.CardImageElement, XmlNames.WSIdentity.Namespace ); 
                if( !String.IsNullOrEmpty( m_mimeType ) )
                { 
                    writer.WriteAttributeString( XmlNames.WSIdentity.MimeTypeAttribute, m_mimeType );
                }
                string val = Convert.ToBase64String( m_logo );
                writer.WriteString( val ); 
                writer.WriteEndElement();
            } 
 
            //
            // card issuer id 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.IssuerElement, XmlNames.WSIdentity.Namespace );
            if( null != m_issuer )
            { 
                writer.WriteString( m_issuer.AbsoluteUri );
            } 
            writer.WriteEndElement(); 

 
            //
            // issue time
            //
            writer.WriteStartElement( XmlNames.WSIdentity.TimeIssuedElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteString( XmlConvert.ToString( m_issuedOn, XmlDateTimeSerializationMode.Utc ) );
            writer.WriteEndElement(); 
 
            //
            // expiry time 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.TimeExpiresElement, XmlNames.WSIdentity.Namespace );
            writer.WriteString( XmlConvert.ToString( m_expiresOn, XmlDateTimeSerializationMode.Utc ) );
            writer.WriteEndElement(); 

            // 
            // authentication info 
            //
            if( null != m_creationParameters ) 
            {
                writer.WriteStartElement( XmlNames.WSIdentity.TokenServiceListElement, XmlNames.WSIdentity.Namespace );

                foreach( TokenCreationParameter param in m_creationParameters ) 
                {
                    param.WriteXml( writer ); 
                } 

                writer.WriteEndElement(); 

            }

 
            //
            // tokentypes 
            // 
            writer.WriteStartElement( XmlNames.WSIdentity.SupportedTokenTypeListElement, XmlNames.WSIdentity.Namespace );
            foreach( string type in m_tokenTypes ) 
            {
                writer.WriteElementString( XmlNames.WSTrustXmlSoap2005.c_TokenType,
                                           XmlNames.WSTrustXmlSoap2005.c_Namespace,
                                           type ); 
            }
            writer.WriteEndElement(); 
 
            //
            // claims 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.SupportedClaimTypeListElement, XmlNames.WSIdentity.Namespace );

            foreach( string clmId in GetClaims().Keys ) 
            {
                InfoCardClaim claim = GetClaims()[ clmId ]; 
 
                //
                // For self-issued cards the private personal identifier 
                // claim must not be written to the roaming store file.
                //
                if( m_isSelfIssued && Utility.CompareUri( claim.Id, InfoCardConstants.PPIDClaimsUri ) )
                { 
                    continue;
                } 
 
                writer.WriteStartElement( XmlNames.WSIdentity.SupportedClaimTypeElement, XmlNames.WSIdentity.Namespace );
                writer.WriteAttributeString( XmlNames.WSIdentity.UriAttribute, claim.Id ); 

                if( !String.IsNullOrEmpty( claim.DisplayTag ) )
                {
                    writer.WriteElementString( XmlNames.WSIdentity.DisplayTagElement, 
                                                   XmlNames.WSIdentity.Namespace,
                                                   claim.DisplayTag ); 
                } 

                if( !String.IsNullOrEmpty( claim.Description ) ) 
                {
                    writer.WriteElementString( XmlNames.WSIdentity.DescriptionElement,
                                               XmlNames.WSIdentity.Namespace,
                                               claim.Description ); 
                }
 
                writer.WriteEndElement(); 
            }
 
            writer.WriteEndElement();

            //
            // RequireAppliesTo 
            //
            if( RequireAppliesToStatus.NotPresent != m_requireAppliesTo ) 
            { 
                writer.WriteStartElement( XmlNames.WSIdentity.RequireAppliesToElement, XmlNames.WSIdentity.Namespace );
                if( RequireAppliesToStatus.Optional == m_requireAppliesTo ) 
                {
                    writer.WriteAttributeString( XmlNames.WSIdentity.OptionalAttribute, "true" );
                }
                writer.WriteEndElement(); 
            }
 
            // 
            // privacy notice
            // 
            if( !String.IsNullOrEmpty( m_privacyPolicyLink ) )
            {
                writer.WriteStartElement( XmlNames.WSIdentity.PrivacyNoticeAtElement, XmlNames.WSIdentity.Namespace );
                if( 0 < m_privacyPolicyVersion ) 
                {
                    writer.WriteAttributeString( XmlNames.WSIdentity.PrivacyNoticeVersionAttribute, m_privacyPolicyVersion.ToString( CultureInfo.InvariantCulture ) ); 
                } 
                writer.WriteString( m_privacyPolicyLink );
                writer.WriteEndElement(); 
            }

            if( GetRPIdentityRequirement().StrongIdentityRequired )
            { 
                writer.WriteStartElement( XmlNames.WSIdentity07.RequireStrongRPIdentity, XmlNames.WSIdentity07.Namespace );
                writer.WriteEndElement(); 
            } 

            // 
            // Issuer information
            //
            if( null != GetExtendedInformation() )
            { 
                foreach( InfocardExtendedInformationEntry entry in m_extendedInformation )
                { 
                    entry.WriteXml( writer ); 
                }
            } 

            //
            // card type
            // 
            writer.WriteStartElement( XmlNames.WSIdentity.IsSelfIssuedElement, XmlNames.WSIdentity.Namespace );
            writer.WriteString( XmlConvert.ToString( m_isSelfIssued ) ); 
            writer.WriteEndElement(); 

 
            //
            // card pin
            //
            if( !Utility.ArrayIsNullOrEmpty( m_pinHash ) ) 
            {
                writer.WriteStartElement( XmlNames.WSIdentity.PinDigestElement, XmlNames.WSIdentity.Namespace ); 
                writer.WriteString( Convert.ToBase64String( m_pinHash ) ); 
                writer.WriteEndElement();
            } 


            //
            // card salt 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.HashSaltElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteString( Convert.ToBase64String( m_salt ) ); 
            writer.WriteEndElement();
 
            //
            // update time
            //
            writer.WriteStartElement( XmlNames.WSIdentity.TimeLastUpdatedElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteString( XmlConvert.ToString( m_lastUpdate, XmlDateTimeSerializationMode.Utc ) );
            writer.WriteEndElement(); 
 
            //
            // issuer key 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.IssuerIdElement, XmlNames.WSIdentity.Namespace );
            if( null != m_issuerIdentifierAsBytes )
            { 
                writer.WriteString( Convert.ToBase64String( m_issuerIdentifierAsBytes, Base64FormattingOptions.None ) );
            } 
            writer.WriteEndElement(); 

            // 
            // card issuer name
            //
            writer.WriteStartElement( XmlNames.WSIdentity.IssuerNameElement, XmlNames.WSIdentity.Namespace );
            if( !String.IsNullOrEmpty( m_issuerName ) ) 
            {
                writer.WriteString( m_issuerName ); 
            } 
            writer.WriteEndElement();
 
            //
            // backgroundcolour
            //
            writer.WriteStartElement( XmlNames.WSIdentity.BackgroundColorElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteString( XmlConvert.ToString( m_backgroundColor ) );
            writer.WriteEndElement(); 
 
            //
            // end of InfoCardMetaData element 
            //
            writer.WriteEndElement();

 

            // 
            // Start writing the private data 
            //
            writer.WriteStartElement( XmlNames.WSIdentity.InfoCardPrivateDataElement, XmlNames.WSIdentity.Namespace ); 

            //
            // card key
            // 
            IDT.Assert( null != m_masterKey, "Masterkey Cannot be null when trying to export a card" );
            writer.WriteStartElement( XmlNames.WSIdentity.MasterKeyElement, XmlNames.WSIdentity.Namespace ); 
            writer.WriteString( Convert.ToBase64String( m_masterKey.Key ) ); 
            writer.WriteEndElement();
 
            if( IsSelfIssued )
            {
                writer.WriteStartElement( XmlNames.WSIdentity.ClaimValueListElement, XmlNames.WSIdentity.Namespace );
 
                foreach( string clmId in GetClaims().Keys )
                { 
                    InfoCardClaim claim = GetClaims()[ clmId ]; 

                    // 
                    // For self-issued cards the private personal identifier
                    // claim must not be written to the roaming store file.
                    //
                    if( Utility.CompareUri( claim.Id, InfoCardConstants.PPIDClaimsUri ) ) 
                    {
                        continue; 
                    } 

                    writer.WriteStartElement( XmlNames.WSIdentity.ClaimValueElement, XmlNames.WSIdentity.Namespace ); 
                    writer.WriteAttributeString( XmlNames.WSIdentity.UriAttribute, claim.Id );

                    if( !String.IsNullOrEmpty( claim.Value ) )
                    { 
                        writer.WriteElementString( XmlNames.WSIdentity.ValueElement,
                                                   XmlNames.WSIdentity.Namespace, 
                                                   claim.Value ); 
                    }
                    else 
                    {
                        writer.WriteElementString( XmlNames.WSIdentity.ValueElement,
                                                   XmlNames.WSIdentity.Namespace,
                                                   String.Empty ); 
                    }
 
                    writer.WriteEndElement(); 
                }
 
                writer.WriteEndElement();
            }

            // 
            // end of InfoCardPrivateData element
            // 
            writer.WriteEndElement(); 

            // 
            // end of Roaming Infocard element
            //
            writer.WriteEndElement();
        } 

 
        private void ReadImportedInfoCard( XmlReader reader ) 
        {
            IDT.Assert( null != reader, "null reader" ); 
            if( !reader.IsStartElement( XmlNames.WSIdentity.InfoCardElement, XmlNames.WSIdentity.Namespace ) )
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) );
            } 

            this.Language = reader.GetAttribute( XmlNames.Xml.Language, XmlNames.Xml.Namespace ); 
            if( String.IsNullOrEmpty( this.Language ) ) 
            {
                this.Language = reader.GetAttribute( XmlNames.Xml.Language ); 
            }

            reader.ReadStartElement();
 
            ReadBaseInfoCard( reader );
 
            // 
            // Do not allow self issued uri as a managed IP address
            // 
            if( !IsSelfIssued )
            {
                if( Utility.CompareUri( m_issuer, XmlNames.WSIdentity.SelfIssuerUriValue ) )
                { 
                    throw IDT.ThrowHelperError(
                            new InvalidCardException( SR.GetString( SR.SelfIssuedUriUsed ) ) ); 
                } 

            } 
            if( null == m_extendedInformation )
            {
                m_extendedInformation = new InfocardExtendedInformationCollection( m_id );
            } 

 
        } 

        private void ReadRoamingInfoCard( XmlReader reader ) 
        {

            IDT.Assert( null != reader, "null reader" );
            if( !reader.IsStartElement( XmlNames.WSIdentity.RoamingInfoCardElement, XmlNames.WSIdentity.Namespace ) ) 
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            } 

            // 
            // Read the metadata
            //
            reader.ReadStartElement();
 
            this.Language = reader.GetAttribute( XmlNames.Xml.Language, XmlNames.Xml.Namespace );
            if( String.IsNullOrEmpty( this.Language ) ) 
            { 
                this.Language = reader.GetAttribute( XmlNames.Xml.Language );
            } 

            ReadBaseInfoCard( reader );

            // 
            // It is invalid for a roaming store file to contain the private
            // personal identifier claim for self-issued cards. 
            // 
            if( m_isSelfIssued )
            { 
                InfoCardClaimCollection claims = GetClaims();

                if( claims.ContainsKey( InfoCardConstants.PPIDClaimsUri ) )
                { 
                    throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.InvalidImportFile ) ) );
                } 
            } 

            ReadInfoCardPrivateData( reader ); 
        }

        //
        // Summary 
        //   Populate the private infocard data by parsing a managed card file
        // 
        // Parameter 
        //   reader - The XmlReader to read from
        // 
        //
        private void ReadInfoCardPrivateData( XmlReader reader )
        {
            // 
            // Read the private data
            // 
            while( reader.Read() ) 
            {
                switch( reader.LocalName ) 
                {
                    case XmlNames.WSIdentity.RoamingInfoCardElement:
                        if( XmlNodeType.EndElement == reader.NodeType )
                        { 
                            return;
                        } 
                        break; 
                    case XmlNames.WSIdentity.MasterKeyElement:
                        byte[ ] rawKey = Utility.ReadByteStreamFromBase64( reader ).ToArray(); 

                        if( this.IsPinProtected )
                        {
                            if( null != rawKey && PinProtectionHelper.EncryptedMasterKeySize == rawKey.Length ) 
                            {
                                m_masterKey = new InfoCardMasterKey( m_id, rawKey ); 
                            } 
                            else
                            { 
                                throw IDT.ThrowHelperError(
                                        new InvalidCardException( SR.GetString( SR.InvalidImportFile ) ) );
                            }
                        } 
                        else
                        { 
                            if( null != rawKey && MasterKeySize == rawKey.Length ) 
                            {
                                m_masterKey = new InfoCardMasterKey( m_id, rawKey ); 
                            }
                            else
                            {
                                throw IDT.ThrowHelperError( 
                                        new InvalidCardException( SR.GetString( SR.InvalidImportFile ) ) );
                            } 
                        } 

                        break; 
                    case XmlNames.WSIdentity.ClaimValueListElement:
                        ReadClaimValues( reader );
                        break;
                } 

            } 
        } 

        // 
        // Summary
        //   Populate the infocard by parsing a managed card file
        //
        // Parameter 
        //   reader - The XmlReader to read from
        // 
        // 
        private void ReadBaseInfoCard( XmlReader reader )
        { 
            string value;
            try
            {
                while( reader.Read() ) 
                {
                    if( XmlNames.WSIdentity.Namespace == reader.NamespaceURI 
                       && XmlNodeType.EndElement == reader.NodeType 
                       && ( XmlNames.WSIdentity.InfoCardElement == reader.LocalName
                           || XmlNames.WSIdentity.InfoCardMetaDataElement == reader.LocalName ) ) 
                    {
                        reader.ReadEndElement();
                        return;
                    } 
                    if( XmlNames.WSIdentity.Namespace != reader.NamespaceURI
                        && XmlNodeType.Element == reader.NodeType ) 
                    { 

                        if( XmlNames.WSIdentity07.Namespace == reader.NamespaceURI 
                            && XmlNames.WSIdentity07.IssuerInformation == reader.LocalName )
                        {
                            if( m_readIssuerInformation )
                            { 
                                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.MultipleIssuerInformation ) ) );
                            } 
                            InfocardExtendedInformationEntry entry = new InfocardExtendedInformationEntry(); 
                            entry.ReadXml( reader );
                            if( null == m_extendedInformation ) 
                            {
                                m_extendedInformation = new InfocardExtendedInformationCollection( m_id );
                            }
                            m_extendedInformation.Add( entry ); 
                            m_readIssuerInformation = true;
                            continue; 
                        } 
                        else
                        { 
                            //
                            // We do not store these for now. In V2 we will be storing these entries too.
                            //
                            InfocardExtendedInformationEntry entry = new InfocardExtendedInformationEntry(); 
                            entry.ReadXml( reader ); // just used to skip this element
 
                        } 
                    }
                    if( XmlNames.WSIdentity.Namespace == reader.NamespaceURI 
                       && XmlNodeType.EndElement != reader.NodeType )
                    {
                        switch( reader.LocalName )
                        { 

                            case XmlNames.WSIdentity.CardIdElement: 
                                this.Id = new Uri( reader.ReadString().Trim() ); 
                                break;
                            case XmlNames.WSIdentity.CardVersionElement: 
                                this.Epoch = Convert.ToUInt32( reader.ReadString().Trim(), CultureInfo.InvariantCulture );

                                break;
                            case XmlNames.WSIdentity.CardImageElement: 
                                this.LogoMimeType = reader.GetAttribute(
                                                        XmlNames.WSIdentity.MimeTypeAttribute, 
                                                        XmlNames.WSIdentity.Namespace ); 
                                if( String.IsNullOrEmpty( this.LogoMimeType ) )
                                { 
                                    this.LogoMimeType = reader.GetAttribute( XmlNames.WSIdentity.MimeTypeAttribute );
                                }
                                this.Logo = Utility.ReadByteStreamFromBase64( reader ).ToArray();
                                break; 
                            case XmlNames.WSIdentity.CardNameElement:
                                this.Name = reader.ReadString().Trim(); 
                                break; 
                            case XmlNames.WSIdentity.IssuerNameElement:
                                this.IssuerName = reader.ReadString().Trim(); 
                                break;
                            case XmlNames.WSIdentity.IssuerElement:
                                this.Issuer = new Uri( reader.ReadString().Trim() );
                                break; 
                            case XmlNames.WSIdentity.TimeExpiresElement:
                                this.ExpiresOn = XmlConvert.ToDateTime( reader.ReadString().Trim(), XmlDateTimeSerializationMode.Utc ); 
                                break; 
                            case XmlNames.WSIdentity.TimeIssuedElement:
                                this.IssuedOn = XmlConvert.ToDateTime( reader.ReadString().Trim(), XmlDateTimeSerializationMode.Utc ); 
                                break;
                            case XmlNames.WSIdentity.SupportedClaimTypeListElement:
                                ReadClaims( reader );
                                break; 
                            case XmlNames.WSIdentity.SupportedTokenTypeListElement:
                                List tokenTypes = ReadTokenType( reader ); 
                                this.TokenTypes = tokenTypes.ToArray(); 
                                break;
                            case XmlNames.WSIdentity.RequireAppliesToElement: 
                                string optionalValue = reader.GetAttribute(
                                                        XmlNames.WSIdentity.OptionalAttribute,
                                                        XmlNames.WSIdentity.Namespace );
                                if( String.IsNullOrEmpty( optionalValue ) ) 
                                {
                                    optionalValue = reader.GetAttribute( XmlNames.WSIdentity.OptionalAttribute ); 
                                } 
                                if( !String.IsNullOrEmpty( optionalValue ) && ( "true" == optionalValue || "1" == optionalValue ) )
                                { 
                                    this.RequireAppliesto = RequireAppliesToStatus.Optional;
                                }
                                else
                                { 
                                    this.RequireAppliesto = RequireAppliesToStatus.Required;
                                } 
 
                                break;
                            case XmlNames.WSIdentity.TokenServiceListElement: 
                                ReadAuthServices( reader );
                                break;
                            case XmlNames.WSIdentity.PrivacyNoticeAtElement:
                                ReadPrivacyPolicy( reader ); 
                                break;
                            case XmlNames.WSIdentity.IsSelfIssuedElement: 
                                this.IsSelfIssued = Convert.ToBoolean( reader.ReadString().Trim(), CultureInfo.InvariantCulture ); 
                                if( this.IsSelfIssued && m_readIssuerInformation )
                                { 
                                    throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.ExtendedInfoInSelfIssued ) ) );
                                }
                                break;
                            case XmlNames.WSIdentity.PinDigestElement: 
                                byte[ ] pinHash = Utility.ReadByteStreamFromBase64( reader ).ToArray();
                                if( null != pinHash && 0 != pinHash.Length ) 
                                { 
                                    m_pinHash = pinHash;
                                } 
                                break;
                            case XmlNames.WSIdentity.HashSaltElement:
                                byte[ ] hashSalt = Utility.ReadByteStreamFromBase64( reader ).ToArray();
                                if( null != hashSalt && 0 != hashSalt.Length ) 
                                {
                                    this.HashSalt = hashSalt; 
                                } 
                                break;
                            case XmlNames.WSIdentity.TimeLastUpdatedElement: 
                                value = reader.ReadString().Trim();
                                if( !String.IsNullOrEmpty( value ) )
                                {
                                    this.LastUpdate = XmlConvert.ToDateTime( value, XmlDateTimeSerializationMode.Utc ); 
                                }
                                break; 
                            case XmlNames.WSIdentity.IssuerIdElement: 
                                byte[ ] issuerIdentifierAsBytes = Utility.ReadByteStreamFromBase64( reader ).ToArray();
                                if( null != issuerIdentifierAsBytes && 0 != issuerIdentifierAsBytes.Length ) 
                                {
                                    this.IssuerIdentifierAsBytes = issuerIdentifierAsBytes;
                                }
                                break; 
                            case XmlNames.WSIdentity.BackgroundColorElement:
                                this.BackgroundColor = Convert.ToInt32( reader.ReadString().Trim(), CultureInfo.InvariantCulture ); 
                                break; 
                            default:
                                break; 
                        }
                    }
                    else if( XmlNames.WSIdentity07.Namespace == reader.NamespaceURI
                       && XmlNodeType.EndElement != reader.NodeType ) 
                    {
                        if( XmlNames.WSIdentity07.RequireStrongRPIdentity == reader.LocalName 
                            && XmlNames.WSIdentity07.Namespace == reader.NamespaceURI ) 
                        {
 
                            GetRPIdentityRequirement().StrongIdentityRequired = true;
                        }
                    }
                } 
            }
            catch( UriFormatException e ) 
            { 
                throw IDT.ThrowHelperError(
                    new InvalidCardException( SR.GetString( SR.InvalidUriFormat ), e ) ); 
            }
        }

 

        // 
        // Summary 
        //   Read the privacy policy of the issuer
        // 
        // Parameter
        //   reader - The XmlReader to read from
        //
        private void ReadPrivacyPolicy( XmlReader reader ) 
        {
            IDT.Assert( null != reader, "null reader" ); 
            if( !reader.IsStartElement( XmlNames.WSIdentity.PrivacyNoticeAtElement, XmlNames.WSIdentity.Namespace ) ) 
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            }

            string privacyPolicyVersion = reader.GetAttribute( XmlNames.WSIdentity.PrivacyNoticeVersionAttribute, XmlNames.Xml.Namespace );
            if( String.IsNullOrEmpty( privacyPolicyVersion ) ) 
            {
                privacyPolicyVersion = reader.GetAttribute( XmlNames.WSIdentity.PrivacyNoticeVersionAttribute ); 
            } 
            if( !String.IsNullOrEmpty( privacyPolicyVersion ) )
            { 
                m_privacyPolicyVersion = Convert.ToUInt32( privacyPolicyVersion, CultureInfo.InvariantCulture );
            }

            IDT.TraceDebug( "Start reading the privacy policy element" ); 

            m_privacyPolicyLink = reader.ReadString().Trim(); 
 

        } 



        // 
        // Summary
        //   Read the claims values for self issued cards and populate the claim collection 
        // 
        // Parameter
        //   reader - The XmlReader to read from 
        //
        private void ReadClaimValues( XmlReader reader )
        {
            IDT.Assert( null != reader, "null reader" ); 
            if( !reader.IsStartElement( XmlNames.WSIdentity.ClaimValueListElement, XmlNames.WSIdentity.Namespace ) )
            { 
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            }
 
            IDT.TraceDebug( "Start reading the claim values elements" );


            while( reader.Read() ) 
            {
                if( XmlNodeType.EndElement == reader.NodeType && 
                    XmlNames.WSIdentity.ClaimValueListElement == reader.LocalName ) 
                {
                    return; 
                }
                if( XmlNames.WSIdentity.Namespace == reader.NamespaceURI
                    && XmlNames.WSIdentity.ClaimValueElement == reader.LocalName
                    && XmlNodeType.Element == reader.NodeType ) 
                {
                    string claimUri = reader.GetAttribute( XmlNames.WSIdentity.UriAttribute, XmlNames.Xml.Namespace ); 
                    if( String.IsNullOrEmpty( claimUri ) ) 
                    {
                        claimUri = reader.GetAttribute( XmlNames.WSIdentity.UriAttribute ); 
                    }
                    reader.Read();
                    string value = reader.ReadString().Trim();
 

                    // 
                    // For non-encrypted values a maximum length of 255 is enforced 
                    //
                    if( !this.IsPinProtected && value.Length > 255 ) 
                    {
                        throw IDT.ThrowHelperError(
                                        new InvalidCardException( SR.GetString( SR.TooLongClaimValue ) ) );
 
                    }
 
 
                    if( !String.IsNullOrEmpty( claimUri ) )
                    { 
                        //
                        // Need to check if the claimUri is a valid key in the
                        // Infocard claim collection
                        // 
                        if( !this.m_claims.ContainsKey( claimUri ) )
                        { 
                            throw IDT.ThrowHelperError( 
                                        new InvalidCardException( SR.GetString( SR.InvalidImportFile ) ) );
                        } 
                        //
                        // Need to perform validation of Gender and DateOfBirth fields
                        //
                        if( !String.IsNullOrEmpty( value ) && !this.IsPinProtected ) 
                        {
                            if( InfoCardConstants.Gender == claimUri ) 
                            { 
                                bool valid = ( "0" == value ||
                                  "1" == value || 
                                  "2" == value );

                                if( !valid )
                                { 
                                    throw IDT.ThrowHelperError(
                                        new InvalidCardException( SR.GetString( SR.InvalidImportFile ) ) ); 
                                } 
                            }
                            if( ( InfoCardConstants.DateOfBirth == claimUri ) ) 
                            {
                                try
                                {
                                    DateTime dob = XmlConvert.ToDateTime( value, XmlDateTimeSerializationMode.Utc ); 
                                }
#pragma warning disable 56500       // do not catch non-recoverable exceptions 
                                catch( Exception e ) 
                                {
                                    if( IDT.IsFatal( e ) ) 
                                    {
                                        InfoCardService.Crash( e );
                                    }
 
                                    throw IDT.ThrowHelperError(
                                        new InvalidCardException( SR.GetString( SR.InvalidImportFile ) ) ); 
                                } 
#pragma warning restore 56500
                            } 

                        }
                        m_claims[ claimUri ].Value = value;
                    } 
                }
            } 
 
        }
 


        //
        // Summary 
        //   Read the claims list in the infocard and populate the claim collection
        // 
        // Parameter 
        //   reader - The XmlReader to read from
        // 
        private void ReadClaims( XmlReader reader )
        {
            IDT.Assert( null != reader, "null reader" );
            if( !reader.IsStartElement( XmlNames.WSIdentity.SupportedClaimTypeListElement, XmlNames.WSIdentity.Namespace ) ) 
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            } 

            IDT.TraceDebug( "Start reading the claims elements" ); 


            while( reader.Read() )
            { 
                if( XmlNodeType.EndElement == reader.NodeType &&
                    XmlNames.WSIdentity.SupportedClaimTypeListElement == reader.LocalName ) 
                { 
                    return;
                } 
                if( XmlNames.WSIdentity.Namespace == reader.NamespaceURI
                    && XmlNames.WSIdentity.SupportedClaimTypeElement == reader.LocalName )
                {
                    InfoCardClaim clm = ReadSingleClaim( reader ); 
                    if( null != clm )
                    { 
                        this.AddClaim( clm ); 
                    }
                } 
            }

        }
 

        // 
        // Summary 
        //   Read a single claim to be added to the claim collection
        // 
        // Parameter
        //   reader - The XmlReader to read from
        //
        private InfoCardClaim ReadSingleClaim( XmlReader reader ) 
        {
            IDT.Assert( null != reader, "null reader" ); 
            if( !reader.IsStartElement( XmlNames.WSIdentity.SupportedClaimTypeElement, XmlNames.WSIdentity.Namespace ) ) 
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            }

            IDT.TraceDebug( "Start reading the claim element" );
 

            string claimUri = null; 
            string displayTag = null; 
            string description = null;
            string claimValue = null; 

            claimUri = reader.GetAttribute( XmlNames.WSIdentity.UriAttribute, XmlNames.WSIdentity.Namespace );
            if( String.IsNullOrEmpty( claimUri ) )
            { 
                claimUri = reader.GetAttribute( XmlNames.WSIdentity.UriAttribute );
            } 
 
            //
            // return if the element is empty 
            //
            if( reader.IsEmptyElement )
            {
                if( !String.IsNullOrEmpty( claimUri ) ) 
                {
                    InfoCardClaim claim = new InfoCardClaim( 
                        claimUri, 
                        claimValue,
                        description, 
                        displayTag );
                    return claim;
                }
                else 
                {
                    throw IDT.ThrowHelperError( 
                        new InvalidCardException( SR.GetString( SR.ClaimIdNull ) ) ); 
                }
            } 

            while( reader.Read() )
            {
                // 
                // Read the claim details
                // 
                switch( reader.LocalName ) 
                {
 
                    case XmlNames.WSIdentity.SupportedClaimTypeElement:
                        if( XmlNodeType.EndElement == reader.NodeType )
                        {
                            if( !String.IsNullOrEmpty( claimUri ) ) 
                            {
                                InfoCardClaim claim = new InfoCardClaim( 
                                    claimUri, 
                                    claimValue,
                                    description, 
                                    displayTag );
                                return claim;
                            }
                            else 
                            {
                                throw IDT.ThrowHelperError( 
                                    new InvalidCardException( SR.GetString( SR.ClaimIdNull ) ) ); 
                            }
                        } 
                        break;
                    case XmlNames.WSIdentity.DescriptionElement:
                        description = reader.ReadString().Trim();
                        break; 
                    case XmlNames.WSIdentity.DisplayTagElement:
                        displayTag = reader.ReadString().Trim(); 
                        break; 
                    case XmlNames.WSIdentity.ClaimValueElement:
                        // 
                        // read values only for self issued cards
                        //
                        if( IsSelfIssued )
                        { 
                            claimValue = reader.ReadString().Trim();
                        } 
                        break; 
                    default:
                        break; 
                }
            }
            return null;
 
        }
 
        // 
        // Summary
        //   Read the authentication service in the card 
        //
        // Parameter
        //   reader - The XmlReader to read from
        // 
        // Return
        //  The list of the authentication services 
        // 
        private void ReadAuthServices( XmlReader reader )
        { 
            IDT.Assert( null != reader, "null reader" );
            if( !reader.IsStartElement( XmlNames.WSIdentity.TokenServiceListElement, XmlNames.WSIdentity.Namespace ) )
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            }
 
 
            IDT.TraceDebug( "Start reading the authentication service elements" );
 
            if( reader.IsEmptyElement )
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.NoAuthenticationServicesInCard ) ) );
            } 
            while( reader.Read() )
            { 
 
                switch( reader.LocalName )
                { 
                    case XmlNames.WSIdentity.TokenServiceElement:
                        if( reader.NodeType != XmlNodeType.EndElement )
                        {
                            TokenCreationParameter service = new TokenCreationParameter(); 
                            service.ReadXml( reader );
                            if( service.IsComplete() ) 
                            { 
                                this.CreationParameters.Add( service );
                            } 
                            else
                            {
                                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.ServiceInvalidTokenService ) ) );
                            } 
                        }
                        break; 
                    case XmlNames.WSIdentity.TokenServiceListElement: 
                        return;
 
                }
            }
        }
 

 
 
        //
        // Summary 
        // Read list of token types supported by the issuer of the managed card
        //
        // Parameter
        //   reader - The XmlReader to read from 
        //
        // Return 
        //  The list of token types 
        //
        private List ReadTokenType( XmlReader reader ) 
        {

            IDT.Assert( null != reader, "null reader" );
            if( !reader.IsStartElement( XmlNames.WSIdentity.SupportedTokenTypeListElement, XmlNames.WSIdentity.Namespace ) ) 
            {
                throw IDT.ThrowHelperError( new InvalidCardException( SR.GetString( SR.UnexpectedElement ) ) ); 
            } 

 
            IDT.TraceDebug( "Reading the token types information" );

            List tokenTypes = new List();
 
            while( reader.Read() )
            { 
                if( XmlNodeType.EndElement == reader.NodeType 
                    && XmlNames.WSIdentity.SupportedTokenTypeListElement == reader.LocalName )
                { 
                    return tokenTypes;
                }

                if( XmlNames.WSTrustXmlSoap2005.c_TokenType == reader.LocalName 
                    && XmlNames.WSTrustXmlSoap2005.c_Namespace == reader.NamespaceURI
                    && XmlNodeType.EndElement != reader.NodeType 
                    && !reader.IsEmptyElement ) 
                {
                    String tokenType = reader.ReadString().Trim(); 
                    if( !String.IsNullOrEmpty( tokenType ) )
                    {
                        tokenTypes.Add( tokenType );
                    } 
                }
            } 
            return tokenTypes; 

        } 



    } 

} 

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