Internal.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / Internal.cs / 1305376 / Internal.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net { 
    using System.IO; 
    using System.Reflection;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Net.Sockets; 
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning; 
    using System.Security.Authentication.ExtendedProtection; 
    using System.Security.Cryptography.X509Certificates;
    using System.Text; 
    using System.Text.RegularExpressions;
    using System.Security.Permissions;
    using System.Diagnostics;
    using System.Threading; 
    using System.Security.Principal;
    using System.Security; 
    using System.Net.Security; 
    using System.Net.NetworkInformation;
    using System.Runtime.Serialization; 
    using Microsoft.Win32;

    internal static class IntPtrHelper {
        /* 
        // Consider removing.
        internal static IntPtr Add(IntPtr a, IntPtr b) { 
            return (IntPtr) ((long)a + (long)b); 
        }
        */ 
        internal static IntPtr Add(IntPtr a, int b) {
            return (IntPtr) ((long)a + (long)b);
        }
 
        internal static long Subtract(IntPtr a, IntPtr b) {
            return ((long)a - (long)b); 
        } 
    }
 
    internal class InternalException : SystemException
    {
        internal InternalException()
        { 
            GlobalLog.Assert("InternalException thrown.");
        } 
 
        internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
            base(serializationInfo, streamingContext) 
        { }
    }

    internal static class NclUtilities 
    {
        ///  
        ///     
        ///       Indicates true if the threadpool is low on threads,
        ///       in this case we need to refuse to start new requests, 
        ///       and avoid blocking.
        ///    
        /// 
        internal static bool IsThreadPoolLow() 
        {
#if !FEATURE_PAL 
            if (ComNetOS.IsAspNetServer) 
            {
                return false; 
            }
#endif //!FEATURE_PAL

            int workerThreads, completionPortThreads; 
            ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
 
#if !FEATURE_PAL 
            return workerThreads < 2 || (ComNetOS.IsWinNt && completionPortThreads < 2);
#else 
            GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
            return workerThreads < 2;
#endif //!FEATURE_PAL
        } 

 
        internal static bool HasShutdownStarted 
        {
            get 
            {
                return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
            }
        } 

        // This only works for context-destroying errors. 
        internal static bool IsCredentialFailure(SecurityStatus error) 
        {
            return error == SecurityStatus.LogonDenied || 
                error == SecurityStatus.UnknownCredentials ||
                error == SecurityStatus.NoImpersonation ||
                error == SecurityStatus.NoAuthenticatingAuthority ||
                error == SecurityStatus.UntrustedRoot || 
                error == SecurityStatus.CertExpired ||
                error == SecurityStatus.SmartcardLogonRequired || 
                error == SecurityStatus.BadBinding; 
        }
 
        // This only works for context-destroying errors.
        internal static bool IsClientFault(SecurityStatus error)
        {
            return error == SecurityStatus.InvalidToken || 
                error == SecurityStatus.CannotPack ||
                error == SecurityStatus.QopNotSupported || 
                error == SecurityStatus.NoCredentials || 
                error == SecurityStatus.MessageAltered ||
                error == SecurityStatus.OutOfSequence || 
                error == SecurityStatus.IncompleteMessage ||
                error == SecurityStatus.IncompleteCredentials ||
                error == SecurityStatus.WrongPrincipal ||
                error == SecurityStatus.TimeSkew || 
                error == SecurityStatus.IllegalMessage ||
                error == SecurityStatus.CertUnknown || 
                error == SecurityStatus.AlgorithmMismatch || 
                error == SecurityStatus.SecurityQosFailed ||
                error == SecurityStatus.UnsupportedPreauth; 
        }


        // ContextRelativeDemand 
        // Allows easily demanding a permission against a given ExecutionContext.
        // Have requested the CLR to provide this method on ExecutionContext. 
        private static ContextCallback s_ContextRelativeDemandCallback; 

        internal static ContextCallback ContextRelativeDemandCallback 
        {
            get
            {
                if (s_ContextRelativeDemandCallback == null) 
                    s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
                return s_ContextRelativeDemandCallback; 
            } 
        }
 
        private static void DemandCallback(object state)
        {
            ((CodeAccessPermission) state).Demand();
        } 

        // This is for checking if a hostname probably refers to this machine without going to DNS. 
        internal static bool GuessWhetherHostIsLoopback(string host) 
        {
            string hostLower = host.ToLowerInvariant(); 
            if (hostLower == "localhost" || hostLower == "loopback")
            {
                return true;
            } 

#if !FEATURE_PAL 
            IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties(); 
            string hostnameLower = ip.HostName.ToLowerInvariant();
            return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant(); 
#else
            return false;
#endif
        } 

        internal static bool IsFatal(Exception exception) 
        { 
            return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
        } 

        // Need a fast cached list of local addresses for internal use.
        private static IPAddress[] _LocalAddresses;
        private static object _LocalAddressesLock; 
        private static NetworkAddressChangePolled s_AddressChange;
 
#if !FEATURE_PAL 
        internal static IPAddress[] LocalAddresses
        { 
            get
            {
                if (s_AddressChange != null && s_AddressChange.CheckAndReset())
                { 
                    return (_LocalAddresses = GetLocalAddresses());
                } 
 
                if (_LocalAddresses != null)
                { 
                    return _LocalAddresses;
                }

                lock (LocalAddressesLock) 
                {
                    if (_LocalAddresses != null) 
                    { 
                        return _LocalAddresses;
                    } 

                    s_AddressChange = new NetworkAddressChangePolled();

                    return (_LocalAddresses = GetLocalAddresses()); 
                }
            } 
        } 

        private static IPAddress[] GetLocalAddresses() 
        {
            IPAddress[] local;

            // Different discovery for pre or post XP 
            if (ComNetOS.IsPostWin2K)
            { 
                ArrayList collections = new ArrayList(16); 
                int total = 0;
 
                SafeLocalFree buffer = null;
                GetAdaptersAddressesFlags gaaFlags = GetAdaptersAddressesFlags.SkipAnycast | GetAdaptersAddressesFlags.SkipMulticast |
                    GetAdaptersAddressesFlags.SkipFriendlyName | GetAdaptersAddressesFlags.SkipDnsServer;
                uint size = 0; 
                uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, SafeLocalFree.Zero, ref size);
                while (result == IpHelperErrors.ErrorBufferOverflow) 
                { 
                    try
                    { 
                        buffer = SafeLocalFree.LocalAlloc((int)size);
                        result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, buffer, ref size);

                        if (result == IpHelperErrors.Success) 
                        {
                            IpAdapterAddresses adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(buffer.DangerousGetHandle(), typeof(IpAdapterAddresses)); 
 
                            while (true)
                            { 
                                if (adapterAddresses.FirstUnicastAddress != IntPtr.Zero)
                                {
                                    UnicastIPAddressInformationCollection coll = SystemUnicastIPAddressInformation.ToAddressInformationCollection(adapterAddresses.FirstUnicastAddress);
                                    total += coll.Count; 
                                    collections.Add(coll);
                                } 
 
                                if (adapterAddresses.next == IntPtr.Zero)
                                { 
                                    break;
                                }

                                adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(adapterAddresses.next, typeof(IpAdapterAddresses)); 
                            }
                        } 
                    } 
                    finally
                    { 
                        if (buffer != null)
                            buffer.Close();
                        buffer = null;
                    } 
                }
 
                if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) 
                {
                    throw new NetworkInformationException((int)result); 
                }

                local = new IPAddress[total];
                uint i = 0; 
                foreach (UnicastIPAddressInformationCollection coll in collections)
                { 
                    foreach (IPAddressInformation info in coll) 
                    {
                        local[i++] = info.Address; 
                    }
                }
            }
            else 
            {
                ArrayList collections = new ArrayList(16); 
                int total = 0; 

                SafeLocalFree buffer = null; 
                uint size = 0;
                uint result = UnsafeNetInfoNativeMethods.GetAdaptersInfo(SafeLocalFree.Zero, ref size);
                while (result == IpHelperErrors.ErrorBufferOverflow)
                { 
                    try
                    { 
                        buffer = SafeLocalFree.LocalAlloc((int)size); 
                        result = UnsafeNetInfoNativeMethods.GetAdaptersInfo(buffer, ref size);
 
                        if (result == IpHelperErrors.Success)
                        {
                            IpAdapterInfo adapterInfo = (IpAdapterInfo)Marshal.PtrToStructure(buffer.DangerousGetHandle(), typeof(IpAdapterInfo));
 
                            while (true)
                            { 
                                IPAddressCollection coll = adapterInfo.ipAddressList.ToIPAddressCollection(); 
                                total += coll.Count;
                                collections.Add(coll); 

                                if (adapterInfo.Next == IntPtr.Zero)
                                {
                                    break; 
                                }
 
                                adapterInfo = (IpAdapterInfo)Marshal.PtrToStructure(adapterInfo.Next, typeof(IpAdapterInfo)); 
                            }
                        } 
                    }
                    finally
                    {
                        if (buffer != null) 
                            buffer.Close();
                    } 
                } 

 
                if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData)
                {
                    throw new NetworkInformationException((int)result);
                } 

                local = new IPAddress[total]; 
                uint i = 0; 
                foreach (IPAddressCollection coll in collections)
                { 
                    foreach (IPAddress info in coll)
                    {
                        local[i++] = info;
                    } 
                }
            } 
            return local; 
        }
 
        internal static bool IsAddressLocal(IPAddress ipAddress) {
            IPAddress[] localAddresses = NclUtilities.LocalAddresses;
            for (int i = 0; i < localAddresses.Length; i++)
            { 
                if (ipAddress.Equals(localAddresses[i], false))
                { 
                    return true; 
                }
            } 
            return false;
        }

