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;
28 internal static class IntPtrHelper {
31 internal static IntPtr Add(IntPtr a, IntPtr b) {
32 return (IntPtr) ((long)a + (long)b);
35 internal static IntPtr Add(IntPtr a, int b) {
36 return (IntPtr) ((long)a + (long)b);
39 internal static long Subtract(IntPtr a, IntPtr b) {
40 return ((long)a - (long)b);
44 internal class InternalException : SystemException
46 internal InternalException()
48 GlobalLog.Assert("InternalException thrown.");
51 internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
52 base(serializationInfo, streamingContext)
56 internal static class NclUtilities
60 /// Indicates true if the threadpool is low on threads,
61 /// in this case we need to refuse to start new requests,
62 /// and avoid blocking.
65 internal static bool IsThreadPoolLow()
68 if (ComNetOS.IsAspNetServer)
74 int workerThreads, completionPortThreads;
75 ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
78 return workerThreads < 2 || (completionPortThreads < 2);
80 GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
81 return workerThreads < 2;
86 internal static bool HasShutdownStarted
90 return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
94 // This only works for context-destroying errors.
95 internal static bool IsCredentialFailure(SecurityStatus error)
97 return error == SecurityStatus.LogonDenied ||
98 error == SecurityStatus.UnknownCredentials ||
99 error == SecurityStatus.NoImpersonation ||
100 error == SecurityStatus.NoAuthenticatingAuthority ||
101 error == SecurityStatus.UntrustedRoot ||
102 error == SecurityStatus.CertExpired ||
103 error == SecurityStatus.SmartcardLogonRequired ||
104 error == SecurityStatus.BadBinding;
107 // This only works for context-destroying errors.
108 internal static bool IsClientFault(SecurityStatus error)
110 return error == SecurityStatus.InvalidToken ||
111 error == SecurityStatus.CannotPack ||
112 error == SecurityStatus.QopNotSupported ||
113 error == SecurityStatus.NoCredentials ||
114 error == SecurityStatus.MessageAltered ||
115 error == SecurityStatus.OutOfSequence ||
116 error == SecurityStatus.IncompleteMessage ||
117 error == SecurityStatus.IncompleteCredentials ||
118 error == SecurityStatus.WrongPrincipal ||
119 error == SecurityStatus.TimeSkew ||
120 error == SecurityStatus.IllegalMessage ||
121 error == SecurityStatus.CertUnknown ||
122 error == SecurityStatus.AlgorithmMismatch ||
123 error == SecurityStatus.SecurityQosFailed ||
124 error == SecurityStatus.UnsupportedPreauth;
128 // ContextRelativeDemand
129 // Allows easily demanding a permission against a given ExecutionContext.
130 // Have requested the CLR to provide this method on ExecutionContext.
131 private static volatile ContextCallback s_ContextRelativeDemandCallback;
133 internal static ContextCallback ContextRelativeDemandCallback
137 if (s_ContextRelativeDemandCallback == null)
138 s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
139 return s_ContextRelativeDemandCallback;
143 private static void DemandCallback(object state)
145 ((CodeAccessPermission) state).Demand();
148 // This is for checking if a hostname probably refers to this machine without going to DNS.
149 internal static bool GuessWhetherHostIsLoopback(string host)
151 string hostLower = host.ToLowerInvariant();
152 if (hostLower == "localhost" || hostLower == "loopback")
158 IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties();
159 string hostnameLower = ip.HostName.ToLowerInvariant();
160 return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant();
166 internal static bool IsFatal(Exception exception)
168 return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
171 // Need a fast cached list of local addresses for internal use.
172 private static volatile IPAddress[] _LocalAddresses;
173 private static object _LocalAddressesLock;
175 #if MONO_NOT_IMPLEMENTED
178 private static volatile NetworkAddressChangePolled s_AddressChange;
180 internal static IPAddress[] LocalAddresses
184 if (s_AddressChange != null && s_AddressChange.CheckAndReset())
186 return (_LocalAddresses = GetLocalAddresses());
189 if (_LocalAddresses != null)
191 return _LocalAddresses;
194 lock (LocalAddressesLock)
196 if (_LocalAddresses != null)
198 return _LocalAddresses;
201 s_AddressChange = new NetworkAddressChangePolled();
203 return (_LocalAddresses = GetLocalAddresses());
208 private static IPAddress[] GetLocalAddresses()
212 ArrayList collections = new ArrayList(16);
215 SafeLocalFree buffer = null;
216 GetAdaptersAddressesFlags gaaFlags = GetAdaptersAddressesFlags.SkipAnycast | GetAdaptersAddressesFlags.SkipMulticast |
217 GetAdaptersAddressesFlags.SkipFriendlyName | GetAdaptersAddressesFlags.SkipDnsServer;
219 uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, SafeLocalFree.Zero, ref size);
220 while (result == IpHelperErrors.ErrorBufferOverflow)
224 buffer = SafeLocalFree.LocalAlloc((int)size);
225 result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, buffer, ref size);
227 if (result == IpHelperErrors.Success)
229 IntPtr nextAdapter = buffer.DangerousGetHandle();
231 while (nextAdapter != IntPtr.Zero)
233 IpAdapterAddresses adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(
234 nextAdapter, typeof(IpAdapterAddresses));
236 if (adapterAddresses.firstUnicastAddress != IntPtr.Zero)
238 UnicastIPAddressInformationCollection coll =
239 SystemUnicastIPAddressInformation.MarshalUnicastIpAddressInformationCollection(
240 adapterAddresses.firstUnicastAddress);
242 collections.Add(coll);
245 nextAdapter = adapterAddresses.next;
257 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData)
259 throw new NetworkInformationException((int)result);
262 local = new IPAddress[total];
264 foreach (UnicastIPAddressInformationCollection coll in collections)
266 foreach (IPAddressInformation info in coll)
268 local[i++] = info.Address;
275 internal static bool IsAddressLocal(IPAddress ipAddress) {
276 IPAddress[] localAddresses = NclUtilities.LocalAddresses;
277 for (int i = 0; i < localAddresses.Length; i++)
279 if (ipAddress.Equals(localAddresses[i], false))
287 #else // !FEATURE_PAL
288 private const int HostNameBufferLength = 256;
289 internal static string _LocalDomainName;
291 // Copied from the old version of DNS.cs
292 // Returns a list of our local addresses by calling gethostbyname with null.
294 private static IPHostEntry GetLocalHost()
297 // IPv6 Changes: If IPv6 is enabled, we can't simply use the
298 // old IPv4 gethostbyname(null). Instead we need
299 // to do a more complete lookup.
301 if (Socket.SupportsIPv6)
304 // IPv6 enabled: use getaddrinfo() of the local host name
305 // to obtain this information. Need to get the machines
306 // name as well - do that here so that we don't need to
307 // Assert DNS permissions.
309 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
310 SocketError errorCode =
311 UnsafeNclNativeMethods.OSSOCK.gethostname(
313 HostNameBufferLength);
315 if (errorCode != SocketError.Success)
317 throw new SocketException();
320 return Dns.GetHostByName(hostname.ToString());
325 // IPv6 disabled: use gethostbyname() to obtain information.
327 IntPtr nativePointer =
328 UnsafeNclNativeMethods.OSSOCK.gethostbyname(
331 if (nativePointer == IntPtr.Zero)
333 throw new SocketException();
336 return Dns.NativeToHostEntry(nativePointer);
341 internal static IPAddress[] LocalAddresses
345 IPAddress[] local = _LocalAddresses;
351 lock (LocalAddressesLock)
353 local = _LocalAddresses;
359 List<IPAddress> localList = new List<IPAddress>();
363 IPHostEntry hostEntry = GetLocalHost();
364 if (hostEntry != null)
366 if (hostEntry.HostName != null)
368 int dot = hostEntry.HostName.IndexOf('.');
371 _LocalDomainName = hostEntry.HostName.Substring(dot);
375 IPAddress[] ipAddresses = hostEntry.AddressList;
376 if (ipAddresses != null)
378 foreach (IPAddress ipAddress in ipAddresses)
380 localList.Add(ipAddress);
389 local = new IPAddress[localList.Count];
391 foreach (IPAddress ipAddress in localList)
393 local[index] = ipAddress;
396 _LocalAddresses = local;
402 #endif // !FEATURE_PAL
405 private static object LocalAddressesLock
409 if (_LocalAddressesLock == null)
411 Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
413 return _LocalAddressesLock;
418 internal static class NclConstants
420 internal static readonly object Sentinel = new object();
421 internal static readonly object[] EmptyObjectArray = new object[0];
422 internal static readonly Uri[] EmptyUriArray = new Uri[0];
424 internal static readonly byte[] CRLF = new byte[] {(byte) '\r', (byte) '\n'};
425 internal static readonly byte[] ChunkTerminator = new byte[] {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'};
429 // A simple [....] point, useful for deferring work. Just an int value with helper methods.
430 // This is used by HttpWebRequest to syncronize Reads/Writes while waiting for a 100-Continue response.
432 internal struct InterlockedGate
436 // Not currently waiting for a response
437 internal const int Open = 0; // Initial state of gate.
438 // Starting the timer to wait for a response (async)
439 internal const int Triggering = 1; // Gate is being actively held by a thread - indeterminate state.
440 // Waiting for response
441 internal const int Triggered = 2; // The triggering event has occurred.
442 // Stopping the timer (got a response or timed out)
443 internal const int Signaling = 3;
444 // Got a response or timed out, may process the response.
445 internal const int Signaled = 4;
446 // Re/submitting data.
447 internal const int Completed = 5; // The gated event is done.
461 // Only call when all threads are guaranteed to be done with the gate.
462 internal void Reset()
467 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggered.
468 internal bool Trigger(bool exclusive)
470 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
471 if (exclusive && (gate == Triggering || gate == Triggered))
473 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
474 throw new InternalException();
479 // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation. This is useful to set up an invariant
480 // that must be ready by the time another thread closes the gate. Do not block between StartTrigger() and FinishTrigger(), just
481 // set up your state to be consistent. If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
484 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already triggering/ed.
485 internal bool StartTriggering(bool exclusive)
487 int gate = Interlocked.CompareExchange(ref m_State, Triggering, Open);
488 if (exclusive && (gate == Triggering || gate == Triggered))
490 GlobalLog.Assert("InterlockedGate::StartTriggering", "Gate already triggered.");
491 throw new InternalException();
496 // Gate must be held by StartTriggering().
497 internal void FinishTriggering()
499 int gate = Interlocked.CompareExchange(ref m_State, Triggered, Triggering);
500 if (gate != Triggering)
502 GlobalLog.Assert("InterlockedGate::FinishTriggering", "Gate not Triggering.");
503 throw new InternalException();
507 // Use StartSignaling() and FinishSignaling() to signal the gate as a two step operation. This is useful to
508 // set up an invariant that must be ready by the time another thread closes the gate. Do not block between
509 // StartSignaling() and FinishSignaling(), just set up your state to be consistent. If this method returns
510 // true, FinishSignaling() *must* be called to avoid deadlock - do it in a finally.
512 // Returns false if the gate is not taken. If exclusive is true, throws if the gate is already Signaling/ed.
513 internal bool StartSignaling(bool exclusive)
515 int gate = Interlocked.CompareExchange(ref m_State, Signaling, Triggered);
516 if (exclusive && (gate == Signaling || gate == Signaled)) //
518 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already Signaled.");
519 throw new InternalException();
521 Debug.Assert(gate != Triggering, "Still Triggering");
522 return gate == Triggered;
525 // Gate must be held by StartSignaling().
526 internal void FinishSignaling()
528 int gate = Interlocked.CompareExchange(ref m_State, Signaled, Signaling);
529 if (gate != Signaling)
531 GlobalLog.Assert("InterlockedGate::FinishSignaling", "Gate not Signaling; " + gate);
532 throw new InternalException();
536 // Makes sure only one thread completes the opperation.
537 internal bool Complete()
539 int gate = Interlocked.CompareExchange(ref m_State, Completed, Signaled);
540 Debug.Assert(gate != Signaling, "Still Signaling");
541 return (gate == Signaled);
547 // A polling implementation of NetworkAddressChange.
549 internal class NetworkAddressChangePolled : IDisposable
551 private bool disposed;
552 private SafeCloseSocketAndEvent ipv4Socket = null;
553 private SafeCloseSocketAndEvent ipv6Socket = null;
556 internal unsafe NetworkAddressChangePolled()
558 Socket.InitializeSockets();
560 if (Socket.OSSupportsIPv4)
563 ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
564 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking);
567 if(Socket.OSSupportsIPv6){
569 ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
570 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking);
572 Setup(StartIPOptions.Both);
575 private unsafe void Setup(StartIPOptions startIPOptions)
578 SocketError errorCode;
581 if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){
582 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
583 ipv4Socket.DangerousGetHandle(),
584 (int) IOControlCode.AddressListChange,
587 SafeNativeOverlapped.Zero, IntPtr.Zero);
589 if (errorCode != SocketError.Success) {
590 NetworkInformationException exception = new NetworkInformationException();
591 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
597 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
598 if (errorCode != SocketError.Success) {
604 if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
605 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
606 ipv6Socket.DangerousGetHandle(),
607 (int) IOControlCode.AddressListChange,
610 SafeNativeOverlapped.Zero, IntPtr.Zero);
612 if (errorCode != SocketError.Success) {
613 NetworkInformationException exception = new NetworkInformationException();
614 if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
620 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
621 if (errorCode != SocketError.Success) {
628 internal bool CheckAndReset()
633 StartIPOptions options = StartIPOptions.None;
635 if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){
636 options|= StartIPOptions.StartIPv4;
638 if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false))
640 options|= StartIPOptions.StartIPv6;
643 if(options != StartIPOptions.None){
653 public void Dispose()
658 if(ipv6Socket != null){
662 if(ipv4Socket != null){
672 #endif // FEATURE_PAL
677 internal static class ComNetOS
679 private const string OSInstallTypeRegKey = @"Software\Microsoft\Windows NT\CurrentVersion";
680 private const string OSInstallTypeRegKeyPath = @"HKEY_LOCAL_MACHINE\" + OSInstallTypeRegKey;
681 private const string OSInstallTypeRegName = "InstallationType";
682 private const string InstallTypeStringClient = "Client";
683 private const string InstallTypeStringServer = "Server";
684 private const string InstallTypeStringServerCore = "Server Core";
685 private const string InstallTypeStringEmbedded = "Embedded";
687 // Minimum support for Windows 2008 is assumed.
688 internal static readonly bool IsAspNetServer; // ie: running under ASP+
689 internal static readonly bool IsWin7orLater; // Is Windows 7 or later
690 internal static readonly bool IsWin7Sp1orLater; // Is Windows 7 Sp1 or later (2008 R2 Sp1+)
691 internal static readonly bool IsWin8orLater; // Is Windows 8 or later
692 internal static readonly WindowsInstallationType InstallationType; // e.g. Client, Server, Server Core
694 // We use it safe so assert
695 [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
696 [ResourceExposure(ResourceScope.None)]
697 [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
700 OperatingSystem operatingSystem = Environment.OSVersion;
702 GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString());
704 Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported");
707 // Detect ASP+ as a platform running under NT
712 IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
716 IsWin7orLater = (operatingSystem.Version >= new Version(6, 1));
718 IsWin7Sp1orLater = (operatingSystem.Version >= new Version(6, 1, 7601));
720 IsWin8orLater = (operatingSystem.Version >= new Version(6, 2));
722 InstallationType = GetWindowsInstallType();
723 if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType));
726 [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)]
727 private static WindowsInstallationType GetWindowsInstallType()
731 using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
733 string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string;
735 if (string.IsNullOrEmpty(installType))
737 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
738 return WindowsInstallationType.Unknown;
742 if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0)
744 return WindowsInstallationType.Client;
746 if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
748 return WindowsInstallationType.Server;
750 if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0)
752 return WindowsInstallationType.ServerCore;
754 if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
756 return WindowsInstallationType.Embedded;
759 if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType));
761 // Our default return is unknown when we don't recognize the SKU or if the registry value
762 // doesn't exist. As a result, the SKU-specific checks in System.Net will not limit the set
763 // of functionality available. This allows SKUs we are not aware of to use all of our
764 // functionality. Burden is on them to ensure that all our dependencies are present.
765 // The alternative would be for us to throw an exception here. If we did this, these other
766 // SKUs wouldn't be able to load this code and test their behavior. We would need to update
767 // this code to enable them to run.
768 return WindowsInstallationType.Unknown;
772 catch (UnauthorizedAccessException e)
774 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
775 return WindowsInstallationType.Unknown;
777 catch (SecurityException e)
779 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
780 return WindowsInstallationType.Unknown;
788 // support class for Validation related stuff.
790 internal static class ValidationHelper {
792 public static string [] EmptyArray = new string[0];
794 internal static readonly char[] InvalidMethodChars =
802 // invalid characters that cannot be found in a valid method-verb or http header
803 internal static readonly char[] InvalidParamChars =
828 public static string [] MakeEmptyArrayNull(string [] stringArray) {
829 if ( stringArray == null || stringArray.Length == 0 ) {
836 public static string MakeStringNull(string stringValue) {
837 if ( stringValue == null || stringValue.Length == 0) {
845 // Consider removing.
846 public static string MakeStringEmpty(string stringValue) {
847 if ( stringValue == null || stringValue.Length == 0) {
857 // Consider removing.
858 public static int HashCode(object objectValue) {
859 if (objectValue == null) {
862 return objectValue.GetHashCode();
868 public static string ExceptionMessage(Exception exception) {
869 if (exception==null) {
872 if (exception.InnerException==null) {
873 return exception.Message;
875 return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
878 public static string ToString(object objectValue) {
879 if (objectValue == null) {
881 } else if (objectValue is string && ((string)objectValue).Length==0) {
882 return "(string.empty)";
883 } else if (objectValue is Exception) {
884 return ExceptionMessage(objectValue as Exception);
885 } else if (objectValue is IntPtr) {
886 return "0x" + ((IntPtr)objectValue).ToString("x");
888 return objectValue.ToString();
891 public static string HashString(object objectValue) {
892 if (objectValue == null) {
894 } else if (objectValue is string && ((string)objectValue).Length==0) {
895 return "(string.empty)";
897 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
901 public static bool IsInvalidHttpString(string stringValue) {
902 return stringValue.IndexOfAny(InvalidParamChars)!=-1;
905 public static bool IsBlankString(string stringValue) {
906 return stringValue==null || stringValue.Length==0;
910 // Consider removing.
911 public static bool ValidateUInt32(long address) {
912 // on false, API should throw new ArgumentOutOfRangeException("address");
913 return address>=0x00000000 && address<=0xFFFFFFFF;
917 public static bool ValidateTcpPort(int port) {
918 // on false, API should throw new ArgumentOutOfRangeException("port");
919 return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort;
922 public static bool ValidateRange(int actual, int fromAllowed, int toAllowed) {
923 // on false, API should throw new ArgumentOutOfRangeException("argument");
924 return actual>=fromAllowed && actual<=toAllowed;
928 // Consider removing.
929 public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
930 // on false, API should throw new ArgumentOutOfRangeException("argument");
931 return actual>=fromAllowed && actual<=toAllowed;
935 // There are threading tricks a malicious app can use to create an ArraySegment with mismatched
936 // array/offset/count. Copy locally and make sure they're valid before using them.
937 internal static void ValidateSegment(ArraySegment<byte> segment) {
938 if (segment == null || segment.Array == null) {
939 throw new ArgumentNullException("segment");
941 // Length zero is explicitly allowed
942 if (segment.Offset < 0 || segment.Count < 0
943 || segment.Count > (segment.Array.Length - segment.Offset)) {
944 throw new ArgumentOutOfRangeException("segment");
949 internal static class ExceptionHelper
952 internal static readonly KeyContainerPermission KeyContainerPermissionOpen = new KeyContainerPermission(KeyContainerPermissionFlags.Open);
953 internal static readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
954 internal static readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
955 internal static readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
956 internal static readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
957 internal static readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
958 internal static readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
960 internal static NotImplementedException MethodNotImplementedException {
962 return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException));
966 internal static NotImplementedException PropertyNotImplementedException {
968 return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
972 internal static NotSupportedException MethodNotSupportedException {
974 return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException));
978 internal static NotSupportedException PropertyNotSupportedException {
980 return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException));
984 internal static WebException IsolatedException {
986 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
990 internal static WebException RequestAbortedException {
992 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
996 internal static WebException CacheEntryNotFoundException {
998 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
1002 internal static WebException RequestProhibitedByCachePolicyException {
1004 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1009 internal enum WindowsInstallationType
1018 internal enum SecurityStatus
1020 // Success / Informational
1022 ContinueNeeded = unchecked((int)0x00090312),
1023 CompleteNeeded = unchecked((int)0x00090313),
1024 CompAndContinue = unchecked((int)0x00090314),
1025 ContextExpired = unchecked((int)0x00090317),
1026 CredentialsNeeded = unchecked((int)0x00090320),
1027 Renegotiate = unchecked((int)0x00090321),
1030 OutOfMemory = unchecked((int)0x80090300),
1031 InvalidHandle = unchecked((int)0x80090301),
1032 Unsupported = unchecked((int)0x80090302),
1033 TargetUnknown = unchecked((int)0x80090303),
1034 InternalError = unchecked((int)0x80090304),
1035 PackageNotFound = unchecked((int)0x80090305),
1036 NotOwner = unchecked((int)0x80090306),
1037 CannotInstall = unchecked((int)0x80090307),
1038 InvalidToken = unchecked((int)0x80090308),
1039 CannotPack = unchecked((int)0x80090309),
1040 QopNotSupported = unchecked((int)0x8009030A),
1041 NoImpersonation = unchecked((int)0x8009030B),
1042 LogonDenied = unchecked((int)0x8009030C),
1043 UnknownCredentials = unchecked((int)0x8009030D),
1044 NoCredentials = unchecked((int)0x8009030E),
1045 MessageAltered = unchecked((int)0x8009030F),
1046 OutOfSequence = unchecked((int)0x80090310),
1047 NoAuthenticatingAuthority = unchecked((int)0x80090311),
1048 IncompleteMessage = unchecked((int)0x80090318),
1049 IncompleteCredentials = unchecked((int)0x80090320),
1050 BufferNotEnough = unchecked((int)0x80090321),
1051 WrongPrincipal = unchecked((int)0x80090322),
1052 TimeSkew = unchecked((int)0x80090324),
1053 UntrustedRoot = unchecked((int)0x80090325),
1054 IllegalMessage = unchecked((int)0x80090326),
1055 CertUnknown = unchecked((int)0x80090327),
1056 CertExpired = unchecked((int)0x80090328),
1057 AlgorithmMismatch = unchecked((int)0x80090331),
1058 SecurityQosFailed = unchecked((int)0x80090332),
1059 SmartcardLogonRequired = unchecked((int)0x8009033E),
1060 UnsupportedPreauth = unchecked((int)0x80090343),
1061 BadBinding = unchecked((int)0x80090346)
1064 internal enum ContentTypeValues {
1065 ChangeCipherSpec = 0x14,
1069 Unrecognized = 0xFF,
1072 internal enum ContextAttribute {
1074 // look into <sspi.h> and <schannel.h>
1081 //KeyInfo = 0x05, must not be used, see ConnectionInfo instead
1083 // SECPKG_ATTR_PROTO_INFO = 7,
1084 // SECPKG_ATTR_PASSWORD_EXPIRY = 8,
1085 // SECPKG_ATTR_SESSION_KEY = 9,
1087 // SECPKG_ATTR_USER_FLAGS = 11,
1088 NegotiationInfo = 0x0C,
1089 // SECPKG_ATTR_NATIVE_NAMES = 13,
1090 // SECPKG_ATTR_FLAGS = 14,
1091 // SECPKG_ATTR_USE_VALIDATED = 15,
1092 // SECPKG_ATTR_CREDENTIAL_NAME = 16,
1093 // SECPKG_ATTR_TARGET_INFORMATION = 17,
1094 // SECPKG_ATTR_ACCESS_TOKEN = 18,
1095 // SECPKG_ATTR_TARGET = 19,
1096 // SECPKG_ATTR_AUTHENTICATION_ID = 20,
1097 UniqueBindings = 0x19,
1098 EndpointBindings = 0x1A,
1099 ClientSpecifiedSpn = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27
1100 RemoteCertificate = 0x53,
1101 LocalCertificate = 0x54,
1103 IssuerListInfoEx = 0x59,
1104 ConnectionInfo = 0x5A,
1105 // SECPKG_ATTR_EAP_KEY_BLOCK 0x5b // returns SecPkgContext_EapKeyBlock
1106 // SECPKG_ATTR_MAPPED_CRED_ATTR 0x5c // returns SecPkgContext_MappedCredAttr
1107 // SECPKG_ATTR_SESSION_INFO 0x5d // returns SecPkgContext_SessionInfo
1108 // SECPKG_ATTR_APP_DATA 0x5e // sets/returns SecPkgContext_SessionAppData
1109 // SECPKG_ATTR_REMOTE_CERTIFICATES 0x5F // returns SecPkgContext_Certificates
1110 // SECPKG_ATTR_CLIENT_CERT_POLICY 0x60 // sets SecPkgCred_ClientCertCtlPolicy
1111 // SECPKG_ATTR_CC_POLICY_RESULT 0x61 // returns SecPkgContext_ClientCertPolicyResult
1112 // SECPKG_ATTR_USE_NCRYPT 0x62 // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group
1113 // SECPKG_ATTR_LOCAL_CERT_INFO 0x63 // returns SecPkgContext_CertInfo
1114 // SECPKG_ATTR_CIPHER_INFO 0x64 // returns new CNG SecPkgContext_CipherInfo
1115 // SECPKG_ATTR_EAP_PRF_INFO 0x65 // sets SecPkgContext_EapPrfInfo
1116 // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66 // returns SecPkgContext_SupportedSignatures
1117 // SECPKG_ATTR_REMOTE_CERT_CHAIN 0x67 // returns PCCERT_CONTEXT
1118 UiInfo = 0x68, // sets SEcPkgContext_UiInfo
1121 internal enum Endianness {
1126 internal enum CredentialUse {
1132 internal enum BufferType {
1141 Padding = 0x09, // non-data padding
1143 ChannelBindings = 0x0E,
1145 ReadOnlyFlag = unchecked((int)0x80000000),
1146 ReadOnlyWithChecksum= 0x10000000
1149 internal enum ChainPolicyType {
1152 Authenticode_TS = 3,
1154 BasicConstraints = 5,
1158 internal enum IgnoreCertProblem {
1159 not_time_valid = 0x00000001,
1160 ctl_not_time_valid = 0x00000002,
1161 not_time_nested = 0x00000004,
1162 invalid_basic_constraints = 0x00000008,
1164 all_not_time_valid =
1166 ctl_not_time_valid |
1169 allow_unknown_ca = 0x00000010,
1170 wrong_usage = 0x00000020,
1171 invalid_name = 0x00000040,
1172 invalid_policy = 0x00000080,
1173 end_rev_unknown = 0x00000100,
1174 ctl_signer_rev_unknown = 0x00000200,
1175 ca_rev_unknown = 0x00000400,
1176 root_rev_unknown = 0x00000800,
1180 ctl_signer_rev_unknown |
1185 ctl_not_time_valid |
1187 invalid_basic_constraints |
1193 ctl_signer_rev_unknown |
1198 internal enum CertUsage {
1199 MatchTypeAnd = 0x00,
1205 [StructLayout(LayoutKind.Sequential)]
1206 internal unsafe struct ChainPolicyParameter {
1208 public uint dwFlags;
1209 public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1211 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1214 [StructLayout(LayoutKind.Sequential)]
1215 internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1217 [StructLayout(LayoutKind.Explicit)]
1219 [FieldOffset(0)] internal uint cbStruct; //DWORD
1220 [FieldOffset(0)] internal uint cbSize; //DWORD
1223 internal int dwAuthType; //DWORD
1224 internal uint fdwChecks; //DWORD
1225 internal char* pwszServerName; //WCHAR* // used to check against CN=xxxx
1227 internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1229 u.cbStruct = StructSize;
1230 u.cbSize = StructSize;
1231 //# define AUTHTYPE_CLIENT 1
1232 //# define AUTHTYPE_SERVER 2
1233 dwAuthType = amIServer? 1: 2;
1235 pwszServerName = null;
1237 static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1240 [StructLayout(LayoutKind.Sequential)]
1241 internal unsafe struct ChainPolicyStatus {
1243 public uint dwError;
1244 public uint lChainIndex;
1245 public uint lElementIndex;
1246 public void* pvExtraPolicyStatus;
1248 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1251 [StructLayout(LayoutKind.Sequential)]
1252 internal unsafe struct CertEnhKeyUse {
1254 public uint cUsageIdentifier;
1255 public void* rgpszUsageIdentifier;
1258 public override string ToString() {
1259 return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1264 [StructLayout(LayoutKind.Sequential)]
1265 internal struct CertUsageMatch {
1266 public CertUsage dwType;
1267 public CertEnhKeyUse Usage;
1269 public override string ToString() {
1270 return "dwType="+dwType.ToString()+" "+Usage.ToString();
1275 [StructLayout(LayoutKind.Sequential)]
1276 internal struct ChainParameters {
1278 public CertUsageMatch RequestedUsage;
1279 public CertUsageMatch RequestedIssuancePolicy;
1280 public uint UrlRetrievalTimeout;
1281 public int BoolCheckRevocationFreshnessTime;
1282 public uint RevocationFreshnessTime;
1285 public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1287 public override string ToString() {
1288 return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1293 [StructLayout(LayoutKind.Sequential)]
1294 struct _CERT_CHAIN_ELEMENT
1297 public IntPtr pCertContext;
1298 // Since this structure is allocated by unmanaged code, we can
1299 // omit the fileds below since we don't need to access them
1300 // CERT_TRUST_STATUS TrustStatus;
1301 // IntPtr pRevocationInfo;
1302 // IntPtr pIssuanceUsage;
1303 // IntPtr pApplicationUsage;
1307 //[StructLayout(LayoutKind.Sequential)]
1308 //unsafe struct CryptoBlob {
1309 // // public uint cbData;
1310 // // public byte* pbData;
1311 // public uint dataSize;
1312 // public byte* dataBlob;
1315 // SecPkgContext_IssuerListInfoEx
1316 [StructLayout(LayoutKind.Sequential)]
1317 unsafe struct IssuerListInfoEx {
1318 public SafeHandle aIssuers;
1319 public uint cIssuers;
1321 public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1323 fixed(byte* voidPtr = nativeBuffer) {
1324 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1325 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1331 [StructLayout(LayoutKind.Sequential)]
1332 internal struct SecureCredential {
1335 typedef struct _SCHANNEL_CRED
1337 DWORD dwVersion; // always SCHANNEL_CRED_VERSION
1339 PCCERT_CONTEXT *paCred;
1340 HCERTSTORE hRootStore;
1343 struct _HMAPPER **aphMappers;
1345 DWORD cSupportedAlgs;
1346 ALG_ID * palgSupportedAlgs;
1348 DWORD grbitEnabledProtocols;
1349 DWORD dwMinimumCipherStrength;
1350 DWORD dwMaximumCipherStrength;
1351 DWORD dwSessionLifespan;
1354 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1357 public const int CurrentVersion = 0x4;
1362 // ptr to an array of pointers
1363 // There is a hack done with this field. AcquireCredentialsHandle requires an array of
1364 // certificate handles; we only ever use one. In order to avoid pinning a one element array,
1365 // we copy this value onto the stack, create a pointer on the stack to the copied value,
1366 // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
1367 // Then we fix it up afterwards. Fine as long as all the SSPI credentials are not
1368 // supposed to be threadsafe.
1369 public IntPtr certContextArray;
1371 private readonly IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE
1372 public int cMappers;
1373 private readonly IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE
1374 public int cSupportedAlgs;
1375 private readonly IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE
1376 public SchProtocols grbitEnabledProtocols;
1377 public int dwMinimumCipherStrength;
1378 public int dwMaximumCipherStrength;
1379 public int dwSessionLifespan;
1380 public SecureCredential.Flags dwFlags;
1381 public int reserved;
1386 NoSystemMapper = 0x02,
1388 ValidateManual = 0x08,
1389 NoDefaultCred = 0x10,
1390 ValidateAuto = 0x20,
1391 UseStrongCrypto = 0x00400000,
1394 public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
1395 // default values required for a struct
1396 rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
1397 cCreds = cMappers = cSupportedAlgs = 0;
1399 if (policy == EncryptionPolicy.RequireEncryption) {
1400 // Prohibit null encryption cipher
1401 dwMinimumCipherStrength = 0;
1402 dwMaximumCipherStrength = 0;
1404 else if (policy == EncryptionPolicy.AllowNoEncryption) {
1405 // Allow null encryption cipher in addition to other ciphers
1406 dwMinimumCipherStrength = -1;
1407 dwMaximumCipherStrength = 0;
1409 else if (policy == EncryptionPolicy.NoEncryption) {
1410 // Suppress all encryption and require null encryption cipher only
1411 dwMinimumCipherStrength = -1;
1412 dwMaximumCipherStrength = -1;
1415 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1418 dwSessionLifespan = reserved = 0;
1419 this.version = version;
1421 grbitEnabledProtocols = protocols;
1422 if (certificate != null) {
1423 certContextArray = certificate.Handle;
1428 [System.Diagnostics.Conditional("TRAVE")]
1429 internal void DebugDump() {
1430 GlobalLog.Print("SecureCredential #"+GetHashCode());
1431 GlobalLog.Print(" version = " + version);
1432 GlobalLog.Print(" cCreds = " + cCreds);
1433 GlobalLog.Print(" certContextArray = " + String.Format("0x{0:x}", certContextArray));
1434 GlobalLog.Print(" rootStore = " + String.Format("0x{0:x}", rootStore));
1435 GlobalLog.Print(" cMappers = " + cMappers);
1436 GlobalLog.Print(" phMappers = " + String.Format("0x{0:x}", phMappers));
1437 GlobalLog.Print(" cSupportedAlgs = " + cSupportedAlgs);
1438 GlobalLog.Print(" palgSupportedAlgs = " + String.Format("0x{0:x}", palgSupportedAlgs));
1439 GlobalLog.Print(" grbitEnabledProtocols = " + String.Format("0x{0:x}", grbitEnabledProtocols));
1440 GlobalLog.Print(" dwMinimumCipherStrength = " + dwMinimumCipherStrength);
1441 GlobalLog.Print(" dwMaximumCipherStrength = " + dwMaximumCipherStrength);
1442 GlobalLog.Print(" dwSessionLifespan = " + String.Format("0x{0:x}", dwSessionLifespan));
1443 GlobalLog.Print(" dwFlags = " + String.Format("0x{0:x}", dwFlags));
1444 GlobalLog.Print(" reserved = " + String.Format("0x{0:x}", reserved));
1447 } // SecureCredential
1449 #endif // !FEATURE_PAL
1451 [StructLayout(LayoutKind.Sequential)]
1452 internal unsafe struct SecurityBufferStruct {
1454 public BufferType type;
1455 public IntPtr token;
1457 public static readonly int Size = sizeof(SecurityBufferStruct);
1460 internal class SecurityBuffer {
1462 public BufferType type;
1463 public byte[] token;
1464 public SafeHandle unmanagedToken;
1467 public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
1468 GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range. [" + offset + "]");
1469 GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range. [" + size + "]");
1471 this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
1472 this.size = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
1473 this.type = tokentype;
1474 this.token = size == 0 ? null : data;
1477 public SecurityBuffer(byte[] data, BufferType tokentype) {
1478 this.size = data == null ? 0 : data.Length;
1479 this.type = tokentype;
1480 this.token = size == 0 ? null : data;
1483 public SecurityBuffer(int size, BufferType tokentype) {
1484 GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range. [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1487 this.type = tokentype;
1488 this.token = size == 0 ? null : new byte[size];
1491 public SecurityBuffer(ChannelBinding binding) {
1492 this.size = (binding == null ? 0 : binding.Size);
1493 this.type = BufferType.ChannelBindings;
1494 this.unmanagedToken = binding;
1498 [StructLayout(LayoutKind.Sequential)]
1499 internal unsafe class SecurityBufferDescriptor {
1501 typedef struct _SecBufferDesc {
1504 PSecBuffer pBuffers;
1505 } SecBufferDesc, * PSecBufferDesc;
1507 public readonly int Version;
1508 public readonly int Count;
1509 public void* UnmanagedPointer;
1511 public SecurityBufferDescriptor(int count) {
1514 UnmanagedPointer = null;
1517 [System.Diagnostics.Conditional("TRAVE")]
1518 internal void DebugDump() {
1519 GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
1520 GlobalLog.Print(" version = " + Version);
1521 GlobalLog.Print(" count = " + Count);
1522 GlobalLog.Print(" securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x"));
1524 } // SecurityBufferDescriptor
1526 internal enum CertificateEncoding {
1528 X509AsnEncoding = unchecked((int)0x00000001),
1529 X509NdrEncoding = unchecked((int)0x00000002),
1530 Pkcs7AsnEncoding = unchecked((int)0x00010000),
1531 Pkcs7NdrEncoding = unchecked((int)0x00020000),
1532 AnyAsnEncoding = X509AsnEncoding|Pkcs7AsnEncoding
1535 internal enum CertificateProblem {
1537 TrustNOSIGNATURE = unchecked((int)0x800B0100),
1538 CertEXPIRED = unchecked((int)0x800B0101),
1539 CertVALIDITYPERIODNESTING = unchecked((int)0x800B0102),
1540 CertROLE = unchecked((int)0x800B0103),
1541 CertPATHLENCONST = unchecked((int)0x800B0104),
1542 CertCRITICAL = unchecked((int)0x800B0105),
1543 CertPURPOSE = unchecked((int)0x800B0106),
1544 CertISSUERCHAINING = unchecked((int)0x800B0107),
1545 CertMALFORMED = unchecked((int)0x800B0108),
1546 CertUNTRUSTEDROOT = unchecked((int)0x800B0109),
1547 CertCHAINING = unchecked((int)0x800B010A),
1548 CertREVOKED = unchecked((int)0x800B010C),
1549 CertUNTRUSTEDTESTROOT = unchecked((int)0x800B010D),
1550 CertREVOCATION_FAILURE = unchecked((int)0x800B010E),
1551 CertCN_NO_MATCH = unchecked((int)0x800B010F),
1552 CertWRONG_USAGE = unchecked((int)0x800B0110),
1553 TrustEXPLICITDISTRUST = unchecked((int)0x800B0111),
1554 CertUNTRUSTEDCA = unchecked((int)0x800B0112),
1555 CertINVALIDPOLICY = unchecked((int)0x800B0113),
1556 CertINVALIDNAME = unchecked((int)0x800B0114),
1558 CryptNOREVOCATIONCHECK = unchecked((int)0x80092012),
1559 CryptREVOCATIONOFFLINE = unchecked((int)0x80092013),
1561 TrustSYSTEMERROR = unchecked((int)0x80096001),
1562 TrustNOSIGNERCERT = unchecked((int)0x80096002),
1563 TrustCOUNTERSIGNER = unchecked((int)0x80096003),
1564 TrustCERTSIGNATURE = unchecked((int)0x80096004),
1565 TrustTIMESTAMP = unchecked((int)0x80096005),
1566 TrustBADDIGEST = unchecked((int)0x80096010),
1567 TrustBASICCONSTRAINTS = unchecked((int)0x80096019),
1568 TrustFINANCIALCRITERIA = unchecked((int)0x8009601E),
1571 [StructLayout(LayoutKind.Sequential)]
1572 internal class SecChannelBindings
1574 internal int dwInitiatorAddrType;
1575 internal int cbInitiatorLength;
1576 internal int dwInitiatorOffset;
1578 internal int dwAcceptorAddrType;
1579 internal int cbAcceptorLength;
1580 internal int dwAcceptorOffset;
1582 internal int cbApplicationDataLength;
1583 internal int dwApplicationDataOffset;
1587 // WebRequestPrefixElement
1589 // This is an element of the prefix list. It contains the prefix and the
1590 // interface to be called to create a request for that prefix.
1594 /// <para>[To be supplied.]</para>
1596 // internal class WebRequestPrefixElement {
1597 internal class WebRequestPrefixElement {
1600 /// <para>[To be supplied.]</para>
1602 public string Prefix;
1604 /// <para>[To be supplied.]</para>
1606 internal IWebRequestCreate creator;
1608 /// <para>[To be supplied.]</para>
1610 internal Type creatorType;
1612 public IWebRequestCreate Creator {
1614 if (creator == null && creatorType != null) {
1616 if (creator == null) {
1617 creator = (IWebRequestCreate)Activator.CreateInstance(
1619 BindingFlags.CreateInstance
1620 | BindingFlags.Instance
1621 | BindingFlags.NonPublic
1622 | BindingFlags.Public,
1624 new object[0], // no arguments
1625 CultureInfo.InvariantCulture
1639 public WebRequestPrefixElement(string P, Type creatorType) {
1640 // verify that its of the proper type of IWebRequestCreate
1641 if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1643 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1644 creatorType.AssemblyQualifiedName,
1645 "IWebRequestCreate"));
1649 this.creatorType = creatorType;
1653 /// <para>[To be supplied.]</para>
1655 public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1660 } // class PrefixListElement
1663 #if MONO_FEATURE_WEB_STACK
1666 // HttpRequestCreator.
1668 // This is the class that we use to create HTTP and HTTPS requests.
1671 internal class HttpRequestCreator : IWebRequestCreate {
1675 Create - Create an HttpWebRequest.
1677 This is our method to create an HttpWebRequest. We register
1678 for HTTP and HTTPS Uris, and this method is called when a request
1679 needs to be created for one of those.
1683 Uri - Uri for request being created.
1686 The newly created HttpWebRequest.
1690 public WebRequest Create( Uri Uri ) {
1692 // Note, DNS permissions check will not happen on WebRequest
1694 return new HttpWebRequest(Uri, null);
1697 } // class HttpRequestCreator
1700 // WebSocketHttpRequestCreator.
1702 // This is the class that we use to create WebSocket connection requests.
1705 internal class WebSocketHttpRequestCreator : IWebRequestCreate
1707 private string m_httpScheme;
1709 // This ctor is used to create a WebSocketHttpRequestCreator.
1710 // We will do a URI change to update the scheme with Http or Https scheme. The usingHttps boolean is
1711 // used to indicate whether the created HttpWebRequest should take the https scheme or not.
1712 public WebSocketHttpRequestCreator(bool usingHttps)
1714 m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1719 Create - Create an HttpWebRequest.
1721 This is our method to create an HttpWebRequest for WebSocket connection. We register
1722 We will register it for custom Uri prefixes. And this method is called when a request
1723 needs to be created for one of those. The created HttpWebRequest will still be with Http or Https
1724 scheme, depending on the m_httpScheme field of this object.
1728 Uri - Uri for request being created.
1731 The newly created HttpWebRequest for WebSocket connection.
1735 public WebRequest Create(Uri Uri)
1737 UriBuilder uriBuilder = new UriBuilder(Uri);
1738 uriBuilder.Scheme = m_httpScheme;
1739 HttpWebRequest request = new HttpWebRequest(uriBuilder.Uri, null, true, "WebSocket" + Guid.NewGuid());
1740 WebSocketHelpers.PrepareWebRequest(ref request);
1744 } // class WebSocketHttpRequestCreator
1750 // CoreResponseData - Used to store result of HTTP header parsing and
1751 // response parsing. Also Contains new stream to use, and
1752 // is used as core of new Response
1754 internal class CoreResponseData {
1756 // Status Line Response Values
1757 public HttpStatusCode m_StatusCode;
1758 public string m_StatusDescription;
1759 public bool m_IsVersionHttp11;
1761 // Content Length needed for semantics, -1 if chunked
1762 public long m_ContentLength;
1765 public WebHeaderCollection m_ResponseHeaders;
1767 // ConnectStream - for reading actual data
1768 public Stream m_ConnectStream;
1770 internal CoreResponseData Clone() {
1771 CoreResponseData cloneResponseData = new CoreResponseData();
1772 cloneResponseData.m_StatusCode = m_StatusCode;
1773 cloneResponseData.m_StatusDescription = m_StatusDescription;
1774 cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11;
1775 cloneResponseData.m_ContentLength = m_ContentLength;
1776 cloneResponseData.m_ResponseHeaders = m_ResponseHeaders;
1777 cloneResponseData.m_ConnectStream = m_ConnectStream;
1778 return cloneResponseData;
1785 internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1788 // this class contains known header names
1791 internal static class HttpKnownHeaderNames {
1793 public const string CacheControl = "Cache-Control";
1794 public const string Connection = "Connection";
1795 public const string Date = "Date";
1796 public const string KeepAlive = "Keep-Alive";
1797 public const string Pragma = "Pragma";
1798 public const string ProxyConnection = "Proxy-Connection";
1799 public const string Trailer = "Trailer";
1800 public const string TransferEncoding = "Transfer-Encoding";
1801 public const string Upgrade = "Upgrade";
1802 public const string Via = "Via";
1803 public const string Warning = "Warning";
1804 public const string ContentLength = "Content-Length";
1805 public const string ContentType = "Content-Type";
1806 public const string ContentDisposition = "Content-Disposition";
1807 public const string ContentEncoding = "Content-Encoding";
1808 public const string ContentLanguage = "Content-Language";
1809 public const string ContentLocation = "Content-Location";
1810 public const string ContentRange = "Content-Range";
1811 public const string Expires = "Expires";
1812 public const string LastModified = "Last-Modified";
1813 public const string Age = "Age";
1814 public const string Location = "Location";
1815 public const string ProxyAuthenticate = "Proxy-Authenticate";
1816 public const string RetryAfter = "Retry-After";
1817 public const string Server = "Server";
1818 public const string SetCookie = "Set-Cookie";
1819 public const string SetCookie2 = "Set-Cookie2";
1820 public const string Vary = "Vary";
1821 public const string WWWAuthenticate = "WWW-Authenticate";
1822 public const string Accept = "Accept";
1823 public const string AcceptCharset = "Accept-Charset";
1824 public const string AcceptEncoding = "Accept-Encoding";
1825 public const string AcceptLanguage = "Accept-Language";
1826 public const string Authorization = "Authorization";
1827 public const string Cookie = "Cookie";
1828 public const string Cookie2 = "Cookie2";
1829 public const string Expect = "Expect";
1830 public const string From = "From";
1831 public const string Host = "Host";
1832 public const string IfMatch = "If-Match";
1833 public const string IfModifiedSince = "If-Modified-Since";
1834 public const string IfNoneMatch = "If-None-Match";
1835 public const string IfRange = "If-Range";
1836 public const string IfUnmodifiedSince = "If-Unmodified-Since";
1837 public const string MaxForwards = "Max-Forwards";
1838 public const string ProxyAuthorization = "Proxy-Authorization";
1839 public const string Referer = "Referer";
1840 public const string Range = "Range";
1841 public const string UserAgent = "User-Agent";
1842 public const string ContentMD5 = "Content-MD5";
1843 public const string ETag = "ETag";
1844 public const string TE = "TE";
1845 public const string Allow = "Allow";
1846 public const string AcceptRanges = "Accept-Ranges";
1847 public const string P3P = "P3P";
1848 public const string XPoweredBy = "X-Powered-By";
1849 public const string XAspNetVersion = "X-AspNet-Version";
1850 public const string SecWebSocketKey = "Sec-WebSocket-Key";
1851 public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
1852 public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
1853 public const string Origin = "Origin";
1854 public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
1855 public const string SecWebSocketVersion = "Sec-WebSocket-Version";
1860 /// Represents the method that will notify callers when a continue has been
1861 /// received by the client.
1864 // Delegate type for us to notify callers when we receive a continue
1865 public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1868 // HttpWriteMode - used to control the way in which an entity Body is posted.
1870 enum HttpWriteMode {
1878 // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1879 delegate void UnlockConnectionDelegate();
1881 enum HttpBehaviour : byte {
1884 HTTP11PartiallyCompliant = 2,
1888 internal enum HttpProcessingResult {
1895 // HttpVerb - used to define various per Verb Properties
1899 // Note - this is a place holder for Verb properties,
1900 // the following two bools can most likely be combined into
1901 // a single Enum type. And the Verb can be incorporated.
1903 class KnownHttpVerb {
1904 internal string Name; // verb name
1906 internal bool RequireContentBody; // require content body to be sent
1907 internal bool ContentBodyNotAllowed; // not allowed to send content body
1908 internal bool ConnectRequest; // special semantics for a connect request
1909 internal bool ExpectNoContentResponse; // response will not have content body
1911 internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1913 RequireContentBody = requireContentBody;
1914 ContentBodyNotAllowed = contentBodyNotAllowed;
1915 ConnectRequest = connectRequest;
1916 ExpectNoContentResponse = expectNoContentResponse;
1919 // Force an an init, before we use them
1920 private static ListDictionary NamedHeaders;
1923 internal static KnownHttpVerb Get;
1924 internal static KnownHttpVerb Connect;
1925 internal static KnownHttpVerb Head;
1926 internal static KnownHttpVerb Put;
1927 internal static KnownHttpVerb Post;
1928 internal static KnownHttpVerb MkCol;
1931 // InitializeKnownVerbs - Does basic init for this object,
1932 // such as creating defaultings and filling them
1934 static KnownHttpVerb() {
1935 NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
1936 Get = new KnownHttpVerb("GET", false, true, false, false);
1937 Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
1938 Head = new KnownHttpVerb("HEAD", false, true, false, true);
1939 Put = new KnownHttpVerb("PUT", true, false, false, false);
1940 Post = new KnownHttpVerb("POST", true, false, false, false);
1941 MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
1942 NamedHeaders[Get.Name] = Get;
1943 NamedHeaders[Connect.Name] = Connect;
1944 NamedHeaders[Head.Name] = Head;
1945 NamedHeaders[Put.Name] = Put;
1946 NamedHeaders[Post.Name] = Post;
1947 NamedHeaders[MkCol.Name] = MkCol;
1950 public bool Equals(KnownHttpVerb verb) {
1951 return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1954 public static KnownHttpVerb Parse(string name) {
1955 KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
1956 if (knownHttpVerb==null) {
1957 // unknown verb, default behaviour
1958 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
1960 return knownHttpVerb;
1965 // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1968 internal class HttpProtocolUtils {
1970 private HttpProtocolUtils() {
1974 // extra buffers for build/parsing, recv/send HTTP data,
1975 // at some point we should consolidate
1979 // parse String to DateTime format.
1980 internal static DateTime string2date(String S) {
1982 if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
1986 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
1991 // convert Date to String using RFC 1123 pattern
1992 internal static string date2string(DateTime D) {
1993 DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
1994 return D.ToUniversalTime().ToString("R", dateFormat);
1999 // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider
2000 internal class PolicyWrapper {
2001 private const uint IgnoreUnmatchedCN = 0x00001000;
2002 private ICertificatePolicy fwdPolicy;
2003 private ServicePoint srvPoint;
2004 private WebRequest request;
2006 internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2007 this.fwdPolicy = policy;
2012 public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2013 return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2016 internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
2017 GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags));
2018 ChainPolicyStatus status = new ChainPolicyStatus();
2019 status.cbSize = ChainPolicyStatus.StructSize;
2021 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2022 (IntPtr) ChainPolicyType.SSL,
2027 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2029 GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2031 GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2032 return status.dwError;
2035 private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2036 switch ((CertificateProblem) errorCode) {
2038 case CertificateProblem.CertINVALIDNAME :
2039 case CertificateProblem.CertCN_NO_MATCH :
2040 return IgnoreCertProblem.invalid_name;
2042 case CertificateProblem.CertINVALIDPOLICY :
2043 case CertificateProblem.CertPURPOSE :
2044 return IgnoreCertProblem.invalid_policy;
2046 case CertificateProblem.CertEXPIRED :
2047 return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2049 case CertificateProblem.CertVALIDITYPERIODNESTING :
2050 return IgnoreCertProblem.not_time_nested;
2052 case CertificateProblem.CertCHAINING :
2053 case CertificateProblem.CertUNTRUSTEDCA :
2054 case CertificateProblem.CertUNTRUSTEDROOT :
2055 return IgnoreCertProblem.allow_unknown_ca;
2057 case CertificateProblem.CertREVOKED :
2058 case CertificateProblem.CertREVOCATION_FAILURE :
2059 case CertificateProblem.CryptNOREVOCATIONCHECK:
2060 case CertificateProblem.CryptREVOCATIONOFFLINE:
2061 return IgnoreCertProblem.all_rev_unknown;
2063 case CertificateProblem.CertROLE:
2064 case CertificateProblem.TrustBASICCONSTRAINTS:
2065 return IgnoreCertProblem.invalid_basic_constraints;
2067 case CertificateProblem.CertWRONG_USAGE :
2068 return IgnoreCertProblem.wrong_usage;
2076 private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2079 SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2080 ArrayList certificateProblems = new ArrayList();
2083 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2084 cppStruct.cbSize = ChainPolicyParameter.StructSize;
2085 cppStruct.dwFlags = 0;
2087 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2088 cppStruct.pvExtraPolicyPara = &eppStruct;
2090 fixed (char* namePtr = hostName) {
2091 if (ServicePointManager.CheckCertificateName){
2092 eppStruct.pwszServerName = namePtr;
2096 status = VerifyChainPolicy(chainContext, ref cppStruct);
2097 uint ignoreErrorMask = (uint)MapErrorCode(status);
2099 certificateProblems.Add(status);
2101 if (status == 0) { // No more problems with the certificate?
2102 break; // Then break out of the callback loop
2105 if (ignoreErrorMask == 0) { // Unrecognized error encountered
2110 cppStruct.dwFlags |= ignoreErrorMask;
2111 if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2112 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2119 return (uint[]) certificateProblems.ToArray(typeof(uint));
2122 internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2124 if (sslPolicyErrors == 0)
2125 return Accept(certificate, 0);
2127 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2128 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2130 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2131 (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2133 bool fatalError = false;
2134 uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2137 // By today design we cannot allow decider to ignore a fatal error.
2138 // This error is fatal.
2139 Accept(certificate, (int) SecurityStatus.InternalError);
2144 if (certificateProblems.Length == 0)
2145 return Accept(certificate, (int) CertificateProblem.OK);
2147 // Run each error through Accept().
2148 foreach (uint error in certificateProblems)
2149 if (!Accept(certificate, (int) error))
2156 /* CONSIDER: Use this code when we switch to managed X509 API
2157 internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2161 case X509ChainStatusFlags.NoError: return CertificateProblem.OK;
2162 case X509ChainStatusFlags.NotTimeValid: return CertificateProblem.CertEXPIRED;
2163 case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING;
2164 case X509ChainStatusFlags.Revoked: return CertificateProblem.CertREVOKED;
2165 case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
2166 case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2167 case X509ChainStatusFlags.UntrustedRoot: return CertificateProblem.CertUNTRUSTEDROOT;
2168 case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
2169 case X509ChainStatusFlags.Cyclic: return CertificateProblem.CertCHAINING; //??
2170 case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL; //??
2171 case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
2172 case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS;
2173 case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME;
2174 case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2175 case X509ChainStatusFlags.HasNotDefinedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2176 case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2177 case X509ChainStatusFlags.HasExcludedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2178 case X509ChainStatusFlags.PartialChain: return CertificateProblem.CertCHAINING; //??
2179 case X509ChainStatusFlags.CtlNotTimeValid: return CertificateProblem.CertEXPIRED;
2180 case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
2181 case X509ChainStatusFlags.CtlNotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2182 case X509ChainStatusFlags.OfflineRevocation: return CertificateProblem.CryptREVOCATIONOFFLINE;
2183 case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
2184 default: return (int) CertificateProblem.TrustSYSTEMERROR; // unknown
2189 // Class implementing default certificate policy
2190 internal class DefaultCertPolicy : ICertificatePolicy {
2191 public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) {
2192 return problem == (int)CertificateProblem.OK;
2195 #endif // !FEATURE_PAL
2197 internal enum TriState {
2203 internal enum DefaultPorts {
2204 DEFAULT_FTP_PORT = 21,
2205 DEFAULT_GOPHER_PORT = 70,
2206 DEFAULT_HTTP_PORT = 80,
2207 DEFAULT_HTTPS_PORT = 443,
2208 DEFAULT_NNTP_PORT = 119,
2209 DEFAULT_SMTP_PORT = 25,
2210 DEFAULT_TELNET_PORT = 23
2213 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
2214 internal struct hostent {
2215 public IntPtr h_name;
2216 public IntPtr h_aliases;
2217 public short h_addrtype;
2218 public short h_length;
2219 public IntPtr h_addr_list;
2223 [StructLayout(LayoutKind.Sequential)]
2224 internal struct Blob {
2226 public int pBlobData;
2230 // This is only for internal code path i.e. TLS stream.
2231 // See comments on GetNextBuffer() method below.
2233 internal class SplitWritesState
2235 private const int c_SplitEncryptedBuffersSize = 64*1024;
2236 private BufferOffsetSize[] _UserBuffers;
2238 private int _LastBufferConsumed;
2239 private BufferOffsetSize[] _RealBuffers;
2242 internal SplitWritesState(BufferOffsetSize[] buffers)
2244 _UserBuffers = buffers;
2245 _LastBufferConsumed = 0;
2247 _RealBuffers = null;
2250 // Everything was handled
2252 internal bool IsDone {
2254 if (_LastBufferConsumed != 0)
2257 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2258 if (_UserBuffers[index].Size != 0)
2264 // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
2265 // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
2266 // up to c_SplitEncryptedBuffersSize total.
2267 // Note that upon return from here EncryptBuffers() may additonally split the input
2268 // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
2270 // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2272 // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2274 internal BufferOffsetSize[] GetNextBuffers()
2276 int curIndex = _Index;
2277 int currentTotalSize = 0;
2278 int lastChunkSize = 0;
2280 int firstBufferConsumed = _LastBufferConsumed;
2282 for ( ;_Index < _UserBuffers.Length; ++_Index)
2284 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2286 currentTotalSize += lastChunkSize;
2288 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2290 lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2291 currentTotalSize = c_SplitEncryptedBuffersSize;
2296 _LastBufferConsumed = 0;
2299 // Are we done done?
2300 if (currentTotalSize == 0)
2303 // Do all buffers fit the limit?
2304 if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2305 return _UserBuffers;
2307 // We do have something to split and send out
2308 int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2310 if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2311 _RealBuffers = new BufferOffsetSize[buffersCount];
2314 for (; curIndex < _Index; ++curIndex)
2316 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2317 firstBufferConsumed = 0;
2320 if (lastChunkSize != 0)
2322 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2323 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2326 _LastBufferConsumed = 0;
2330 return _RealBuffers;