1 //------------------------------------------------------------------------------
2 // <copyright file="Internal.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 using System.Reflection;
10 using System.Collections;
11 using System.Collections.Specialized;
12 using System.Globalization;
13 using System.Net.Sockets;
14 using System.Net.WebSockets;
15 using System.Runtime.InteropServices;
16 using System.Runtime.Versioning;
17 using System.Security.Authentication.ExtendedProtection;
18 using System.Security.Cryptography.X509Certificates;
19 using System.Security.Permissions;
20 using System.Diagnostics;
21 using System.Threading;
22 using System.Security;
23 using System.Net.Security;
24 using System.Net.NetworkInformation;
25 using System.Runtime.Serialization;
26 using Microsoft.Win32;
27 using System.Collections.Generic;
29 internal static class IntPtrHelper {
32 internal static IntPtr Add(IntPtr a, IntPtr b) {
33 return (IntPtr) ((long)a + (long)b);
36 internal static IntPtr Add(IntPtr a, int b) {
37 return (IntPtr) ((long)a + (long)b);
40 internal static long Subtract(IntPtr a, IntPtr b) {
41 return ((long)a - (long)b);
45 internal class InternalException : SystemException
47 internal InternalException()
49 GlobalLog.Assert("InternalException thrown.");
52 internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
53 base(serializationInfo, streamingContext)
57 internal static class NclUtilities
61 /// Indicates true if the threadpool is low on threads,
62 /// in this case we need to refuse to start new requests,
63 /// and avoid blocking.
66 internal static bool IsThreadPoolLow()
69 if (ComNetOS.IsAspNetServer)
75 int workerThreads, completionPortThreads;
76 ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
79 return workerThreads < 2 || (completionPortThreads < 2);
81 GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
82 return workerThreads < 2;
87 internal static bool HasShutdownStarted
91 return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
95 // This only works for context-destroying errors.
96 internal static bool IsCredentialFailure(SecurityStatus error)
98 return error == SecurityStatus.LogonDenied ||
99 error == SecurityStatus.UnknownCredentials ||
100 error == SecurityStatus.NoImpersonation ||
101 error == SecurityStatus.NoAuthenticatingAuthority ||
102 error == SecurityStatus.UntrustedRoot ||
103 error == SecurityStatus.CertExpired ||
104 error == SecurityStatus.SmartcardLogonRequired ||
105 error == SecurityStatus.BadBinding;
108 // This only works for context-destroying errors.
109 internal static bool IsClientFault(SecurityStatus error)
111 return error == SecurityStatus.InvalidToken ||
112 error == SecurityStatus.CannotPack ||
113 error == SecurityStatus.QopNotSupported ||
114 error == SecurityStatus.NoCredentials ||
115 error == SecurityStatus.MessageAltered ||
116 error == SecurityStatus.OutOfSequence ||
117 error == SecurityStatus.IncompleteMessage ||
118 error == SecurityStatus.IncompleteCredentials ||
119 error == SecurityStatus.WrongPrincipal ||
120 error == SecurityStatus.TimeSkew ||
121 error == SecurityStatus.IllegalMessage ||
122 error == SecurityStatus.CertUnknown ||
123 error == SecurityStatus.AlgorithmMismatch ||
124 error == SecurityStatus.SecurityQosFailed ||
125 error == SecurityStatus.UnsupportedPreauth;
129 // ContextRelativeDemand
130 // Allows easily demanding a permission against a given ExecutionContext.
131 // Have requested the CLR to provide this method on ExecutionContext.
132 private static volatile ContextCallback s_ContextRelativeDemandCallback;
134 internal static ContextCallback ContextRelativeDemandCallback
138 if (s_ContextRelativeDemandCallback == null)
139 s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
140 return s_ContextRelativeDemandCallback;
144 private static void DemandCallback(object state)
147 ((CodeAccessPermission) state).Demand();
151 // This is for checking if a hostname probably refers to this machine without going to DNS.
152 internal static bool GuessWhetherHostIsLoopback(string host)
154 string hostLower = host.ToLowerInvariant();
155 if (hostLower == "localhost" || hostLower == "loopback")
161 IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties();
162 string hostnameLower = ip.HostName.ToLowerInvariant();
163 return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant();
169 internal static bool IsFatal(Exception exception)
171 return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
174 // Need a fast cached list of local addresses for internal use.
175 private static volatile IPAddress[] _LocalAddresses;
176 private static object _LocalAddressesLock;
180 private static volatile NetworkAddressChangePolled s_AddressChange;
182 internal static IPAddress[] LocalAddresses
186 if (s_AddressChange != null && s_AddressChange.CheckAndReset())
188 return (_LocalAddresses = GetLocalAddresses());
191 if (_LocalAddresses != null)
193 return _LocalAddresses;
196 lock (LocalAddressesLock)
198 if (_LocalAddresses != null)
200 return _LocalAddresses;
203 s_AddressChange = new NetworkAddressChangePolled();
205 return (_LocalAddresses = GetLocalAddresses());
210 private static IPAddress[] GetLocalAddresses()
214 ArrayList collections = new ArrayList(16);
217 SafeLocalFree buffer = null;
218 GetAdaptersAddressesFlags gaaFlags = GetAdaptersAddressesFlags.SkipAnycast | GetAdaptersAddressesFlags.SkipMulticast |
219 GetAdaptersAddressesFlags.SkipFriendlyName | GetAdaptersAddressesFlags.SkipDnsServer;
221 uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, SafeLocalFree.Zero, ref size);
222 while (result == IpHelperErrors.ErrorBufferOverflow)
226 buffer = SafeLocalFree.LocalAlloc((int)size);
227 result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, buffer, ref size);
229 if (result == IpHelperErrors.Success)
231 IntPtr nextAdapter = buffer.DangerousGetHandle();
233 while (nextAdapter != IntPtr.Zero)
235 IpAdapterAddresses adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(
236 nextAdapter, typeof(IpAdapterAddresses));
238 if (adapterAddresses.firstUnicastAddress != IntPtr.Zero)
240 UnicastIPAddressInformationCollection coll =
241 SystemUnicastIPAddressInformation.MarshalUnicastIpAddressInformationCollection(
242 adapterAddresses.firstUnicastAddress);
244 collections.Add(coll);
247 nextAdapter = adapterAddresses.next;
259 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData)
261 throw new NetworkInformationException((int)result);
264 local = new IPAddress[total];
266 foreach (UnicastIPAddressInformationCollection coll in collections)
268 foreach (IPAddressInformation info in coll)
270 local[i++] = info.Address;
277 internal static bool IsAddressLocal(IPAddress ipAddress) {
278 IPAddress[] localAddresses = NclUtilities.LocalAddresses;
279 for (int i = 0; i < localAddresses.Length; i++)
281 if (ipAddress.Equals(localAddresses[i], false))
289 #else // !FEATURE_PAL
291 internal static bool IsAddressLocal(IPAddress ipAddress) {
292 IPAddress[] localAddresses = NclUtilities.LocalAddresses;
293 for (int i = 0; i < localAddresses.Length; i++)
295 if (ipAddress.Equals(localAddresses[i], false))
303 private const int HostNameBufferLength = 256;
304 internal static string _LocalDomainName;
306 // Copied from the old version of DNS.cs
307 // Returns a list of our local addresses by calling gethostbyname with null.
309 private static IPHostEntry GetLocalHost()
312 return Dns.GetHostByName (Dns.GetHostName ());
315 // IPv6 Changes: If IPv6 is enabled, we can't simply use the
316 // old IPv4 gethostbyname(null). Instead we need
317 // to do a more complete lookup.
319 if (Socket.SupportsIPv6)
322 // IPv6 enabled: use getaddrinfo() of the local host name
323 // to obtain this information. Need to get the machines
324 // name as well - do that here so that we don't need to
325 // Assert DNS permissions.
327 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
328 SocketError errorCode =
329 UnsafeNclNativeMethods.OSSOCK.gethostname(
331 HostNameBufferLength);
333 if (errorCode != SocketError.Success)
335 throw new SocketException();
338 return Dns.GetHostByName(hostname.ToString());
343 // IPv6 disabled: use gethostbyname() to obtain information.
345 IntPtr nativePointer =
346 UnsafeNclNativeMethods.OSSOCK.gethostbyname(
349 if (nativePointer == IntPtr.Zero)
351 throw new SocketException();
354 return Dns.NativeToHostEntry(nativePointer);
360 internal static IPAddress[] LocalAddresses
364 IPAddress[] local = _LocalAddresses;
370 lock (LocalAddressesLock)
372 local = _LocalAddresses;
378 List<IPAddress> localList = new List<IPAddress>();
382 IPHostEntry hostEntry = GetLocalHost();
383 if (hostEntry != null)
385 if (hostEntry.HostName != null)
387 int dot = hostEntry.HostName.IndexOf('.');
390 _LocalDomainName = hostEntry.HostName.Substring(dot);
394 IPAddress[] ipAddresses = hostEntry.AddressList;
395 if (ipAddresses != null)
397 foreach (IPAddress ipAddress in ipAddresses)
399 localList.Add(ipAddress);
408 local = new IPAddress[localList.Count];
410 foreach (IPAddress ipAddress in localList)
412 local[index] = ipAddress;
415 _LocalAddresses = local;
421 #endif // !FEATURE_PAL
423 private static object LocalAddressesLock
427 if (_LocalAddressesLock == null)
429 Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
431 return _LocalAddressesLock;
436 internal static class NclConstants
438 internal static readonly object Sentinel = new object();
439 internal static readonly object[] EmptyObjectArray = new object[0];
440 internal static readonly Uri[] EmptyUriArray = new Uri[0];
442 internal static readonly byte[] CRLF = new byte[] {(byte) '\r', (byte) '\n'};
443 internal static readonly byte[] ChunkTerminator = new byte[] {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'};
447 // A simple [....] point, useful for deferring work. Just an int value with helper methods.
448 // This is used by HttpWebRequest to syncronize Reads/Writes while waiting for a 100-Continue response.
450 internal struct InterlockedGate
454 // Not currently waiting for a response
455 internal const int Open = 0; // Initial state of gate.
456 // Starting the timer to wait for a response (async)
457 internal const int Triggering = 1; // Gate is being actively held by a thread - indeterminate state.
458 // Waiting for response
459 internal const int Triggered = 2; // The triggering event has occurred.
460 // Stopping the timer (got a response or timed out)
461 internal const int Signaling = 3;
462 // Got a response or timed out, may process the response.
463 internal const int Signaled = 4;
464 // Re/submitting data.
465 internal const int Completed = 5; // The gated event is done.
479 // Only call when all threads are guaranteed to be done with the gate.
480 internal void Reset()
485 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggered.
486 internal bool Trigger(bool exclusive)
488 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
489 if (exclusive && (gate == Triggering || gate == Triggered))
491 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
492 throw new InternalException();
497 // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation. This is useful to set up an invariant
498 // that must be ready by the time another thread closes the gate. Do not block between StartTrigger() and FinishTrigger(), just
499 // set up your state to be consistent. If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
502 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggering/ed.
503 internal bool StartTriggering(bool exclusive)
505 int gate = Interlocked.CompareExchange(ref m_State, Triggering, Open);
506 if (exclusive && (gate == Triggering || gate == Triggered))
508 GlobalLog.Assert("InterlockedGate::StartTriggering", "Gate already triggered.");
509 throw new InternalException();
514 // Gate must be held by StartTriggering().
515 internal void FinishTriggering()
517 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Triggering);
518 if (gate != Triggering)
520 GlobalLog.Assert("InterlockedGate::FinishTriggering", "Gate not Triggering.");
521 throw new InternalException();
525 // Use StartSignaling() and FinishSignaling() to signal the gate as a two step operation. This is useful to
526 // set up an invariant that must be ready by the time another thread closes the gate. Do not block between
527 // StartSignaling() and FinishSignaling(), just set up your state to be consistent. If this method returns
528 // true, FinishSignaling() *must* be called to avoid deadlock - do it in a finally.
530 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already Signaling/ed.
531 internal bool StartSignaling(bool exclusive)
533 int gate = Interlocked.CompareExchange(ref m_State, Signaling, Triggered);
534 if (exclusive && (gate == Signaling || gate == Signaled)) //
536 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already Signaled.");
537 throw new InternalException();
539 Debug.Assert(gate != Triggering, "Still Triggering");
540 return gate == Triggered;
543 // Gate must be held by StartSignaling().
544 internal void FinishSignaling()
546 int gate = Interlocked.CompareExchange(ref m_State, Signaled, Signaling);
547 if (gate != Signaling)
549 GlobalLog.Assert("InterlockedGate::FinishSignaling", "Gate not Signaling; " + gate);
550 throw new InternalException();
554 // Makes sure only one thread completes the opperation.
555 internal bool Complete()
557 int gate = Interlocked.CompareExchange(ref m_State, Completed, Signaled);
558 Debug.Assert(gate != Signaling, "Still Signaling");
559 return (gate == Signaled);
565 // A polling implementation of NetworkAddressChange.
567 internal class NetworkAddressChangePolled : IDisposable
569 private bool disposed;
570 private SafeCloseSocketAndEvent ipv4Socket = null;
571 private SafeCloseSocketAndEvent ipv6Socket = null;
574 internal unsafe NetworkAddressChangePolled()
576 Socket.InitializeSockets();
578 if (Socket.OSSupportsIPv4)
581 ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
582 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking);
585 if(Socket.OSSupportsIPv6){
587 ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
588 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking);
590 Setup(StartIPOptions.Both);
593 private unsafe void Setup(StartIPOptions startIPOptions)
596 SocketError errorCode;
599 if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){
600 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
601 ipv4Socket.DangerousGetHandle(),
602 (int) IOControlCode.AddressListChange,
605 SafeNativeOverlapped.Zero, IntPtr.Zero);
607 if (errorCode != SocketError.Success) {
608 NetworkInformationException exception = new NetworkInformationException();
609 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
615 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
616 if (errorCode != SocketError.Success) {
622 if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
623 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
624 ipv6Socket.DangerousGetHandle(),
625 (int) IOControlCode.AddressListChange,
628 SafeNativeOverlapped.Zero, IntPtr.Zero);
630 if (errorCode != SocketError.Success) {
631 NetworkInformationException exception = new NetworkInformationException();
632 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
638 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
639 if (errorCode != SocketError.Success) {
646 internal bool CheckAndReset()
651 StartIPOptions options = StartIPOptions.None;
653 if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){
654 options|= StartIPOptions.StartIPv4;
656 if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false))
658 options|= StartIPOptions.StartIPv6;
661 if(options != StartIPOptions.None){
671 public void Dispose()
676 if(ipv6Socket != null){
680 if(ipv4Socket != null){
690 #endif // FEATURE_PAL
695 internal static class ComNetOS
697 private const string OSInstallTypeRegKey = @"Software\Microsoft\Windows NT\CurrentVersion";
698 private const string OSInstallTypeRegKeyPath = @"HKEY_LOCAL_MACHINE\" + OSInstallTypeRegKey;
699 private const string OSInstallTypeRegName = "InstallationType";
700 private const string InstallTypeStringClient = "Client";
701 private const string InstallTypeStringServer = "Server";
702 private const string InstallTypeStringServerCore = "Server Core";
703 private const string InstallTypeStringEmbedded = "Embedded";
705 // Minimum support for Windows 2008 is assumed.
706 internal static readonly bool IsAspNetServer; // ie: running under ASP+
707 internal static readonly bool IsWin7orLater; // Is Windows 7 or later
708 internal static readonly bool IsWin7Sp1orLater; // Is Windows 7 Sp1 or later (2008 R2 Sp1+)
709 internal static readonly bool IsWin8orLater; // Is Windows 8 or later
710 internal static readonly WindowsInstallationType InstallationType; // e.g. Client, Server, Server Core
712 // We use it safe so assert
713 [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
714 [ResourceExposure(ResourceScope.None)]
715 [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
718 OperatingSystem operatingSystem = Environment.OSVersion;
720 GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString());
722 Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported");
725 // Detect ASP+ as a platform running under NT
730 IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
734 IsWin7orLater = (operatingSystem.Version >= new Version(6, 1));
736 IsWin7Sp1orLater = (operatingSystem.Version >= new Version(6, 1, 7601));
738 IsWin8orLater = (operatingSystem.Version >= new Version(6, 2));
740 InstallationType = GetWindowsInstallType();
741 if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType));
744 [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)]
745 private static WindowsInstallationType GetWindowsInstallType()
749 using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
751 string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string;
753 if (string.IsNullOrEmpty(installType))
755 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
756 return WindowsInstallationType.Unknown;
760 if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0)
762 return WindowsInstallationType.Client;
764 if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
766 return WindowsInstallationType.Server;
768 if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0)
770 return WindowsInstallationType.ServerCore;
772 if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
774 return WindowsInstallationType.Embedded;
777 if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType));
779 // Our default return is unknown when we don't recognize the SKU or if the registry value
780 // doesn't exist. As a result, the SKU-specific checks in System.Net will not limit the set
781 // of functionality available. This allows SKUs we are not aware of to use all of our
782 // functionality. Burden is on them to ensure that all our dependencies are present.
783 // The alternative would be for us to throw an exception here. If we did this, these other
784 // SKUs wouldn't be able to load this code and test their behavior. We would need to update
785 // this code to enable them to run.
786 return WindowsInstallationType.Unknown;
790 catch (UnauthorizedAccessException e)
792 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
793 return WindowsInstallationType.Unknown;
795 catch (SecurityException e)
797 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
798 return WindowsInstallationType.Unknown;
806 // support class for Validation related stuff.
808 internal static class ValidationHelper {
810 public static string [] EmptyArray = new string[0];
812 internal static readonly char[] InvalidMethodChars =
820 // invalid characters that cannot be found in a valid method-verb or http header
821 internal static readonly char[] InvalidParamChars =
846 public static string [] MakeEmptyArrayNull(string [] stringArray) {
847 if ( stringArray == null || stringArray.Length == 0 ) {
854 public static string MakeStringNull(string stringValue) {
855 if ( stringValue == null || stringValue.Length == 0) {
863 // Consider removing.
864 public static string MakeStringEmpty(string stringValue) {
865 if ( stringValue == null || stringValue.Length == 0) {
875 // Consider removing.
876 public static int HashCode(object objectValue) {
877 if (objectValue == null) {
880 return objectValue.GetHashCode();
886 public static string ExceptionMessage(Exception exception) {
887 if (exception==null) {
890 if (exception.InnerException==null) {
891 return exception.Message;
893 return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
896 public static string ToString(object objectValue) {
897 if (objectValue == null) {
899 } else if (objectValue is string && ((string)objectValue).Length==0) {
900 return "(string.empty)";
901 } else if (objectValue is Exception) {
902 return ExceptionMessage(objectValue as Exception);
903 } else if (objectValue is IntPtr) {
904 return "0x" + ((IntPtr)objectValue).ToString("x");
906 return objectValue.ToString();
909 public static string HashString(object objectValue) {
910 if (objectValue == null) {
912 } else if (objectValue is string && ((string)objectValue).Length==0) {
913 return "(string.empty)";
915 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
919 public static bool IsInvalidHttpString(string stringValue) {
920 return stringValue.IndexOfAny(InvalidParamChars)!=-1;
923 public static bool IsBlankString(string stringValue) {
924 return stringValue==null || stringValue.Length==0;
928 // Consider removing.
929 public static bool ValidateUInt32(long address) {
930 // on false, API should throw new ArgumentOutOfRangeException("address");
931 return address>=0x00000000 && address<=0xFFFFFFFF;
935 public static bool ValidateTcpPort(int port) {
936 // on false, API should throw new ArgumentOutOfRangeException("port");
937 return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort;
940 public static bool ValidateRange(int actual, int fromAllowed, int toAllowed) {
941 // on false, API should throw new ArgumentOutOfRangeException("argument");
942 return actual>=fromAllowed && actual<=toAllowed;
946 // Consider removing.
947 public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
948 // on false, API should throw new ArgumentOutOfRangeException("argument");
949 return actual>=fromAllowed && actual<=toAllowed;
953 // There are threading tricks a malicious app can use to create an ArraySegment with mismatched
954 // array/offset/count. Copy locally and make sure they're valid before using them.
955 internal static void ValidateSegment(ArraySegment<byte> segment) {
956 if (segment == null || segment.Array == null) {
957 throw new ArgumentNullException("segment");
959 // Length zero is explicitly allowed
960 if (segment.Offset < 0 || segment.Count < 0
961 || segment.Count > (segment.Array.Length - segment.Offset)) {
962 throw new ArgumentOutOfRangeException("segment");
967 internal static class ExceptionHelper
970 internal static readonly KeyContainerPermission KeyContainerPermissionOpen = new KeyContainerPermission(KeyContainerPermissionFlags.Open);
971 internal static readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
972 internal static readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
973 internal static readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
974 internal static readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
975 internal static readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
976 internal static readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
978 internal static NotImplementedException MethodNotImplementedException {
980 return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException));
984 internal static NotImplementedException PropertyNotImplementedException {
986 return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
990 internal static NotSupportedException MethodNotSupportedException {
992 return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException));
996 internal static NotSupportedException PropertyNotSupportedException {
998 return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException));
1002 internal static WebException IsolatedException {
1004 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
1008 internal static WebException RequestAbortedException {
1010 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
1014 internal static WebException CacheEntryNotFoundException {
1016 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
1020 internal static WebException RequestProhibitedByCachePolicyException {
1022 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1027 internal enum WindowsInstallationType
1036 internal enum SecurityStatus
1038 // Success / Informational
1040 ContinueNeeded = unchecked((int)0x00090312),
1041 CompleteNeeded = unchecked((int)0x00090313),
1042 CompAndContinue = unchecked((int)0x00090314),
1043 ContextExpired = unchecked((int)0x00090317),
1044 CredentialsNeeded = unchecked((int)0x00090320),
1045 Renegotiate = unchecked((int)0x00090321),
1048 OutOfMemory = unchecked((int)0x80090300),
1049 InvalidHandle = unchecked((int)0x80090301),
1050 Unsupported = unchecked((int)0x80090302),
1051 TargetUnknown = unchecked((int)0x80090303),
1052 InternalError = unchecked((int)0x80090304),
1053 PackageNotFound = unchecked((int)0x80090305),
1054 NotOwner = unchecked((int)0x80090306),
1055 CannotInstall = unchecked((int)0x80090307),
1056 InvalidToken = unchecked((int)0x80090308),
1057 CannotPack = unchecked((int)0x80090309),
1058 QopNotSupported = unchecked((int)0x8009030A),
1059 NoImpersonation = unchecked((int)0x8009030B),
1060 LogonDenied = unchecked((int)0x8009030C),
1061 UnknownCredentials = unchecked((int)0x8009030D),
1062 NoCredentials = unchecked((int)0x8009030E),
1063 MessageAltered = unchecked((int)0x8009030F),
1064 OutOfSequence = unchecked((int)0x80090310),
1065 NoAuthenticatingAuthority = unchecked((int)0x80090311),
1066 IncompleteMessage = unchecked((int)0x80090318),
1067 IncompleteCredentials = unchecked((int)0x80090320),
1068 BufferNotEnough = unchecked((int)0x80090321),
1069 WrongPrincipal = unchecked((int)0x80090322),
1070 TimeSkew = unchecked((int)0x80090324),
1071 UntrustedRoot = unchecked((int)0x80090325),
1072 IllegalMessage = unchecked((int)0x80090326),
1073 CertUnknown = unchecked((int)0x80090327),
1074 CertExpired = unchecked((int)0x80090328),
1075 AlgorithmMismatch = unchecked((int)0x80090331),
1076 SecurityQosFailed = unchecked((int)0x80090332),
1077 SmartcardLogonRequired = unchecked((int)0x8009033E),
1078 UnsupportedPreauth = unchecked((int)0x80090343),
1079 BadBinding = unchecked((int)0x80090346)
1082 internal enum ContentTypeValues {
1083 ChangeCipherSpec = 0x14,
1087 Unrecognized = 0xFF,
1090 internal enum ContextAttribute {
1092 // look into <sspi.h> and <schannel.h>
1099 //KeyInfo = 0x05, must not be used, see ConnectionInfo instead
1101 // SECPKG_ATTR_PROTO_INFO = 7,
1102 // SECPKG_ATTR_PASSWORD_EXPIRY = 8,
1103 // SECPKG_ATTR_SESSION_KEY = 9,
1105 // SECPKG_ATTR_USER_FLAGS = 11,
1106 NegotiationInfo = 0x0C,
1107 // SECPKG_ATTR_NATIVE_NAMES = 13,
1108 // SECPKG_ATTR_FLAGS = 14,
1109 // SECPKG_ATTR_USE_VALIDATED = 15,
1110 // SECPKG_ATTR_CREDENTIAL_NAME = 16,
1111 // SECPKG_ATTR_TARGET_INFORMATION = 17,
1112 // SECPKG_ATTR_ACCESS_TOKEN = 18,
1113 // SECPKG_ATTR_TARGET = 19,
1114 // SECPKG_ATTR_AUTHENTICATION_ID = 20,
1115 UniqueBindings = 0x19,
1116 EndpointBindings = 0x1A,
1117 ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27
1118 RemoteCertificate = 0x53,
1119 LocalCertificate = 0x54,
1121 IssuerListInfoEx = 0x59,
1122 ConnectionInfo = 0x5A,
1123 // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock
1124 // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr
1125 // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo
1126 // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData
1127 // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates
1128 // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy
1129 // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult
1130 // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group
1131 // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo
1132 // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo
1133 // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo
1134 // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures
1135 // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT
1136 UiInfo = 0x68, // sets SEcPkgContext_UiInfo
1139 internal enum Endianness {
1144 internal enum CredentialUse {
1150 internal enum BufferType {
1159 Padding = 0x09, // non-data padding
1161 ChannelBindings = 0x0E,
1163 ReadOnlyFlag = unchecked((int)0x80000000),
1164 ReadOnlyWithChecksum= 0x10000000
1167 internal enum ChainPolicyType {
1170 Authenticode_TS = 3,
1172 BasicConstraints = 5,
1176 internal enum IgnoreCertProblem {
1177 not_time_valid = 0x00000001,
1178 ctl_not_time_valid = 0x00000002,
1179 not_time_nested = 0x00000004,
1180 invalid_basic_constraints = 0x00000008,
1182 all_not_time_valid =
1184 ctl_not_time_valid |
1187 allow_unknown_ca = 0x00000010,
1188 wrong_usage = 0x00000020,
1189 invalid_name = 0x00000040,
1190 invalid_policy = 0x00000080,
1191 end_rev_unknown = 0x00000100,
1192 ctl_signer_rev_unknown = 0x00000200,
1193 ca_rev_unknown = 0x00000400,
1194 root_rev_unknown = 0x00000800,
1198 ctl_signer_rev_unknown |
1203 ctl_not_time_valid |
1205 invalid_basic_constraints |
1211 ctl_signer_rev_unknown |
1216 internal enum CertUsage {
1217 MatchTypeAnd = 0x00,
1223 [StructLayout(LayoutKind.Sequential)]
1224 internal unsafe struct ChainPolicyParameter {
1226 public uint dwFlags;
1227 public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1229 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1232 [StructLayout(LayoutKind.Sequential)]
1233 internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1235 [StructLayout(LayoutKind.Explicit)]
1237 [FieldOffset(0)] internal uint cbStruct; //DWORD
1238 [FieldOffset(0)] internal uint cbSize; //DWORD
1241 internal int dwAuthType; //DWORD
1242 internal uint fdwChecks; //DWORD
1243 internal char* pwszServerName; //WCHAR* // used to check against CN=xxxx
1245 internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1247 u.cbStruct = StructSize;
1248 u.cbSize = StructSize;
1249 //# define AUTHTYPE_CLIENT 1
1250 //# define AUTHTYPE_SERVER 2
1251 dwAuthType = amIServer? 1: 2;
1253 pwszServerName = null;
1255 static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1258 [StructLayout(LayoutKind.Sequential)]
1259 internal unsafe struct ChainPolicyStatus {
1261 public uint dwError;
1262 public uint lChainIndex;
1263 public uint lElementIndex;
1264 public void* pvExtraPolicyStatus;
1266 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1269 [StructLayout(LayoutKind.Sequential)]
1270 internal unsafe struct CertEnhKeyUse {
1272 public uint cUsageIdentifier;
1273 public void* rgpszUsageIdentifier;
1276 public override string ToString() {
1277 return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1282 [StructLayout(LayoutKind.Sequential)]
1283 internal struct CertUsageMatch {
1284 public CertUsage dwType;
1285 public CertEnhKeyUse Usage;
1287 public override string ToString() {
1288 return "dwType="+dwType.ToString()+" "+Usage.ToString();
1293 [StructLayout(LayoutKind.Sequential)]
1294 internal struct ChainParameters {
1296 public CertUsageMatch RequestedUsage;
1297 public CertUsageMatch RequestedIssuancePolicy;
1298 public uint UrlRetrievalTimeout;
1299 public int BoolCheckRevocationFreshnessTime;
1300 public uint RevocationFreshnessTime;
1303 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1305 public override string ToString() {
1306 return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1311 [StructLayout(LayoutKind.Sequential)]
1312 struct _CERT_CHAIN_ELEMENT
1315 public IntPtr pCertContext;
1316 // Since this structure is allocated by unmanaged code, we can
1317 // omit the fileds below since we don't need to access them
1318 // CERT_TRUST_STATUS TrustStatus;
1319 // IntPtr pRevocationInfo;
1320 // IntPtr pIssuanceUsage;
1321 // IntPtr pApplicationUsage;
1325 //[StructLayout(LayoutKind.Sequential)]
1326 //unsafe struct CryptoBlob {
1327 // // public uint cbData;
1328 // // public byte* pbData;
1329 // public uint dataSize;
1330 // public byte* dataBlob;
1333 // SecPkgContext_IssuerListInfoEx
1334 [StructLayout(LayoutKind.Sequential)]
1335 unsafe struct IssuerListInfoEx {
1336 public SafeHandle aIssuers;
1337 public uint cIssuers;
1339 public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1341 fixed(byte* voidPtr = nativeBuffer) {
1342 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1343 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1349 [StructLayout(LayoutKind.Sequential)]
1350 internal struct SecureCredential {
1353 typedef struct _SCHANNEL_CRED
1355 DWORD dwVersion; // always SCHANNEL_CRED_VERSION
1357 PCCERT_CONTEXT *paCred;
1358 HCERTSTORE hRootStore;
1361 struct _HMAPPER **aphMappers;
1363 DWORD cSupportedAlgs;
1364 ALG_ID * palgSupportedAlgs;
1366 DWORD grbitEnabledProtocols;
1367 DWORD dwMinimumCipherStrength;
1368 DWORD dwMaximumCipherStrength;
1369 DWORD dwSessionLifespan;
1372 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1375 public const int CurrentVersion = 0x4;
1380 // ptr to an array of pointers
1381 // There is a hack done with this field. AcquireCredentialsHandle requires an array of
1382 // certificate handles; we only ever use one. In order to avoid pinning a one element array,
1383 // we copy this value onto the stack, create a pointer on the stack to the copied value,
1384 // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
1385 // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not
1386 // supposed to be threadsafe.
1387 public IntPtr certContextArray;
1389 private readonly IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE
1390 public int cMappers;
1391 private readonly IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE
1392 public int cSupportedAlgs;
1393 private readonly IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE
1394 public SchProtocols grbitEnabledProtocols;
1395 public int dwMinimumCipherStrength;
1396 public int dwMaximumCipherStrength;
1397 public int dwSessionLifespan;
1398 public SecureCredential.Flags dwFlags;
1399 public int reserved;
1404 NoSystemMapper = 0x02,
1406 ValidateManual = 0x08,
1407 NoDefaultCred = 0x10,
1408 ValidateAuto = 0x20,
1409 UseStrongCrypto = 0x00400000,
1412 public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
1413 // default values required for a struct
1414 rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
1415 cCreds = cMappers = cSupportedAlgs = 0;
1417 if (policy == EncryptionPolicy.RequireEncryption) {
1418 // Prohibit null encryption cipher
1419 dwMinimumCipherStrength = 0;
1420 dwMaximumCipherStrength = 0;
1422 else if (policy == EncryptionPolicy.AllowNoEncryption) {
1423 // Allow null encryption cipher in addition to other ciphers
1424 dwMinimumCipherStrength = -1;
1425 dwMaximumCipherStrength = 0;
1427 else if (policy == EncryptionPolicy.NoEncryption) {
1428 // Suppress all encryption and require null encryption cipher only
1429 dwMinimumCipherStrength = -1;
1430 dwMaximumCipherStrength = -1;
1433 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1436 dwSessionLifespan = reserved = 0;
1437 this.version = version;
1439 grbitEnabledProtocols = protocols;
1440 if (certificate != null) {
1441 certContextArray = certificate.Handle;
1446 [System.Diagnostics.Conditional("TRAVE")]
1447 internal void DebugDump() {
1448 GlobalLog.Print("SecureCredential #"+GetHashCode());
1449 GlobalLog.Print(" version = " + version);
1450 GlobalLog.Print(" cCreds = " + cCreds);
1451 GlobalLog.Print(" certContextArray = " + String.Format("0x{0:x}", certContextArray));
1452 GlobalLog.Print(" rootStore = " + String.Format("0x{0:x}", rootStore));
1453 GlobalLog.Print(" cMappers = " + cMappers);
1454 GlobalLog.Print(" phMappers = " + String.Format("0x{0:x}", phMappers));
1455 GlobalLog.Print(" cSupportedAlgs = " + cSupportedAlgs);
1456 GlobalLog.Print(" palgSupportedAlgs = " + String.Format("0x{0:x}", palgSupportedAlgs));
1457 GlobalLog.Print(" grbitEnabledProtocols = " + String.Format("0x{0:x}", grbitEnabledProtocols));
1458 GlobalLog.Print(" dwMinimumCipherStrength = " + dwMinimumCipherStrength);
1459 GlobalLog.Print(" dwMaximumCipherStrength = " + dwMaximumCipherStrength);
1460 GlobalLog.Print(" dwSessionLifespan = " + String.Format("0x{0:x}", dwSessionLifespan));
1461 GlobalLog.Print(" dwFlags = " + String.Format("0x{0:x}", dwFlags));
1462 GlobalLog.Print(" reserved = " + String.Format("0x{0:x}", reserved));
1465 } // SecureCredential
1467 #endif // !FEATURE_PAL
1469 [StructLayout(LayoutKind.Sequential)]
1470 internal unsafe struct SecurityBufferStruct {
1472 public BufferType type;
1473 public IntPtr token;
1475 public static readonly int Size = sizeof(SecurityBufferStruct);
1478 internal class SecurityBuffer {
1480 public BufferType type;
1481 public byte[] token;
1482 public SafeHandle unmanagedToken;
1485 public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
1486 GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]");
1487 GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]");
1489 this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
1490 this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
1491 this.type = tokentype;
1492 this.token = size == 0 ? null : data;
1495 public SecurityBuffer(byte[] data, BufferType tokentype) {
1496 this.size = data == null ? 0 : data.Length;
1497 this.type = tokentype;
1498 this.token = size == 0 ? null : data;
1501 public SecurityBuffer(int size, BufferType tokentype) {
1502 GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1505 this.type = tokentype;
1506 this.token = size == 0 ? null : new byte[size];
1509 public SecurityBuffer(ChannelBinding binding) {
1510 this.size = (binding == null ? 0 : binding.Size);
1511 this.type = BufferType.ChannelBindings;
1512 this.unmanagedToken = binding;
1516 [StructLayout(LayoutKind.Sequential)]
1517 internal unsafe class SecurityBufferDescriptor {
1519 typedef struct _SecBufferDesc {
1522 PSecBuffer pBuffers;
1523 } SecBufferDesc, * PSecBufferDesc;
1525 public readonly int Version;
1526 public readonly int Count;
1527 public void* UnmanagedPointer;
1529 public SecurityBufferDescriptor(int count) {
1532 UnmanagedPointer = null;
1535 [System.Diagnostics.Conditional("TRAVE")]
1536 internal void DebugDump() {
1537 GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
1538 GlobalLog.Print(" version = " + Version);
1539 GlobalLog.Print(" count = " + Count);
1540 GlobalLog.Print(" securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x"));
1542 } // SecurityBufferDescriptor
1544 internal enum CertificateEncoding {
1546 X509AsnEncoding = unchecked((int)0x00000001),
1547 X509NdrEncoding = unchecked((int)0x00000002),
1548 Pkcs7AsnEncoding = unchecked((int)0x00010000),
1549 Pkcs7NdrEncoding = unchecked((int)0x00020000),
1550 AnyAsnEncoding = X509AsnEncoding|Pkcs7AsnEncoding
1553 internal enum CertificateProblem {
1555 TrustNOSIGNATURE = unchecked((int)0x800B0100),
1556 CertEXPIRED = unchecked((int)0x800B0101),
1557 CertVALIDITYPERIODNESTING = unchecked((int)0x800B0102),
1558 CertROLE = unchecked((int)0x800B0103),
1559 CertPATHLENCONST = unchecked((int)0x800B0104),
1560 CertCRITICAL = unchecked((int)0x800B0105),
1561 CertPURPOSE = unchecked((int)0x800B0106),
1562 CertISSUERCHAINING = unchecked((int)0x800B0107),
1563 CertMALFORMED = unchecked((int)0x800B0108),
1564 CertUNTRUSTEDROOT = unchecked((int)0x800B0109),
1565 CertCHAINING = unchecked((int)0x800B010A),
1566 CertREVOKED = unchecked((int)0x800B010C),
1567 CertUNTRUSTEDTESTROOT = unchecked((int)0x800B010D),
1568 CertREVOCATION_FAILURE = unchecked((int)0x800B010E),
1569 CertCN_NO_MATCH = unchecked((int)0x800B010F),
1570 CertWRONG_USAGE = unchecked((int)0x800B0110),
1571 TrustEXPLICITDISTRUST = unchecked((int)0x800B0111),
1572 CertUNTRUSTEDCA = unchecked((int)0x800B0112),
1573 CertINVALIDPOLICY = unchecked((int)0x800B0113),
1574 CertINVALIDNAME = unchecked((int)0x800B0114),
1576 CryptNOREVOCATIONCHECK = unchecked((int)0x80092012),
1577 CryptREVOCATIONOFFLINE = unchecked((int)0x80092013),
1579 TrustSYSTEMERROR = unchecked((int)0x80096001),
1580 TrustNOSIGNERCERT = unchecked((int)0x80096002),
1581 TrustCOUNTERSIGNER = unchecked((int)0x80096003),
1582 TrustCERTSIGNATURE = unchecked((int)0x80096004),
1583 TrustTIMESTAMP = unchecked((int)0x80096005),
1584 TrustBADDIGEST = unchecked((int)0x80096010),
1585 TrustBASICCONSTRAINTS = unchecked((int)0x80096019),
1586 TrustFINANCIALCRITERIA = unchecked((int)0x8009601E),
1589 [StructLayout(LayoutKind.Sequential)]
1590 internal class SecChannelBindings
1592 internal int dwInitiatorAddrType;
1593 internal int cbInitiatorLength;
1594 internal int dwInitiatorOffset;
1596 internal int dwAcceptorAddrType;
1597 internal int cbAcceptorLength;
1598 internal int dwAcceptorOffset;
1600 internal int cbApplicationDataLength;
1601 internal int dwApplicationDataOffset;
1605 // WebRequestPrefixElement
1607 // This is an element of the prefix list. It contains the prefix and the
1608 // interface to be called to create a request for that prefix.
1612 /// <para>[To be supplied.]</para>
1614 // internal class WebRequestPrefixElement {
1615 internal class WebRequestPrefixElement {
1618 /// <para>[To be supplied.]</para>
1620 public string Prefix;
1622 /// <para>[To be supplied.]</para>
1624 internal IWebRequestCreate creator;
1626 /// <para>[To be supplied.]</para>
1628 internal Type creatorType;
1630 public IWebRequestCreate Creator {
1632 if (creator == null && creatorType != null) {
1634 if (creator == null) {
1635 creator = (IWebRequestCreate)Activator.CreateInstance(
1637 BindingFlags.CreateInstance
1638 | BindingFlags.Instance
1639 | BindingFlags.NonPublic
1640 | BindingFlags.Public,
1642 new object[0], // no arguments
1643 CultureInfo.InvariantCulture
1657 public WebRequestPrefixElement(string P, Type creatorType) {
1658 // verify that its of the proper type of IWebRequestCreate
1659 if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1661 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1662 creatorType.AssemblyQualifiedName,
1663 "IWebRequestCreate"));
1667 this.creatorType = creatorType;
1671 /// <para>[To be supplied.]</para>
1673 public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1678 } // class PrefixListElement
1681 #if MONO_FEATURE_WEB_STACK
1684 // HttpRequestCreator.
1686 // This is the class that we use to create HTTP and HTTPS requests.
1689 internal class HttpRequestCreator : IWebRequestCreate {
1693 Create - Create an HttpWebRequest.
1695 This is our method to create an HttpWebRequest. We register
1696 for HTTP and HTTPS Uris, and this method is called when a request
1697 needs to be created for one of those.
1701 Uri - Uri for request being created.
1704 The newly created HttpWebRequest.
1708 public WebRequest Create( Uri Uri ) {
1710 // Note, DNS permissions check will not happen on WebRequest
1712 return new HttpWebRequest(Uri, null);
1715 } // class HttpRequestCreator
1718 // WebSocketHttpRequestCreator.
1720 // This is the class that we use to create WebSocket connection requests.
1723 internal class WebSocketHttpRequestCreator : IWebRequestCreate
1725 private string m_httpScheme;
1727 // This ctor is used to create a WebSocketHttpRequestCreator.
1728 // We will do a URI change to update the scheme with Http or Https scheme. The usingHttps boolean is
1729 // used to indicate whether the created HttpWebRequest should take the https scheme or not.
1730 public WebSocketHttpRequestCreator(bool usingHttps)
1732 m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1737 Create - Create an HttpWebRequest.
1739 This is our method to create an HttpWebRequest for WebSocket connection. We register
1740 We will register it for custom Uri prefixes. And this method is called when a request
1741 needs to be created for one of those. The created HttpWebRequest will still be with Http or Https
1742 scheme, depending on the m_httpScheme field of this object.
1746 Uri - Uri for request being created.
1749 The newly created HttpWebRequest for WebSocket connection.
1753 public WebRequest Create(Uri Uri)
1755 UriBuilder uriBuilder = new UriBuilder(Uri);
1756 uriBuilder.Scheme = m_httpScheme;
1757 HttpWebRequest request = new HttpWebRequest(uriBuilder.Uri, null, true, "WebSocket" + Guid.NewGuid());
1758 WebSocketHelpers.PrepareWebRequest(ref request);
1762 } // class WebSocketHttpRequestCreator
1768 // CoreResponseData - Used to store result of HTTP header parsing and
1769 // response parsing. Also Contains new stream to use, and
1770 // is used as core of new Response
1772 internal class CoreResponseData {
1774 // Status Line Response Values
1775 public HttpStatusCode m_StatusCode;
1776 public string m_StatusDescription;
1777 public bool m_IsVersionHttp11;
1779 // Content Length needed for semantics, -1 if chunked
1780 public long m_ContentLength;
1783 public WebHeaderCollection m_ResponseHeaders;
1785 // ConnectStream - for reading actual data
1786 public Stream m_ConnectStream;
1788 internal CoreResponseData Clone() {
1789 CoreResponseData cloneResponseData = new CoreResponseData();
1790 cloneResponseData.m_StatusCode = m_StatusCode;
1791 cloneResponseData.m_StatusDescription = m_StatusDescription;
1792 cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11;
1793 cloneResponseData.m_ContentLength = m_ContentLength;
1794 cloneResponseData.m_ResponseHeaders = m_ResponseHeaders;
1795 cloneResponseData.m_ConnectStream = m_ConnectStream;
1796 return cloneResponseData;
1803 internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1806 // this class contains known header names
1809 internal static class HttpKnownHeaderNames {
1811 public const string CacheControl = "Cache-Control";
1812 public const string Connection = "Connection";
1813 public const string Date = "Date";
1814 public const string KeepAlive = "Keep-Alive";
1815 public const string Pragma = "Pragma";
1816 public const string ProxyConnection = "Proxy-Connection";
1817 public const string Trailer = "Trailer";
1818 public const string TransferEncoding = "Transfer-Encoding";
1819 public const string Upgrade = "Upgrade";
1820 public const string Via = "Via";
1821 public const string Warning = "Warning";
1822 public const string ContentLength = "Content-Length";
1823 public const string ContentType = "Content-Type";
1824 public const string ContentDisposition = "Content-Disposition";
1825 public const string ContentEncoding = "Content-Encoding";
1826 public const string ContentLanguage = "Content-Language";
1827 public const string ContentLocation = "Content-Location";
1828 public const string ContentRange = "Content-Range";
1829 public const string Expires = "Expires";
1830 public const string LastModified = "Last-Modified";
1831 public const string Age = "Age";
1832 public const string Location = "Location";
1833 public const string ProxyAuthenticate = "Proxy-Authenticate";
1834 public const string RetryAfter = "Retry-After";
1835 public const string Server = "Server";
1836 public const string SetCookie = "Set-Cookie";
1837 public const string SetCookie2 = "Set-Cookie2";
1838 public const string Vary = "Vary";
1839 public const string WWWAuthenticate = "WWW-Authenticate";
1840 public const string Accept = "Accept";
1841 public const string AcceptCharset = "Accept-Charset";
1842 public const string AcceptEncoding = "Accept-Encoding";
1843 public const string AcceptLanguage = "Accept-Language";
1844 public const string Authorization = "Authorization";
1845 public const string Cookie = "Cookie";
1846 public const string Cookie2 = "Cookie2";
1847 public const string Expect = "Expect";
1848 public const string From = "From";
1849 public const string Host = "Host";
1850 public const string IfMatch = "If-Match";
1851 public const string IfModifiedSince = "If-Modified-Since";
1852 public const string IfNoneMatch = "If-None-Match";
1853 public const string IfRange = "If-Range";
1854 public const string IfUnmodifiedSince = "If-Unmodified-Since";
1855 public const string MaxForwards = "Max-Forwards";
1856 public const string ProxyAuthorization = "Proxy-Authorization";
1857 public const string Referer = "Referer";
1858 public const string Range = "Range";
1859 public const string UserAgent = "User-Agent";
1860 public const string ContentMD5 = "Content-MD5";
1861 public const string ETag = "ETag";
1862 public const string TE = "TE";
1863 public const string Allow = "Allow";
1864 public const string AcceptRanges = "Accept-Ranges";
1865 public const string P3P = "P3P";
1866 public const string XPoweredBy = "X-Powered-By";
1867 public const string XAspNetVersion = "X-AspNet-Version";
1868 public const string SecWebSocketKey = "Sec-WebSocket-Key";
1869 public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
1870 public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
1871 public const string Origin = "Origin";
1872 public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
1873 public const string SecWebSocketVersion = "Sec-WebSocket-Version";
1878 /// Represents the method that will notify callers when a continue has been
1879 /// received by the client.
1882 // Delegate type for us to notify callers when we receive a continue
1883 public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1886 // HttpWriteMode - used to control the way in which an entity Body is posted.
1888 enum HttpWriteMode {
1896 // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1897 delegate void UnlockConnectionDelegate();
1899 enum HttpBehaviour : byte {
1902 HTTP11PartiallyCompliant = 2,
1906 internal enum HttpProcessingResult {
1913 // HttpVerb - used to define various per Verb Properties
1917 // Note - this is a place holder for Verb properties,
1918 // the following two bools can most likely be combined into
1919 // a single Enum type. And the Verb can be incorporated.
1921 class KnownHttpVerb {
1922 internal string Name; // verb name
1924 internal bool RequireContentBody; // require content body to be sent
1925 internal bool ContentBodyNotAllowed; // not allowed to send content body
1926 internal bool ConnectRequest; // special semantics for a connect request
1927 internal bool ExpectNoContentResponse; // response will not have content body
1929 internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1931 RequireContentBody = requireContentBody;
1932 ContentBodyNotAllowed = contentBodyNotAllowed;
1933 ConnectRequest = connectRequest;
1934 ExpectNoContentResponse = expectNoContentResponse;
1937 // Force an an init, before we use them
1938 private static ListDictionary NamedHeaders;
1941 internal static KnownHttpVerb Get;
1942 internal static KnownHttpVerb Connect;
1943 internal static KnownHttpVerb Head;
1944 internal static KnownHttpVerb Put;
1945 internal static KnownHttpVerb Post;
1946 internal static KnownHttpVerb MkCol;
1949 // InitializeKnownVerbs - Does basic init for this object,
1950 // such as creating defaultings and filling them
1952 static KnownHttpVerb() {
1953 NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
1954 Get = new KnownHttpVerb("GET", false, true, false, false);
1955 Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
1956 Head = new KnownHttpVerb("HEAD", false, true, false, true);
1957 Put = new KnownHttpVerb("PUT", true, false, false, false);
1958 Post = new KnownHttpVerb("POST", true, false, false, false);
1959 MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
1960 NamedHeaders[Get.Name] = Get;
1961 NamedHeaders[Connect.Name] = Connect;
1962 NamedHeaders[Head.Name] = Head;
1963 NamedHeaders[Put.Name] = Put;
1964 NamedHeaders[Post.Name] = Post;
1965 NamedHeaders[MkCol.Name] = MkCol;
1968 public bool Equals(KnownHttpVerb verb) {
1969 return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1972 public static KnownHttpVerb Parse(string name) {
1973 KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
1974 if (knownHttpVerb==null) {
1975 // unknown verb, default behaviour
1976 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
1978 return knownHttpVerb;
1983 // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1986 internal class HttpProtocolUtils {
1988 private HttpProtocolUtils() {
1992 // extra buffers for build/parsing, recv/send HTTP data,
1993 // at some point we should consolidate
1997 // parse String to DateTime format.
1998 internal static DateTime string2date(String S) {
2000 if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
2004 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
2009 // convert Date to String using RFC 1123 pattern
2010 internal static string date2string(DateTime D) {
2011 DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
2012 return D.ToUniversalTime().ToString("R", dateFormat);
2017 // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider
2018 internal class PolicyWrapper {
2019 private const uint IgnoreUnmatchedCN = 0x00001000;
2020 private ICertificatePolicy fwdPolicy;
2021 private ServicePoint srvPoint;
2022 private WebRequest request;
2024 internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2025 this.fwdPolicy = policy;
2030 public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2031 return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2034 internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
2035 GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags));
2036 ChainPolicyStatus status = new ChainPolicyStatus();
2037 status.cbSize = ChainPolicyStatus.StructSize;
2039 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2040 (IntPtr) ChainPolicyType.SSL,
2045 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2047 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2049 GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2050 return status.dwError;
2053 private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2054 switch ((CertificateProblem) errorCode) {
2056 case CertificateProblem.CertINVALIDNAME :
2057 case CertificateProblem.CertCN_NO_MATCH :
2058 return IgnoreCertProblem.invalid_name;
2060 case CertificateProblem.CertINVALIDPOLICY :
2061 case CertificateProblem.CertPURPOSE :
2062 return IgnoreCertProblem.invalid_policy;
2064 case CertificateProblem.CertEXPIRED :
2065 return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2067 case CertificateProblem.CertVALIDITYPERIODNESTING :
2068 return IgnoreCertProblem.not_time_nested;
2070 case CertificateProblem.CertCHAINING :
2071 case CertificateProblem.CertUNTRUSTEDCA :
2072 case CertificateProblem.CertUNTRUSTEDROOT :
2073 return IgnoreCertProblem.allow_unknown_ca;
2075 case CertificateProblem.CertREVOKED :
2076 case CertificateProblem.CertREVOCATION_FAILURE :
2077 case CertificateProblem.CryptNOREVOCATIONCHECK:
2078 case CertificateProblem.CryptREVOCATIONOFFLINE:
2079 return IgnoreCertProblem.all_rev_unknown;
2081 case CertificateProblem.CertROLE:
2082 case CertificateProblem.TrustBASICCONSTRAINTS:
2083 return IgnoreCertProblem.invalid_basic_constraints;
2085 case CertificateProblem.CertWRONG_USAGE :
2086 return IgnoreCertProblem.wrong_usage;
2094 private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2097 SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2098 ArrayList certificateProblems = new ArrayList();
2101 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2102 cppStruct.cbSize = ChainPolicyParameter.StructSize;
2103 cppStruct.dwFlags = 0;
2105 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2106 cppStruct.pvExtraPolicyPara = &eppStruct;
2108 fixed (char* namePtr = hostName) {
2109 if (ServicePointManager.CheckCertificateName){
2110 eppStruct.pwszServerName = namePtr;
2114 status = VerifyChainPolicy(chainContext, ref cppStruct);
2115 uint ignoreErrorMask = (uint)MapErrorCode(status);
2117 certificateProblems.Add(status);
2119 if (status == 0) { // No more problems with the certificate?
2120 break; // Then break out of the callback loop
2123 if (ignoreErrorMask == 0) { // Unrecognized error encountered
2128 cppStruct.dwFlags |= ignoreErrorMask;
2129 if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2130 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2137 return (uint[]) certificateProblems.ToArray(typeof(uint));
2140 internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2142 if (sslPolicyErrors == 0)
2143 return Accept(certificate, 0);
2145 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2146 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2148 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2149 (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2151 bool fatalError = false;
2152 uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2155 // By today design we cannot allow decider to ignore a fatal error.
2156 // This error is fatal.
2157 Accept(certificate, (int) SecurityStatus.InternalError);
2162 if (certificateProblems.Length == 0)
2163 return Accept(certificate, (int) CertificateProblem.OK);
2165 // Run each error through Accept().
2166 foreach (uint error in certificateProblems)
2167 if (!Accept(certificate, (int) error))
2174 /* CONSIDER: Use this code when we switch to managed X509 API
2175 internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2179 case X509ChainStatusFlags.NoError: return CertificateProblem.OK;
2180 case X509ChainStatusFlags.NotTimeValid: return CertificateProblem.CertEXPIRED;
2181 case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING;
2182 case X509ChainStatusFlags.Revoked: return CertificateProblem.CertREVOKED;
2183 case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
2184 case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2185 case X509ChainStatusFlags.UntrustedRoot: return CertificateProblem.CertUNTRUSTEDROOT;
2186 case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
2187 case X509ChainStatusFlags.Cyclic: return CertificateProblem.CertCHAINING; //??
2188 case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL; //??
2189 case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
2190 case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS;
2191 case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME;
2192 case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2193 case X509ChainStatusFlags.HasNotDefinedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2194 case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2195 case X509ChainStatusFlags.HasExcludedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2196 case X509ChainStatusFlags.PartialChain: return CertificateProblem.CertCHAINING; //??
2197 case X509ChainStatusFlags.CtlNotTimeValid: return CertificateProblem.CertEXPIRED;
2198 case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
2199 case X509ChainStatusFlags.CtlNotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2200 case X509ChainStatusFlags.OfflineRevocation: return CertificateProblem.CryptREVOCATIONOFFLINE;
2201 case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
2202 default: return (int) CertificateProblem.TrustSYSTEMERROR; // unknown
2207 // Class implementing default certificate policy
2208 internal class DefaultCertPolicy : ICertificatePolicy {
2209 public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) {
2210 return problem == (int)CertificateProblem.OK;
2213 #endif // !FEATURE_PAL
2215 internal enum TriState {
2221 internal enum DefaultPorts {
2222 DEFAULT_FTP_PORT = 21,
2223 DEFAULT_GOPHER_PORT = 70,
2224 DEFAULT_HTTP_PORT = 80,
2225 DEFAULT_HTTPS_PORT = 443,
2226 DEFAULT_NNTP_PORT = 119,
2227 DEFAULT_SMTP_PORT = 25,
2228 DEFAULT_TELNET_PORT = 23
2231 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
2232 internal struct hostent {
2233 public IntPtr h_name;
2234 public IntPtr h_aliases;
2235 public short h_addrtype;
2236 public short h_length;
2237 public IntPtr h_addr_list;
2241 [StructLayout(LayoutKind.Sequential)]
2242 internal struct Blob {
2244 public int pBlobData;
2248 // This is only for internal code path i.e. TLS stream.
2249 // See comments on GetNextBuffer() method below.
2251 internal class SplitWritesState
2253 private const int c_SplitEncryptedBuffersSize = 64*1024;
2254 private BufferOffsetSize[] _UserBuffers;
2256 private int _LastBufferConsumed;
2257 private BufferOffsetSize[] _RealBuffers;
2260 internal SplitWritesState(BufferOffsetSize[] buffers)
2262 _UserBuffers = buffers;
2263 _LastBufferConsumed = 0;
2265 _RealBuffers = null;
2268 // Everything was handled
2270 internal bool IsDone {
2272 if (_LastBufferConsumed != 0)
2275 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2276 if (_UserBuffers[index].Size != 0)
2282 // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
2283 // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
2284 // up to c_SplitEncryptedBuffersSize total.
2285 // Note that upon return from here EncryptBuffers() may additonally split the input
2286 // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
2288 // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2290 // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2292 internal BufferOffsetSize[] GetNextBuffers()
2294 int curIndex = _Index;
2295 int currentTotalSize = 0;
2296 int lastChunkSize = 0;
2298 int firstBufferConsumed = _LastBufferConsumed;
2300 for ( ;_Index < _UserBuffers.Length; ++_Index)
2302 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2304 currentTotalSize += lastChunkSize;
2306 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2308 lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2309 currentTotalSize = c_SplitEncryptedBuffersSize;
2314 _LastBufferConsumed = 0;
2317 // Are we done done?
2318 if (currentTotalSize == 0)
2321 // Do all buffers fit the limit?
2322 if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2323 return _UserBuffers;
2325 // We do have something to split and send out
2326 int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2328 if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2329 _RealBuffers = new BufferOffsetSize[buffersCount];
2332 for (; curIndex < _Index; ++curIndex)
2334 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2335 firstBufferConsumed = 0;
2338 if (lastChunkSize != 0)
2340 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2341 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2344 _LastBufferConsumed = 0;
2348 return _RealBuffers;