#else // !FEATURE_PAL 
        private const int HostNameBufferLength = 256;
        internal static string _LocalDomainName; 
 
        // Copied from the old version of DNS.cs
        // Returns a list of our local addresses by calling gethostbyname with null. 
        //
        private static IPHostEntry GetLocalHost()
        {
            // 
            // IPv6 Changes: If IPv6 is enabled, we can't simply use the
            //               old IPv4 gethostbyname(null). Instead we need 
            //               to do a more complete lookup. 
            //
            if (Socket.SupportsIPv6) 
            {
                //
                // IPv6 enabled: use getaddrinfo() of the local host name
                // to obtain this information. Need to get the machines 
                // name as well - do that here so that we don't need to
                // Assert DNS permissions. 
                // 
                StringBuilder hostname = new StringBuilder(HostNameBufferLength);
                SocketError errorCode = 
                    UnsafeNclNativeMethods.OSSOCK.gethostname(
                    hostname,
                    HostNameBufferLength);
 
                if (errorCode != SocketError.Success)
                { 
                    throw new SocketException(); 
                }
 
                return Dns.GetHostByName(hostname.ToString());
            }
            else
            { 
                //
                // IPv6 disabled: use gethostbyname() to obtain information. 
                // 
                IntPtr nativePointer =
                    UnsafeNclNativeMethods.OSSOCK.gethostbyname( 
                    null);

                if (nativePointer == IntPtr.Zero)
                { 
                    throw new SocketException();
                } 
 
                return Dns.NativeToHostEntry(nativePointer);
            } 

        } // GetLocalHost

        internal static IPAddress[] LocalAddresses 
        {
            get 
            { 
                IPAddress[] local = _LocalAddresses;
                if (local != null) 
                {
                    return local;
                }
 
                lock (LocalAddressesLock)
                { 
                    local = _LocalAddresses; 
                    if (local != null)
                    { 
                        return local;
                    }

                    List localList = new List(); 

                        try 
                        { 
                            IPHostEntry hostEntry = GetLocalHost();
                            if (hostEntry != null) 
                            {
                                if (hostEntry.HostName != null)
                                {
                                    int dot = hostEntry.HostName.IndexOf('.'); 
                                    if (dot != -1)
                                    { 
                                        _LocalDomainName = hostEntry.HostName.Substring(dot); 
                                    }
                                } 

                                IPAddress[] ipAddresses = hostEntry.AddressList;
                                if (ipAddresses != null)
                                { 
                                    foreach (IPAddress ipAddress in ipAddresses)
                                    { 
                                        localList.Add(ipAddress); 
                                    }
                                } 
                            }
                        }
                        catch
                        { 
                        }
 
                    local = new IPAddress[localList.Count]; 
                    int index = 0;
                    foreach (IPAddress ipAddress in localList) 
                    {
                        local[index] = ipAddress;
                        index++;
                    } 
                    _LocalAddresses = local;
 
                    return local; 
                }
            } 
        }
#endif // !FEATURE_PAL

        private static object LocalAddressesLock 
        {
            get 
            { 
                if (_LocalAddressesLock == null)
                { 
                    Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
                }
                return _LocalAddressesLock;
            } 
        }
    } 
 
    internal static class NclConstants
    { 
        internal static readonly object Sentinel = new object();
        internal static readonly object[] EmptyObjectArray = new object[0];
        internal static readonly Uri[] EmptyUriArray = new Uri[0];
 
        internal static readonly byte[] CRLF = new byte[] {(byte) '\r', (byte) '\n'};
        internal static readonly byte[] ChunkTerminator = new byte[] {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'}; 
    } 

    // 
    // A simple [....] point, useful for deferring work.  Just an int value with helper methods.
    //
    // The two events being synchronized are the "Triggering" event and the "Completing" event.  The Triggering event
    // marks the gate as being active; the first subsequent Completing event handles the action. 
    //
    // First, a thread calls Trigger() to set the trigger on the gate.  This means it needs some work to be done, but only 
    // after another operation (the Completing event) finishes.  If Trigger() returns false, the Completing event already 
    // happened.  When the Completing event occurs, that thread calls Complete().  It returns true if the gate has been
    // previously triggered and the caller is the first one to complete it.  The caller should then handle the pending work item. 
    //
    // StartTrigger()/FinishTrigger() can be used instead of Trigger() if the triggering thread needs to set up some state
    // (e.g. the pending work item).  It will block Complete() in a spin-lock.
    // 
    internal struct InterlockedGate
    { 
        private int m_State; 

        internal const int Open = 0;        // Initial state of gate. 
        internal const int Held = 1;        // Gate is being actively held by a thread - indeterminate state.
        internal const int Triggered = 2;   // The triggering event has occurred.
        internal const int Closed = 3;      // The gated event is done.
 
#if DEBUG
        /* Consider removing 
        internal int State 
        {
            get 
            {
                return m_State;
            }
        } 
        */
#endif 
 
        // Only call when all threads are guaranteed to be done with the gate.
        internal void Reset() 
        {
            m_State = Open;
        }
 
        // Returns false if the gate is already closed or triggered.  If exclusive is true, throws if the gate is already
        // triggered. 
        internal bool Trigger(bool exclusive) 
        {
            int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open); 
            if (exclusive && (gate == Held || gate == Triggered))
            {
                GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
                throw new InternalException(); 
            }
            return gate == Open; 
        } 

        // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation.  This is useful to set up an invariant 
        // that must be ready by the time another thread closes the gate.  Do not block between StartTrigger() and FinishTrigger(), just
        // set up your state to be consistent.  If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
        // it in a finally.
        // 
        // Returns false if the gate is already closed or triggered.  If exclusive is true, throws if the gate is already
        // triggered. 
        internal bool StartTrigger(bool exclusive) 
        {
            int gate = Interlocked.CompareExchange(ref m_State, Held, Open); 
            if (exclusive && (gate == Held || gate == Triggered))
            {
                GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already triggered.");
                throw new InternalException(); 
            }
            return gate == Open; 
        } 

        // Gate must be held by StartTrigger(). 
        internal void FinishTrigger()
        {
            int gate = Interlocked.CompareExchange(ref m_State, Triggered, Held);
            if (gate != Held) 
            {
                GlobalLog.Assert("InterlockedGate::FinishTrigger", "Gate not held."); 
                throw new InternalException(); 
            }
        } 

        // Returns false if the gate had never been triggered or is already closed.
        internal bool Complete()
        { 
            int gate;
 
            // Spin while the gate is being held, allowing the other thread to set invariants up. 
            while ((gate = Interlocked.CompareExchange(ref m_State, Closed, Triggered)) != Triggered)
            { 
                if (gate == Closed)
                {
                    return false;
                } 

                if (gate == Open) 
                { 
                    if (Interlocked.CompareExchange(ref m_State, Closed, Open) == Open)
                    { 
                        return false;
                    }

                    continue; 
                }
 
                // gate == Held 
                Thread.SpinWait(1);
            } 

            return true;
        }
    } 

#if !FEATURE_PAL 
    // 
    // A polling implementation of NetworkAddressChange.
    // 
    internal class NetworkAddressChangePolled : IDisposable
    {
        private bool disposed;
        private SafeCloseSocketAndEvent ipv4Socket = null; 
        private SafeCloseSocketAndEvent ipv6Socket = null;
 
 
        internal unsafe NetworkAddressChangePolled()
        { 
            Socket.InitializeSockets();
            int blocking;
            if (Socket.OSSupportsIPv4)
            { 
                blocking = -1;
                ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false); 
                UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking); 
            }
 
            if(Socket.OSSupportsIPv6){
                blocking = -1;
                ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
                UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking); 
            }
            Setup(StartIPOptions.Both); 
        } 

        private unsafe void Setup(StartIPOptions startIPOptions) 
        {
            int length;
            SocketError errorCode;
 

            if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){ 
                errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking( 
                    ipv4Socket.DangerousGetHandle(),
                    (int) IOControlCode.AddressListChange, 
                    null, 0, null, 0,
                    out length,
                    IntPtr.Zero, IntPtr.Zero);
 
                if (errorCode != SocketError.Success) {
                    NetworkInformationException exception = new NetworkInformationException(); 
                    if (exception.ErrorCode != (uint)SocketError.WouldBlock) { 
                        Dispose();
                        return; 
                    }
                }

                errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange); 
                if (errorCode != SocketError.Success) {
                    Dispose(); 
                    return; 
                }
            } 

            if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
                errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
                    ipv6Socket.DangerousGetHandle(), 
                    (int) IOControlCode.AddressListChange,
                    null, 0, null, 0, 
                    out length, 
                    IntPtr.Zero, IntPtr.Zero);
 
                if (errorCode != SocketError.Success) {
                    NetworkInformationException exception = new NetworkInformationException();
                    if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
                        Dispose(); 
                        return;
                    } 
                } 

                errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange); 
                if (errorCode != SocketError.Success) {
                    Dispose();
                    return;
                } 
            }
        } 
 
        internal bool CheckAndReset()
        { 
            if(!disposed){
                lock (this){
                    if (!disposed){
                        StartIPOptions options = StartIPOptions.None; 

                        if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){ 
                            options|= StartIPOptions.StartIPv4; 
                        }
                        if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false)) 
                        {
                            options|= StartIPOptions.StartIPv6;
                        }
 
                        if(options != StartIPOptions.None){
                            Setup(options); 
                            return true; 
                        }
                    } 
                }
            }
            return false;
        } 

        public void Dispose() 
        { 
            if(!disposed){
                lock (this){ 
                    if (!disposed){
                        if(ipv6Socket != null){
                            ipv6Socket.Close();
                            ipv6Socket = null; 
                        }
                        if(ipv4Socket != null){ 
                            ipv4Socket.Close(); 
                            ipv6Socket = null;
                        } 
                        disposed = true;
                    }
                }
            } 
        }
    } 
#endif // FEATURE_PAL 

 

#if !FEATURE_PAL
    internal static class ComNetOS
    { 
        private const string OSInstallTypeRegKey = @"Software\Microsoft\Windows NT\CurrentVersion";
        private const string OSInstallTypeRegKeyPath = @"HKEY_LOCAL_MACHINE\" + OSInstallTypeRegKey; 
        private const string OSInstallTypeRegName = "InstallationType"; 
        private const string InstallTypeStringClient = "Client";
        private const string InstallTypeStringServer = "Server"; 
        private const string InstallTypeStringServerCore = "Server Core";
        private const string InstallTypeStringEmbedded = "Embedded";

        internal static readonly bool IsWin9x; 
        internal static readonly bool IsWinNt;
        internal static readonly bool IsWin2K; 
        internal static readonly bool IsPostWin2K;    // ie: XP or later but not Win2K 
        internal static readonly bool IsAspNetServer; // ie: running under ASP+
        internal static readonly bool IsWinHttp51;    // Is WinHttp 5.1 available. 
        internal static readonly bool IsWin2k3;       // Is Windows Server 2003 or later.
        internal static readonly bool IsXpSp2;        // Is Windows XP sp2 or later
        internal static readonly bool IsWin2k3Sp1;    // Is Windows 2003 sp1 or later
        internal static readonly bool IsVista;        // Is Windows Vista or later 
        internal static readonly bool IsWin7;         // Is Windows 7 or later
        internal static readonly WindowsInstallationType InstallationType; // e.g. Client, Server, Server Core 
 
        // We use it safe so assert
        [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)] 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
        static ComNetOS()
        { 
            OperatingSystem operatingSystem = Environment.OSVersion;
 
            GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString()); 

            if (operatingSystem.Platform == PlatformID.Win32Windows) 
            {
                IsWin9x = true;
                return;
            } 

            // 
            // Detect ASP+ as a platform running under NT 
            //
 
            try
            {
                IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
            } 
            catch { }
 
            // 
            // Platform is Windows NT or later
            // NT4: 4.0 
            // 2000: 5.0
            // XP: 5.1
            // Win2k3: 5.2
            // 
            IsWinNt = true;
 
            // 
            // Platform is Windows NT 2K or later
            // operatingSystem.Version.Major>=5 
            //
            IsWin2K = true;

            if (operatingSystem.Version.Major == 5 && operatingSystem.Version.Minor == 0) 
            {
                IsWinHttp51 = operatingSystem.Version.MajorRevision >= 3;    // Win2k SP3 
                return; 
            }
 
            IsPostWin2K = true;

            if ((operatingSystem.Version.Major == 5
                && operatingSystem.Version.Minor == 1 
                && operatingSystem.Version.MajorRevision >=2)
                ||(operatingSystem.Version.Major >= 6)) 
            { 
                IsXpSp2 = true;        // WinXP SP2
            } 

            if (operatingSystem.Version.Major == 5 && operatingSystem.Version.Minor == 1)
            {
                IsWinHttp51 = operatingSystem.Version.MajorRevision >= 1;    // WinXP SP1 

                return; 
            } 

            IsWinHttp51 = true; 
            IsWin2k3 = true;

            if ((operatingSystem.Version.Major == 5
                && operatingSystem.Version.Minor == 2 
                && operatingSystem.Version.MajorRevision >= 1)
                || (operatingSystem.Version.Major >= 6)) 
            { 
                IsWin2k3Sp1 = true;    // Win2k3 SP1
            } 

            if (operatingSystem.Version.Major >= 6)
            {
                IsVista = true; 
            }
 
            if (operatingSystem.Version.Major >= 7 || 
                (operatingSystem.Version.Major == 6 &&
                 operatingSystem.Version.Minor >= 1)) 
            {
                IsWin7 = true;
            }
 
            InstallationType = GetWindowsInstallType();
            if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType)); 
        } 

        [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)] 
        private static WindowsInstallationType GetWindowsInstallType()
        {
            try
            { 
                using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
                { 
                    string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string; 

                    if (string.IsNullOrEmpty(installType)) 
                    {
                        if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
                        return WindowsInstallationType.Unknown;
                    } 
                    else
                    { 
                        if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            return WindowsInstallationType.Client; 
                        }
                        if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            return WindowsInstallationType.Server; 
                        }
                        if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0) 
                        { 
                            return WindowsInstallationType.ServerCore;
                        } 
                        if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            return WindowsInstallationType.Embedded;
                        } 

                        if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType)); 
 
                        // Our default return is unknown when we don't recognize the SKU or if the registry value
                        // doesn't exist. As a result, the SKU-specific checks in System.Net will not limit the set 
                        // of functionality available. This allows SKUs we are not aware of to use all of our
                        // functionality. Burden is on them to ensure that all our dependencies are present.
                        // The alternative would be for us to throw an exception here. If we did this, these other
                        // SKUs wouldn't be able to load this code and test their behavior. We would need to update 
                        // this code to enable them to run.
                        return WindowsInstallationType.Unknown; 
                    } 
                }
            } 
            catch (UnauthorizedAccessException e)
            {
                if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
                return WindowsInstallationType.Unknown; 
            }
            catch (SecurityException e) 
            { 
                if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
                return WindowsInstallationType.Unknown; 
            }
        }
    }
#endif 

 
    // 
    // support class for Validation related stuff.
    // 
    internal static class ValidationHelper {

        public static string [] EmptyArray = new string[0];
 
        internal static readonly char[]  InvalidMethodChars =
                new char[]{ 
                ' ', 
                '\r',
                '\n', 
                '\t'
                };

        // invalid characters that cannot be found in a valid method-verb or http header 
        internal static readonly char[]  InvalidParamChars =
                new char[]{ 
                '(', 
                ')',
                '<', 
                '>',
                '@',
                ',',
                ';', 
                ':',
                '\\', 
                '"', 
                '\'',
                '/', 
                '[',
                ']',
                '?',
                '=', 
                '{',
                '}', 
                ' ', 
                '\t',
                '\r', 
                '\n'};

        public static string [] MakeEmptyArrayNull(string [] stringArray) {
            if ( stringArray == null || stringArray.Length == 0 ) { 
                return null;
            } else { 
                return stringArray; 
            }
        } 

        public static string MakeStringNull(string stringValue) {
            if ( stringValue == null || stringValue.Length == 0) {
                return null; 
            } else {
                return stringValue; 
            } 
        }
 
        /*
        // Consider removing.
        public static string MakeStringEmpty(string stringValue) {
            if ( stringValue == null || stringValue.Length == 0) { 
                return String.Empty;
            } else { 
                return stringValue; 
            }
        } 
        */

#if TRAVE
        /* 
        // Consider removing.
        public static int HashCode(object objectValue) { 
            if (objectValue == null) { 
                return -1;
            } else { 
                return objectValue.GetHashCode();
            }
        }
        */ 
#endif
 
        public static string ExceptionMessage(Exception exception) { 
            if (exception==null) {
                return string.Empty; 
            }
            if (exception.InnerException==null) {
                return exception.Message;
            } 
            return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
        } 
 
        public static string ToString(object objectValue) {
            if (objectValue == null) { 
                return "(null)";
            } else if (objectValue is string && ((string)objectValue).Length==0) {
                return "(string.empty)";
            } else if (objectValue is Exception) { 
                return ExceptionMessage(objectValue as Exception);
            } else if (objectValue is IntPtr) { 
                return "0x" + ((IntPtr)objectValue).ToString("x"); 
            } else {
                return objectValue.ToString(); 
            }
        }
        public static string HashString(object objectValue) {
            if (objectValue == null) { 
                return "(null)";
            } else if (objectValue is string && ((string)objectValue).Length==0) { 
                return "(string.empty)"; 
            } else {
                return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo); 
            }
        }

        public static bool IsInvalidHttpString(string stringValue) { 
            return stringValue.IndexOfAny(InvalidParamChars)!=-1;
        } 
 
        public static bool IsBlankString(string stringValue) {
            return stringValue==null || stringValue.Length==0; 
        }

        /*
        // Consider removing. 
        public static bool ValidateUInt32(long address) {
            // on false, API should throw new ArgumentOutOfRangeException("address"); 
            return address>=0x00000000 && address<=0xFFFFFFFF; 
        }
        */ 

        public static bool ValidateTcpPort(int port) {
            // on false, API should throw new ArgumentOutOfRangeException("port");
            return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort; 
        }
 
        public static bool ValidateRange(int actual, int fromAllowed, int toAllowed) { 
            // on false, API should throw new ArgumentOutOfRangeException("argument");
            return actual>=fromAllowed && actual<=toAllowed; 
        }

        /*
        // Consider removing. 
        public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
            // on false, API should throw new ArgumentOutOfRangeException("argument"); 
            return actual>=fromAllowed && actual<=toAllowed; 
        }
        */ 
    }

    internal static class ExceptionHelper
    { 
        internal static readonly KeyContainerPermission KeyContainerPermissionOpen = new KeyContainerPermission(KeyContainerPermissionFlags.Open);
        internal static readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect); 
        internal static readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); 
        internal static readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
        internal static readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure); 
        internal static readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
        internal static readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);

        internal static NotImplementedException MethodNotImplementedException { 
            get {
                return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException)); 
            } 
        }
 
        internal static NotImplementedException PropertyNotImplementedException {
            get {
                return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
            } 
        }
 
        internal static NotSupportedException MethodNotSupportedException { 
            get {
                return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException)); 
            }
        }

        internal static NotSupportedException PropertyNotSupportedException { 
            get {
                return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException)); 
            } 
        }
 
        internal static WebException IsolatedException {
            get {
                return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
            } 
        }
 
        internal static WebException RequestAbortedException { 
            get {
                return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled); 
            }
        }

        internal static UriFormatException BadSchemeException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_BadScheme)); 
            } 
        }
 
        internal static UriFormatException BadAuthorityException {
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_BadAuthority));
            } 
        }
 
        internal static UriFormatException EmptyUriException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_EmptyUri)); 
            }
        }

        internal static UriFormatException SchemeLimitException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_SchemeLimit)); 
            } 
        }
 
        internal static UriFormatException SizeLimitException {
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_SizeLimit));
            } 
        }
 
        internal static UriFormatException MustRootedPathException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_MustRootedPath)); 
            }
        }

        internal static UriFormatException BadHostNameException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_BadHostName)); 
            } 
        }
 
        internal static UriFormatException BadPortException {
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_BadPort));
            } 
        }
 
        internal static UriFormatException BadAuthorityTerminatorException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_BadAuthorityTerminator)); 
            }
        }

        internal static UriFormatException BadFormatException { 
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_BadFormat)); 
            } 
        }
 
        internal static UriFormatException CannotCreateRelativeException {
            get {
                return new UriFormatException(SR.GetString(SR.net_uri_CannotCreateRelative));
            } 
        }
 
        internal static WebException CacheEntryNotFoundException { 
            get {
                return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound); 
            }
        }

        internal static WebException RequestProhibitedByCachePolicyException { 
            get {
                return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy); 
            } 
        }
    } 

#if !FEATURE_PAL

    internal enum WindowsInstallationType 
    {
        Unknown = 0, 
        Client, 
        Server,
        ServerCore, 
        Embedded
    }

    internal enum SecurityStatus 
    {
        // Success / Informational 
        OK                          =   0x00000000, 
        ContinueNeeded              =   unchecked((int)0x00090312),
        CompleteNeeded              =   unchecked((int)0x00090313), 
        CompAndContinue             =   unchecked((int)0x00090314),
        ContextExpired              =   unchecked((int)0x00090317),
        CredentialsNeeded           =   unchecked((int)0x00090320),
        Renegotiate                 =   unchecked((int)0x00090321), 

        // Errors 
        OutOfMemory                 =   unchecked((int)0x80090300), 
        InvalidHandle               =   unchecked((int)0x80090301),
        Unsupported                 =   unchecked((int)0x80090302), 
        TargetUnknown               =   unchecked((int)0x80090303),
        InternalError               =   unchecked((int)0x80090304),
        PackageNotFound             =   unchecked((int)0x80090305),
        NotOwner                    =   unchecked((int)0x80090306), 
        CannotInstall               =   unchecked((int)0x80090307),
        InvalidToken                =   unchecked((int)0x80090308), 
        CannotPack                  =   unchecked((int)0x80090309), 
        QopNotSupported             =   unchecked((int)0x8009030A),
        NoImpersonation             =   unchecked((int)0x8009030B), 
        LogonDenied                 =   unchecked((int)0x8009030C),
        UnknownCredentials          =   unchecked((int)0x8009030D),
        NoCredentials               =   unchecked((int)0x8009030E),
        MessageAltered              =   unchecked((int)0x8009030F), 
        OutOfSequence               =   unchecked((int)0x80090310),
        NoAuthenticatingAuthority   =   unchecked((int)0x80090311), 
        IncompleteMessage           =   unchecked((int)0x80090318), 
        IncompleteCredentials       =   unchecked((int)0x80090320),
        BufferNotEnough             =   unchecked((int)0x80090321), 
        WrongPrincipal              =   unchecked((int)0x80090322),
        TimeSkew                    =   unchecked((int)0x80090324),
        UntrustedRoot               =   unchecked((int)0x80090325),
        IllegalMessage              =   unchecked((int)0x80090326), 
        CertUnknown                 =   unchecked((int)0x80090327),
        CertExpired                 =   unchecked((int)0x80090328), 
        AlgorithmMismatch           =   unchecked((int)0x80090331), 
        SecurityQosFailed           =   unchecked((int)0x80090332),
        SmartcardLogonRequired      =   unchecked((int)0x8009033E), 
        UnsupportedPreauth          =   unchecked((int)0x80090343),
        BadBinding                  =   unchecked((int)0x80090346)
    }
 
    internal enum ContentTypeValues {
        ChangeCipherSpec    = 0x14, 
        Alert               = 0x15, 
        HandShake           = 0x16,
        AppData             = 0x17, 
        Unrecognized        = 0xFF,
    }

    internal enum ContextAttribute { 
        //
        // look into  and  
        // 
        Sizes               = 0x00,
        Names               = 0x01, 
        Lifespan            = 0x02,
        DceInfo             = 0x03,
        StreamSizes         = 0x04,
        //KeyInfo             = 0x05, must not be used, see ConnectionInfo instead 
        Authority           = 0x06,
        // SECPKG_ATTR_PROTO_INFO          = 7, 
        // SECPKG_ATTR_PASSWORD_EXPIRY     = 8, 
        // SECPKG_ATTR_SESSION_KEY         = 9,
        PackageInfo         = 0x0A, 
        // SECPKG_ATTR_USER_FLAGS          = 11,
        NegotiationInfo    = 0x0C,
        // SECPKG_ATTR_NATIVE_NAMES        = 13,
        // SECPKG_ATTR_FLAGS               = 14, 
        // SECPKG_ATTR_USE_VALIDATED       = 15,
        // SECPKG_ATTR_CREDENTIAL_NAME     = 16, 
        // SECPKG_ATTR_TARGET_INFORMATION  = 17, 
        // SECPKG_ATTR_ACCESS_TOKEN        = 18,
        // SECPKG_ATTR_TARGET              = 19, 
        // SECPKG_ATTR_AUTHENTICATION_ID   = 20,
        UniqueBindings      = 0x19,
        EndpointBindings    = 0x1A,
        ClientSpecifiedSpn  = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27 
        RemoteCertificate   = 0x53,
        LocalCertificate    = 0x54, 
        RootStore           = 0x55, 
        IssuerListInfoEx    = 0x59,
        ConnectionInfo      = 0x5A, 
    }

    internal enum Endianness {
        Network             = 0x00, 
        Native              = 0x10,
    } 
 
    internal enum CredentialUse {
        Inbound             = 0x1, 
        Outbound            = 0x2,
        Both                = 0x3,
    }
 
    internal enum BufferType {
        Empty               = 0x00, 
        Data                = 0x01, 
        Token               = 0x02,
        Parameters          = 0x03, 
        Missing             = 0x04,
        Extra               = 0x05,
        Trailer             = 0x06,
        Header              = 0x07, 
        Padding             = 0x09,    // non-data padding
        Stream              = 0x0A, 
        ChannelBindings     = 0x0E, 
        TargetHost          = 0x10,
        ReadOnlyFlag        = unchecked((int)0x80000000), 
        ReadOnlyWithChecksum= 0x10000000
    }

    internal enum ChainPolicyType { 
        Base                = 1,
        Authenticode        = 2, 
        Authenticode_TS     = 3, 
        SSL                 = 4,
        BasicConstraints    = 5, 
        NtAuth              = 6,
    }

    internal enum IgnoreCertProblem { 
        not_time_valid              = 0x00000001,
        ctl_not_time_valid          = 0x00000002, 
        not_time_nested             = 0x00000004, 
        invalid_basic_constraints   = 0x00000008,
 
        all_not_time_valid          =
            not_time_valid          |
            ctl_not_time_valid      |
            not_time_nested, 

        allow_unknown_ca            = 0x00000010, 
        wrong_usage                 = 0x00000020, 
        invalid_name                = 0x00000040,
        invalid_policy              = 0x00000080, 
        end_rev_unknown             = 0x00000100,
        ctl_signer_rev_unknown      = 0x00000200,
        ca_rev_unknown              = 0x00000400,
        root_rev_unknown            = 0x00000800, 

        all_rev_unknown             = 
            end_rev_unknown         | 
            ctl_signer_rev_unknown  |
            ca_rev_unknown          | 
            root_rev_unknown,
        none =
            not_time_valid |
            ctl_not_time_valid | 
            not_time_nested |
            invalid_basic_constraints | 
            allow_unknown_ca | 
            wrong_usage |
            invalid_name | 
            invalid_policy |
            end_rev_unknown |
            ctl_signer_rev_unknown |
            ca_rev_unknown | 
            root_rev_unknown
    } 
 
    internal enum CertUsage {
        MatchTypeAnd    = 0x00, 
        MatchTypeOr     = 0x01,
    }

    [StructLayout(LayoutKind.Sequential)] 
    internal unsafe struct ChainPolicyParameter {
        public uint cbSize; 
        public uint dwFlags; 
        public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
 
        public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
    }

    [StructLayout(LayoutKind.Sequential)] 
    internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
 
        [StructLayout(LayoutKind.Explicit)] 
        internal struct U {
              [FieldOffset(0)] internal uint cbStruct;  //DWORD 
              [FieldOffset(0)] internal uint cbSize;    //DWORD
        };
        internal U u;
        internal int    dwAuthType;  //DWORD 
        internal uint   fdwChecks;   //DWORD
        internal char*  pwszServerName; //WCHAR* // used to check against CN=xxxx 
 
        internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
        { 
            u.cbStruct = StructSize;
            u.cbSize   = StructSize;
            //#      define      AUTHTYPE_CLIENT         1
            //#      define      AUTHTYPE_SERVER         2 
            dwAuthType = amIServer? 1: 2;
            fdwChecks = 0; 
            pwszServerName = null; 
        }
        static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA)); 
    }

    [StructLayout(LayoutKind.Sequential)]
    internal unsafe struct ChainPolicyStatus { 
        public uint   cbSize;
        public uint   dwError; 
        public uint   lChainIndex; 
        public uint   lElementIndex;
        public void*  pvExtraPolicyStatus; 

        public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
    }
 
    [StructLayout(LayoutKind.Sequential)]
    internal unsafe struct CertEnhKeyUse { 
 
        public uint   cUsageIdentifier;
        public void*  rgpszUsageIdentifier; 

#if TRAVE
        public override string ToString() {
            return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x"); 
        }
#endif 
    }; 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct CertUsageMatch {
        public CertUsage     dwType;
        public CertEnhKeyUse Usage;
#if TRAVE 
        public override string ToString() {
            return "dwType="+dwType.ToString()+" "+Usage.ToString(); 
        } 
#endif
    }; 

    [StructLayout(LayoutKind.Sequential)]
    internal struct ChainParameters {
        public uint cbSize; 
        public CertUsageMatch RequestedUsage;
        public CertUsageMatch RequestedIssuancePolicy; 
        public uint           UrlRetrievalTimeout; 
        public int            BoolCheckRevocationFreshnessTime;
        public uint           RevocationFreshnessTime; 


        public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
#if TRAVE 
        public override string ToString() {
            return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString(); 
        } 
#endif
    }; 

    [StructLayout(LayoutKind.Sequential)]
    struct _CERT_CHAIN_ELEMENT
    { 
        public uint cbSize;
        public IntPtr pCertContext; 
        // Since this structure is allocated by unmanaged code, we can 
        // omit the fileds below since we don't need to access them
        // CERT_TRUST_STATUS   TrustStatus; 
        // IntPtr                pRevocationInfo;
        // IntPtr                pIssuanceUsage;
        // IntPtr                pApplicationUsage;
    } 

    // CRYPTOAPI_BLOB 
    //[StructLayout(LayoutKind.Sequential)] 
    //unsafe struct CryptoBlob {
    //    // public uint cbData; 
    //    // public byte* pbData;
    //    public uint dataSize;
    //    public byte* dataBlob;
    //} 

    // SecPkgContext_IssuerListInfoEx 
    [StructLayout(LayoutKind.Sequential)] 
    unsafe struct IssuerListInfoEx {
        public SafeHandle aIssuers; 
        public uint cIssuers;

        public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
            aIssuers = handle; 
            fixed(byte* voidPtr = nativeBuffer) {
                // if this breaks on 64 bit, do the sizeof(IntPtr) trick 
                cIssuers = *((uint*)(voidPtr + IntPtr.Size)); 
            }
        } 
    }


    [StructLayout(LayoutKind.Sequential)] 
    internal struct SecureCredential {
 
/* 
typedef struct _SCHANNEL_CRED
{ 
    DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION
    DWORD           cCreds;
    PCCERT_CONTEXT *paCred;
    HCERTSTORE      hRootStore; 

    DWORD           cMappers; 
    struct _HMAPPER **aphMappers; 

    DWORD           cSupportedAlgs; 
    ALG_ID *        palgSupportedAlgs;

    DWORD           grbitEnabledProtocols;
    DWORD           dwMinimumCipherStrength; 
    DWORD           dwMaximumCipherStrength;
    DWORD           dwSessionLifespan; 
    DWORD           dwFlags; 
    DWORD           reserved;
} SCHANNEL_CRED, *PSCHANNEL_CRED; 
*/

        public const int CurrentVersion = 0x4;
 
        public int version;
        public int cCreds; 
 
        // ptr to an array of pointers
        // There is a hack done with this field.  AcquireCredentialsHandle requires an array of 
        // certificate handles; we only ever use one.  In order to avoid pinning a one element array,
        // we copy this value onto the stack, create a pointer on the stack to the copied value,
        // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
        // Then we fix it up afterwards.  Fine as long as all the SSPI credentials are not 
        // supposed to be threadsafe.
        public IntPtr certContextArray; 
 
        private readonly IntPtr rootStore;               // == always null, OTHERWISE NOT RELIABLE
        public int cMappers; 
        private readonly IntPtr phMappers;               // == always null, OTHERWISE NOT RELIABLE
        public int cSupportedAlgs;
        private readonly IntPtr palgSupportedAlgs;       // == always null, OTHERWISE NOT RELIABLE
        public SchProtocols grbitEnabledProtocols; 
        public int dwMinimumCipherStrength;
        public int dwMaximumCipherStrength; 
        public int dwSessionLifespan; 
        public SecureCredential.Flags dwFlags;
        public int reserved; 

        [Flags]
        public enum Flags {
            Zero            = 0, 
            NoSystemMapper  = 0x02,
            NoNameCheck     = 0x04, 
            ValidateManual  = 0x08, 
            NoDefaultCred   = 0x10,
            ValidateAuto    = 0x20 
        }

        public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
            // default values required for a struct 
            rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
            cCreds = cMappers = cSupportedAlgs = 0; 
 
            if (policy == EncryptionPolicy.RequireEncryption) {
                // Prohibit null encryption cipher 
                dwMinimumCipherStrength = 0;
                dwMaximumCipherStrength = 0;
            }
            else if (policy == EncryptionPolicy.AllowNoEncryption) { 
                // Allow null encryption cipher in addition to other ciphers
                dwMinimumCipherStrength = -1; 
                dwMaximumCipherStrength =  0; 
            }
            else if (policy == EncryptionPolicy.NoEncryption) { 
                // Suppress all encryption and require null encryption cipher only
                dwMinimumCipherStrength = -1;
                dwMaximumCipherStrength = -1;
            } 
            else {
                throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy"); 
            } 

            dwSessionLifespan = reserved = 0; 
            this.version = version;
            dwFlags = flags;
            grbitEnabledProtocols = protocols;
            if (certificate != null) { 
                certContextArray = certificate.Handle;
                cCreds = 1; 
            } 
        }
 
        [System.Diagnostics.Conditional("TRAVE")]
        internal void DebugDump() {
            GlobalLog.Print("SecureCredential #"+GetHashCode());
            GlobalLog.Print("    version                 = " + version); 
            GlobalLog.Print("    cCreds                  = " + cCreds);
            GlobalLog.Print("    certContextArray        = " + String.Format("0x{0:x}", certContextArray)); 
            GlobalLog.Print("    rootStore               = " + String.Format("0x{0:x}", rootStore)); 
            GlobalLog.Print("    cMappers                = " + cMappers);
            GlobalLog.Print("    phMappers               = " + String.Format("0x{0:x}", phMappers)); 
            GlobalLog.Print("    cSupportedAlgs          = " + cSupportedAlgs);
            GlobalLog.Print("    palgSupportedAlgs       = " + String.Format("0x{0:x}", palgSupportedAlgs));
            GlobalLog.Print("    grbitEnabledProtocols   = " + String.Format("0x{0:x}", grbitEnabledProtocols));
            GlobalLog.Print("    dwMinimumCipherStrength = " + dwMinimumCipherStrength); 
            GlobalLog.Print("    dwMaximumCipherStrength = " + dwMaximumCipherStrength);
            GlobalLog.Print("    dwSessionLifespan       = " + String.Format("0x{0:x}", dwSessionLifespan)); 
            GlobalLog.Print("    dwFlags                 = " + String.Format("0x{0:x}", dwFlags)); 
            GlobalLog.Print("    reserved                = " + String.Format("0x{0:x}", reserved));
        } 

    } // SecureCredential

 
    [StructLayout(LayoutKind.Sequential)]
    internal unsafe struct SecurityBufferStruct { 
        public int          count; 
        public BufferType   type;
        public IntPtr       token; 

        public static readonly int Size = sizeof(SecurityBufferStruct);
    }
 
    internal class SecurityBuffer {
        public int size; 
        public BufferType type; 
        public byte[] token;
        public SafeHandle unmanagedToken; 
        public int offset;

        public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
            GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range.  [" + offset + "]"); 
            GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range.  [" + size + "]");
 			 
            this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length); 
            this.size   = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
            this.type   = tokentype; 
            this.token  = size == 0 ? null : data;
        }

        public SecurityBuffer(byte[] data, BufferType tokentype) { 
            this.size   = data == null ? 0 : data.Length;
            this.type   = tokentype; 
            this.token  = size == 0 ? null : data; 
        }
 
        public SecurityBuffer(int size, BufferType tokentype) {
            GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range.  [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");

            this.size   = size; 
            this.type   = tokentype;
            this.token  = size == 0 ? null : new byte[size]; 
        } 

        public SecurityBuffer(ChannelBinding binding) { 
            this.size           = (binding == null ? 0 : binding.Size);
            this.type           = BufferType.ChannelBindings;
            this.unmanagedToken = binding;
        } 
    }
 
    [StructLayout(LayoutKind.Sequential)] 
    internal unsafe class SecurityBufferDescriptor {
    /* 
    typedef struct _SecBufferDesc {
        ULONG        ulVersion;
        ULONG        cBuffers;
        PSecBuffer   pBuffers; 
    } SecBufferDesc, * PSecBufferDesc;
    */ 
            public  readonly    int     Version; 
            public  readonly    int     Count;
            public  void*       UnmanagedPointer; 

        public SecurityBufferDescriptor(int count) {
            Version = 0;
            Count = count; 
            UnmanagedPointer = null;
        } 
 
        [System.Diagnostics.Conditional("TRAVE")]
        internal void DebugDump() { 
            GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
            GlobalLog.Print("    version             = " + Version);
            GlobalLog.Print("    count               = " + Count);
            GlobalLog.Print("    securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x")); 
        }
    } // SecurityBufferDescriptor 
 
    internal  enum    CertificateEncoding {
        Zero                     = 0, 
        X509AsnEncoding          = unchecked((int)0x00000001),
        X509NdrEncoding          = unchecked((int)0x00000002),
        Pkcs7AsnEncoding         = unchecked((int)0x00010000),
        Pkcs7NdrEncoding         = unchecked((int)0x00020000), 
        AnyAsnEncoding           = X509AsnEncoding|Pkcs7AsnEncoding
    } 
 
    internal  enum    CertificateProblem {
        OK                          =   0x00000000, 
        TrustNOSIGNATURE            = unchecked((int)0x800B0100),
        CertEXPIRED                 = unchecked((int)0x800B0101),
        CertVALIDITYPERIODNESTING   = unchecked((int)0x800B0102),
        CertROLE                    = unchecked((int)0x800B0103), 
        CertPATHLENCONST            = unchecked((int)0x800B0104),
        CertCRITICAL                = unchecked((int)0x800B0105), 
        CertPURPOSE                 = unchecked((int)0x800B0106), 
        CertISSUERCHAINING          = unchecked((int)0x800B0107),
        CertMALFORMED               = unchecked((int)0x800B0108), 
        CertUNTRUSTEDROOT           = unchecked((int)0x800B0109),
        CertCHAINING                = unchecked((int)0x800B010A),
        CertREVOKED                 = unchecked((int)0x800B010C),
        CertUNTRUSTEDTESTROOT       = unchecked((int)0x800B010D), 
        CertREVOCATION_FAILURE      = unchecked((int)0x800B010E),
        CertCN_NO_MATCH             = unchecked((int)0x800B010F), 
        CertWRONG_USAGE             = unchecked((int)0x800B0110), 
        TrustEXPLICITDISTRUST       = unchecked((int)0x800B0111),
        CertUNTRUSTEDCA             = unchecked((int)0x800B0112), 
        CertINVALIDPOLICY           = unchecked((int)0x800B0113),
        CertINVALIDNAME             = unchecked((int)0x800B0114),

        CryptNOREVOCATIONCHECK       = unchecked((int)0x80092012), 
        CryptREVOCATIONOFFLINE       = unchecked((int)0x80092013),
 
        TrustSYSTEMERROR            = unchecked((int)0x80096001), 
        TrustNOSIGNERCERT           = unchecked((int)0x80096002),
        TrustCOUNTERSIGNER          = unchecked((int)0x80096003), 
        TrustCERTSIGNATURE          = unchecked((int)0x80096004),
        TrustTIMESTAMP              = unchecked((int)0x80096005),
        TrustBADDIGEST              = unchecked((int)0x80096010),
        TrustBASICCONSTRAINTS       = unchecked((int)0x80096019), 
        TrustFINANCIALCRITERIA      = unchecked((int)0x8009601E),
    } 
 
    [StructLayout(LayoutKind.Sequential)]
    internal class SecChannelBindings 
    {
        internal int dwInitiatorAddrType;
        internal int cbInitiatorLength;
        internal int dwInitiatorOffset; 

        internal int dwAcceptorAddrType; 
        internal int cbAcceptorLength; 
        internal int dwAcceptorOffset;
 
        internal int cbApplicationDataLength;
        internal int dwApplicationDataOffset;
    }
 
#endif // !FEATURE_PAL
 
    // 
    // WebRequestPrefixElement
    // 
    // This is an element of the prefix list. It contains the prefix and the
    // interface to be called to create a request for that prefix.
    //
 
    /// 
    ///    [To be supplied.] 
    ///  
    // internal class WebRequestPrefixElement {
    internal class WebRequestPrefixElement  { 

        /// 
        ///    [To be supplied.]
        ///  
        public    string              Prefix;
        ///  
        ///    [To be supplied.] 
        /// 
        internal    IWebRequestCreate   creator; 
        /// 
        ///    [To be supplied.]
        /// 
        internal    Type   creatorType; 

        public IWebRequestCreate Creator { 
            get { 
                if (creator == null && creatorType != null) {
                    lock(this) { 
                        if (creator == null) {
                            creator = (IWebRequestCreate)Activator.CreateInstance(
                                                        creatorType,
                                                        BindingFlags.CreateInstance 
                                                        | BindingFlags.Instance
                                                        | BindingFlags.NonPublic 
                                                        | BindingFlags.Public, 
                                                        null,          // Binder
                                                        new object[0], // no arguments 
                                                        CultureInfo.InvariantCulture
                                                        );
                        }
                    } 
                }
 
                return creator; 
            }
 
            set {
                creator = value;
            }
        } 

        public WebRequestPrefixElement(string P, Type creatorType) { 
            // verify that its of the proper type of IWebRequestCreate 
            if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
            { 
                throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
                                                                creatorType.AssemblyQualifiedName,
                                                                "IWebRequestCreate"));
            } 

            Prefix = P; 
            this.creatorType = creatorType; 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        public WebRequestPrefixElement(string P, IWebRequestCreate C) { 
            Prefix = P;
            Creator = C; 
        } 

    } // class PrefixListElement 


    //
    // HttpRequestCreator. 
    //
    // This is the class that we use to create HTTP and HTTPS requests. 
    // 

    internal class HttpRequestCreator : IWebRequestCreate { 

        /*++

         Create - Create an HttpWebRequest. 

            This is our method to create an HttpWebRequest. We register 
            for HTTP and HTTPS Uris, and this method is called when a request 
            needs to be created for one of those.
 

            Input:
                    Uri             - Uri for request being created.
 
            Returns:
                    The newly created HttpWebRequest. 
 
         --*/
 
        public WebRequest Create( Uri Uri ) {
            //
            // Note, DNS permissions check will not happen on WebRequest
            // 
            return new HttpWebRequest(Uri, null);
        } 
 
    } // class HttpRequestCreator
 
    //
    //  CoreResponseData - Used to store result of HTTP header parsing and
    //      response parsing.  Also Contains new stream to use, and
    //      is used as core of new Response 
    //
    internal class CoreResponseData { 
 
        // Status Line Response Values
        public HttpStatusCode m_StatusCode; 
        public string m_StatusDescription;
        public bool m_IsVersionHttp11;

        // Content Length needed for semantics, -1 if chunked 
        public long m_ContentLength;
 
        // Response Headers 
        public WebHeaderCollection m_ResponseHeaders;
 
        // ConnectStream - for reading actual data
        public Stream m_ConnectStream;

        internal CoreResponseData Clone() { 
            CoreResponseData cloneResponseData = new CoreResponseData();
            cloneResponseData.m_StatusCode        = m_StatusCode; 
            cloneResponseData.m_StatusDescription = m_StatusDescription; 
            cloneResponseData.m_IsVersionHttp11   = m_IsVersionHttp11;
            cloneResponseData.m_ContentLength     = m_ContentLength; 
            cloneResponseData.m_ResponseHeaders   = m_ResponseHeaders;
            cloneResponseData.m_ConnectStream     = m_ConnectStream;
            return cloneResponseData;
        } 

    } 
 

    /*++ 

    StreamChunkBytes - A class to read a chunk stream from a ConnectStream.

    A simple little value class that implements the IReadChunkBytes 
    interface.
 
    --*/ 
    internal class StreamChunkBytes : IReadChunkBytes {
 
        public  ConnectStream   ChunkStream;
        public  int             BytesRead = 0;
        public  int             TotalBytesRead = 0;
        private byte            PushByte; 
        private bool            HavePush;
 
        public StreamChunkBytes(ConnectStream connectStream) { 
            ChunkStream = connectStream;
            return; 
        }

        public int NextByte {
            get { 
                if (HavePush) {
                    HavePush = false; 
                    return PushByte; 
                }
 
                return ChunkStream.ReadSingleByte();
            }
            set {
                PushByte = (byte)value; 
                HavePush = true;
            } 
        } 

    } // class StreamChunkBytes 


    internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
 
    //
    // this class contains known header names 
    // 

    internal static class HttpKnownHeaderNames { 

        public const string CacheControl = "Cache-Control";
        public const string Connection = "Connection";
        public const string Date = "Date"; 
        public const string KeepAlive = "Keep-Alive";
        public const string Pragma = "Pragma"; 
        public const string ProxyConnection = "Proxy-Connection"; 
        public const string Trailer = "Trailer";
        public const string TransferEncoding = "Transfer-Encoding"; 
        public const string Upgrade = "Upgrade";
        public const string Via = "Via";
        public const string Warning = "Warning";
        public const string ContentLength = "Content-Length"; 
        public const string ContentType = "Content-Type";
        public const string ContentEncoding = "Content-Encoding"; 
        public const string ContentLanguage = "Content-Language"; 
        public const string ContentLocation = "Content-Location";
        public const string ContentRange = "Content-Range"; 
        public const string Expires = "Expires";
        public const string LastModified = "Last-Modified";
        public const string Age = "Age";
        public const string Location = "Location"; 
        public const string ProxyAuthenticate = "Proxy-Authenticate";
        public const string RetryAfter = "Retry-After"; 
        public const string Server = "Server"; 
        public const string SetCookie = "Set-Cookie";
        public const string SetCookie2 = "Set-Cookie2"; 
        public const string Vary = "Vary";
        public const string WWWAuthenticate = "WWW-Authenticate";
        public const string Accept = "Accept";
        public const string AcceptCharset = "Accept-Charset"; 
        public const string AcceptEncoding = "Accept-Encoding";
        public const string AcceptLanguage = "Accept-Language"; 
        public const string Authorization = "Authorization"; 
        public const string Cookie = "Cookie";
        public const string Cookie2 = "Cookie2"; 
        public const string Expect = "Expect";
        public const string From = "From";
        public const string Host = "Host";
        public const string IfMatch = "If-Match"; 
        public const string IfModifiedSince = "If-Modified-Since";
        public const string IfNoneMatch = "If-None-Match"; 
        public const string IfRange = "If-Range"; 
        public const string IfUnmodifiedSince = "If-Unmodified-Since";
        public const string MaxForwards = "Max-Forwards"; 
        public const string ProxyAuthorization = "Proxy-Authorization";
        public const string Referer = "Referer";
        public const string Range = "Range";
        public const string UserAgent = "User-Agent"; 
        public const string ContentMD5 = "Content-MD5";
        public const string ETag = "ETag"; 
        public const string TE = "TE"; 
        public const string Allow = "Allow";
        public const string AcceptRanges = "Accept-Ranges"; 
        public const string P3P = "P3P";
        public const string XPoweredBy = "X-Powered-By";
        public const string XAspNetVersion = "X-AspNet-Version";
    } 

    ///  
    ///     
    ///       Represents the method that will notify callers when a continue has been
    ///       received by the client. 
    ///    
    /// 
    // Delegate type for us to notify callers when we receive a continue
    public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders); 

    // 
    // HttpWriteMode - used to control the way in which an entity Body is posted. 
    //
    enum HttpWriteMode { 
        Unknown         = 0,
        ContentLength   = 1,
        Chunked         = 2,
        Buffer          = 3, 
        None            = 4,
    } 
 
    // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
    delegate void UnlockConnectionDelegate(); 

    enum HttpBehaviour : byte {
        Unknown                     = 0,
        HTTP10                      = 1, 
        HTTP11PartiallyCompliant    = 2,
        HTTP11                      = 3, 
    } 

    internal enum HttpProcessingResult { 
        Continue  = 0,
        ReadWait  = 1,
        WriteWait = 2,
    } 

    // 
    // HttpVerb - used to define various per Verb Properties 
    //
 
    //
    // Note - this is a place holder for Verb properties,
    //  the following two bools can most likely be combined into
    //  a single Enum type.  And the Verb can be incorporated. 
    //
    class KnownHttpVerb { 
        internal string Name; // verb name 

        internal bool RequireContentBody; // require content body to be sent 
        internal bool ContentBodyNotAllowed; // not allowed to send content body
        internal bool ConnectRequest; // special semantics for a connect request
        internal bool ExpectNoContentResponse; // response will not have content body
 
        internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
            Name = name; 
            RequireContentBody = requireContentBody; 
            ContentBodyNotAllowed = contentBodyNotAllowed;
            ConnectRequest = connectRequest; 
            ExpectNoContentResponse = expectNoContentResponse;
        }

        // Force an an init, before we use them 
        private static ListDictionary NamedHeaders;
 
        // known verbs 
        internal static KnownHttpVerb Get;
        internal static KnownHttpVerb Connect; 
        internal static KnownHttpVerb Head;
        internal static KnownHttpVerb Put;
        internal static KnownHttpVerb Post;
        internal static KnownHttpVerb MkCol; 

        // 
        // InitializeKnownVerbs - Does basic init for this object, 
        //  such as creating defaultings and filling them
        // 
        static KnownHttpVerb() {
            NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
            Get = new KnownHttpVerb("GET", false, true, false, false);
            Connect = new KnownHttpVerb("CONNECT", false, true, true, false); 
            Head = new KnownHttpVerb("HEAD", false, true, false, true);
            Put = new KnownHttpVerb("PUT", true, false, false, false); 
            Post = new KnownHttpVerb("POST", true, false, false, false); 
            MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
            NamedHeaders[Get.Name] = Get; 
            NamedHeaders[Connect.Name] = Connect;
            NamedHeaders[Head.Name] = Head;
            NamedHeaders[Put.Name] = Put;
            NamedHeaders[Post.Name] = Post; 
            NamedHeaders[MkCol.Name] = MkCol;
        } 
 
        public bool Equals(KnownHttpVerb verb) {
            return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0; 
        }

        public static KnownHttpVerb Parse(string name) {
            KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb; 
            if (knownHttpVerb==null) {
                // unknown verb, default behaviour 
                knownHttpVerb = new KnownHttpVerb(name, false, false, false, false); 
            }
            return knownHttpVerb; 
        }
    }

 
    //
    // HttpProtocolUtils - A collection of utility functions for HTTP usage. 
    // 

    internal class HttpProtocolUtils { 

        private HttpProtocolUtils() {
        }
 
        //
        // extra buffers for build/parsing, recv/send HTTP data, 
        //  at some point we should consolidate 
        //
 

        // parse String to DateTime format.
        internal static DateTime string2date(String S) {
            DateTime dtOut; 
            if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
                return dtOut; 
            } 
            else {
                throw new ProtocolViolationException(SR.GetString(SR.net_baddate)); 
            }

        }
 
        // convert Date to String using RFC 1123 pattern
        internal static string date2string(DateTime D) { 
            DateTimeFormatInfo dateFormat = new DateTimeFormatInfo(); 
            return D.ToUniversalTime().ToString("R", dateFormat);
        } 
    }

#if !FEATURE_PAL
    // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider 
    internal class  PolicyWrapper {
        private const uint          IgnoreUnmatchedCN       = 0x00001000; 
        private ICertificatePolicy  fwdPolicy; 
        private ServicePoint        srvPoint;
        private WebRequest          request; 

        internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
            this.fwdPolicy = policy;
            srvPoint = sp; 
            request = wr;
        } 
 
        public bool Accept(X509Certificate Certificate, int CertificateProblem) {
            return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem); 
        }

        internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
            GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags)); 
            ChainPolicyStatus status = new ChainPolicyStatus();
            status.cbSize = ChainPolicyStatus.StructSize; 
            int errorCode = 
                UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
                    (IntPtr) ChainPolicyType.SSL, 
                    chainContext,
                    ref cpp,
                    ref status);
 
            GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
#if TRAVE 
            GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]"); 
#endif
            GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString()); 
            return status.dwError;
        }

        private static IgnoreCertProblem MapErrorCode(uint errorCode) { 
            switch ((CertificateProblem) errorCode) {
 
                case CertificateProblem.CertINVALIDNAME : 
                case CertificateProblem.CertCN_NO_MATCH :
                    return IgnoreCertProblem.invalid_name; 

                case CertificateProblem.CertINVALIDPOLICY :
                case CertificateProblem.CertPURPOSE :
                    return IgnoreCertProblem.invalid_policy; 

                case CertificateProblem.CertEXPIRED : 
                    return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid; 

                case CertificateProblem.CertVALIDITYPERIODNESTING : 
                    return IgnoreCertProblem.not_time_nested;

                case CertificateProblem.CertCHAINING :
                case CertificateProblem.CertUNTRUSTEDCA : 
                case CertificateProblem.CertUNTRUSTEDROOT :
                    return IgnoreCertProblem.allow_unknown_ca; 
 
                case CertificateProblem.CertREVOKED :
                case CertificateProblem.CertREVOCATION_FAILURE : 
                case CertificateProblem.CryptNOREVOCATIONCHECK:
                case CertificateProblem.CryptREVOCATIONOFFLINE:
                    return IgnoreCertProblem.all_rev_unknown;
 
                case CertificateProblem.CertROLE:
                case CertificateProblem.TrustBASICCONSTRAINTS: 
                    return IgnoreCertProblem.invalid_basic_constraints; 

                case CertificateProblem.CertWRONG_USAGE : 
                    return IgnoreCertProblem.wrong_usage;

                default:
                    return 0; 
            }
        } 
 

        private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError) 
        {
            fatalError = false;
            SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
            ArrayList certificateProblems = new ArrayList(); 
            unsafe {
                uint status = 0; 
                ChainPolicyParameter cppStruct = new ChainPolicyParameter(); 
                cppStruct.cbSize  = ChainPolicyParameter.StructSize;
                cppStruct.dwFlags = 0; 

                SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
                cppStruct.pvExtraPolicyPara = &eppStruct;
 
                fixed (char* namePtr = hostName) {
                    if (ServicePointManager.CheckCertificateName){ 
                        eppStruct.pwszServerName = namePtr; 
                    }
 
                    while (true) {
                        status = VerifyChainPolicy(chainContext, ref cppStruct);
                        uint ignoreErrorMask = (uint)MapErrorCode(status);
 
                        certificateProblems.Add(status);
 
                        if (status == 0) {  // No more problems with the certificate? 
                            break;          // Then break out of the callback loop
                        } 

                        if (ignoreErrorMask == 0) {  // Unrecognized error encountered
                            fatalError = true;
                            break; 
                        }
                        else { 
                            cppStruct.dwFlags |= ignoreErrorMask; 
                            if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
                                eppStruct.fdwChecks = IgnoreUnmatchedCN; 
                            }
                        }
                    }
                } 
            }
 
            return (uint[]) certificateProblems.ToArray(typeof(uint)); 
        }
 
        internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == 0)
                return Accept(certificate, 0); 

            if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) 
                return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry 
            else {
                if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 || 
                    (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
                {
                    bool fatalError = false;
                    uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError); 

                    if (fatalError) { 
                        // By today design we cannot allow decider to ignore a fatal error. 
                        // This error is fatal.
                        Accept(certificate, (int) SecurityStatus.InternalError); 
                        return false;
                    }

 
                    if (certificateProblems.Length == 0)
                        return Accept(certificate, (int) CertificateProblem.OK); 
 
                    // Run each error through Accept().
                    foreach (uint error in certificateProblems) 
                        if (!Accept(certificate, (int) error))
                            return false;
                }
                return true; 
            }
        } 
 
/* CONSIDER: Use this code when we switch to managed X509 API
        internal static int MapStatusToWin32Error(X509ChainStatusFlags status) 
        {
            switch (status)
            {
            case X509ChainStatusFlags.NoError:       return CertificateProblem.OK; 
            case X509ChainStatusFlags.NotTimeValid:  return CertificateProblem.CertEXPIRED;
            case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING; 
            case X509ChainStatusFlags.Revoked:       return CertificateProblem.CertREVOKED; 
            case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
            case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE; 
            case X509ChainStatusFlags.UntrustedRoot:    return CertificateProblem.CertUNTRUSTEDROOT;
            case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
            case X509ChainStatusFlags.Cyclic:           return CertificateProblem.CertCHAINING;             //??
            case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL;             //?? 
            case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
            case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS; 
            case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME; 
            case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
            case X509ChainStatusFlags.HasNotDefinedNameConstraint:   return CertificateProblem.CertINVALIDNAME; //?? 
            case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
            case X509ChainStatusFlags.HasExcludedNameConstraint:     return CertificateProblem.CertINVALIDNAME; //??
            case X509ChainStatusFlags.PartialChain:         return CertificateProblem.CertCHAINING;             //??
            case X509ChainStatusFlags.CtlNotTimeValid:      return CertificateProblem.CertEXPIRED; 
            case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
            case X509ChainStatusFlags.CtlNotValidForUsage:  return CertificateProblem.CertWRONG_USAGE; 
            case X509ChainStatusFlags.OfflineRevocation:    return CertificateProblem.CryptREVOCATIONOFFLINE; 
            case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
            default: return (int) CertificateProblem.TrustSYSTEMERROR;  // unknown 
            }
        }
***/
    } 
    // Class implementing default certificate policy
    internal class DefaultCertPolicy : ICertificatePolicy { 
        public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) { 
            return problem == (int)CertificateProblem.OK;
        } 
    }
#endif // !FEATURE_PAL

    internal enum TriState { 
        Unspecified = -1,
        False = 0, 
        True = 1 
    }
 
    internal enum DefaultPorts {
        DEFAULT_FTP_PORT = 21,
        DEFAULT_GOPHER_PORT = 70,
        DEFAULT_HTTP_PORT = 80, 
        DEFAULT_HTTPS_PORT = 443,
        DEFAULT_NNTP_PORT = 119, 
        DEFAULT_SMTP_PORT = 25, 
        DEFAULT_TELNET_PORT = 23
    } 

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    internal struct hostent {
        public IntPtr   h_name; 
        public IntPtr   h_aliases;
        public short    h_addrtype; 
        public short    h_length; 
        public IntPtr   h_addr_list;
    } 


    [StructLayout(LayoutKind.Sequential)]
    internal struct Blob { 
        public int cbSize;
        public int pBlobData; 
    } 

 
    // This is only for internal code path i.e. TLS stream.
    // See comments on GetNextBuffer() method below.
    //
    internal class SplitWritesState 
    {
        private const int c_SplitEncryptedBuffersSize = 64*1024; 
        private BufferOffsetSize[] _UserBuffers; 
        private int _Index;
        private int _LastBufferConsumed; 
        private BufferOffsetSize[] _RealBuffers;

        //
        internal SplitWritesState(BufferOffsetSize[] buffers) 
        {
            _UserBuffers    = buffers; 
            _LastBufferConsumed = 0; 
            _Index          = 0;
            _RealBuffers = null; 
        }
        //
        // Everything was handled
        // 
        internal bool IsDone {
            get { 
                if (_LastBufferConsumed != 0) 
                    return false;
 
                for (int index = _Index ;index < _UserBuffers.Length; ++index)
                    if (_UserBuffers[index].Size != 0)
                        return false;
 
                return true;
            } 
        } 
        // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
        // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks 
        // up to c_SplitEncryptedBuffersSize total.
        // Note that upon return from here EncryptBuffers() may additonally split the input
        // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
        // 
        //  Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
        // 
        //  Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method 
        //
        internal BufferOffsetSize[] GetNextBuffers() 
        {
            int curIndex = _Index;
            int currentTotalSize = 0;
            int lastChunkSize = 0; 

            int  firstBufferConsumed = _LastBufferConsumed; 
 
            for ( ;_Index < _UserBuffers.Length; ++_Index)
            { 
                lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;

                currentTotalSize += lastChunkSize;
 
                if (currentTotalSize > c_SplitEncryptedBuffersSize)
                { 
                    lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize); 
                    currentTotalSize = c_SplitEncryptedBuffersSize;
                    break; 
                }

                lastChunkSize = 0;
                _LastBufferConsumed = 0; 
            }
 
            // Are we done done? 
            if (currentTotalSize == 0)
                return null; 

             // Do all buffers fit the limit?
            if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
                return _UserBuffers; 

            // We do have something to split and send out 
            int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1; 

            if (_RealBuffers == null || _RealBuffers.Length != buffersCount) 
                _RealBuffers = new BufferOffsetSize[buffersCount];

            int j = 0;
            for (; curIndex < _Index; ++curIndex) 
            {
                _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false); 
                firstBufferConsumed = 0; 
            }
 
            if (lastChunkSize != 0)
            {
                _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
                if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size) 
                {
                    ++_Index; 
                    _LastBufferConsumed = 0; 
                }
            } 

            return _RealBuffers;

        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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