Moving BSTR conv to native code in SecureStringToBSTR.
[mono.git] / mcs / class / referencesource / System / net / System / Net / Internal.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Internal.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net {
8     using System.IO;
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;
28
29     internal static class IntPtrHelper {
30         /*
31         // Consider removing.
32         internal static IntPtr Add(IntPtr a, IntPtr b) {
33             return (IntPtr) ((long)a + (long)b);
34         }
35         */
36         internal static IntPtr Add(IntPtr a, int b) {
37             return (IntPtr) ((long)a + (long)b);
38         }
39
40         internal static long Subtract(IntPtr a, IntPtr b) {
41             return ((long)a - (long)b);
42         }
43     }
44
45     internal class InternalException : SystemException
46     {
47         internal InternalException()
48         {
49             GlobalLog.Assert("InternalException thrown.");
50         }
51
52         internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
53             base(serializationInfo, streamingContext)
54         { }
55     }
56
57     internal static class NclUtilities
58     {
59         /// <devdoc>
60         ///    <para>
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.
64         ///    </para>
65         /// </devdoc>
66         internal static bool IsThreadPoolLow()
67         {
68 #if !FEATURE_PAL
69             if (ComNetOS.IsAspNetServer)
70             {
71                 return false;
72             }
73 #endif //!FEATURE_PAL
74
75             int workerThreads, completionPortThreads;
76             ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
77
78 #if !FEATURE_PAL
79             return workerThreads < 2 || (completionPortThreads < 2);
80 #else
81             GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
82             return workerThreads < 2;
83 #endif //!FEATURE_PAL
84         }
85
86
87         internal static bool HasShutdownStarted
88         {
89             get
90             {
91                 return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
92             }
93         }
94
95         // This only works for context-destroying errors.
96         internal static bool IsCredentialFailure(SecurityStatus error)
97         {
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;
106         }
107
108         // This only works for context-destroying errors.
109         internal static bool IsClientFault(SecurityStatus error)
110         {
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;
126         }
127
128
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;
133
134         internal static ContextCallback ContextRelativeDemandCallback
135         {
136             get
137             {
138                 if (s_ContextRelativeDemandCallback == null)
139                     s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
140                 return s_ContextRelativeDemandCallback;
141             }
142         }
143
144         private static void DemandCallback(object state)
145         {
146 #if FEATURE_MONO_CAS
147             ((CodeAccessPermission) state).Demand();
148 #endif
149         }
150
151         // This is for checking if a hostname probably refers to this machine without going to DNS.
152         internal static bool GuessWhetherHostIsLoopback(string host)
153         {
154             string hostLower = host.ToLowerInvariant();
155             if (hostLower == "localhost" || hostLower == "loopback")
156             {
157                 return true;
158             }
159
160 #if !FEATURE_PAL
161             IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties();
162             string hostnameLower = ip.HostName.ToLowerInvariant();
163             return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant();
164 #else
165             return false;
166 #endif
167         }
168
169         internal static bool IsFatal(Exception exception)
170         {
171             return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
172         }
173
174         // Need a fast cached list of local addresses for internal use.
175         private static volatile IPAddress[] _LocalAddresses;
176         private static object _LocalAddressesLock;
177
178 #if !FEATURE_PAL
179
180         private static volatile NetworkAddressChangePolled s_AddressChange;
181
182         internal static IPAddress[] LocalAddresses
183         {
184             get
185             {
186                 if (s_AddressChange != null && s_AddressChange.CheckAndReset())
187                 {
188                     return (_LocalAddresses = GetLocalAddresses());
189                 }
190
191                 if (_LocalAddresses != null)
192                 {
193                     return _LocalAddresses;
194                 }
195
196                 lock (LocalAddressesLock)
197                 {
198                     if (_LocalAddresses != null)
199                     {
200                         return _LocalAddresses;
201                     }
202
203                     s_AddressChange = new NetworkAddressChangePolled();
204
205                     return (_LocalAddresses = GetLocalAddresses());
206                 }
207             }
208         }
209
210         private static IPAddress[] GetLocalAddresses()
211         {
212             IPAddress[] local;
213
214             ArrayList collections = new ArrayList(16);
215             int total = 0;
216
217             SafeLocalFree buffer = null;
218             GetAdaptersAddressesFlags gaaFlags = GetAdaptersAddressesFlags.SkipAnycast | GetAdaptersAddressesFlags.SkipMulticast |
219                 GetAdaptersAddressesFlags.SkipFriendlyName | GetAdaptersAddressesFlags.SkipDnsServer;
220             uint size = 0;
221             uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, SafeLocalFree.Zero, ref size);
222             while (result == IpHelperErrors.ErrorBufferOverflow)
223             {
224                 try
225                 {
226                     buffer = SafeLocalFree.LocalAlloc((int)size);
227                     result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, buffer, ref size);
228
229                     if (result == IpHelperErrors.Success)
230                     {
231                         IntPtr nextAdapter = buffer.DangerousGetHandle();
232
233                         while (nextAdapter != IntPtr.Zero)
234                         {
235                             IpAdapterAddresses adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(
236                                 nextAdapter, typeof(IpAdapterAddresses));
237
238                             if (adapterAddresses.firstUnicastAddress != IntPtr.Zero)
239                             {
240                                 UnicastIPAddressInformationCollection coll = 
241                                     SystemUnicastIPAddressInformation.MarshalUnicastIpAddressInformationCollection(
242                                     adapterAddresses.firstUnicastAddress);
243                                 total += coll.Count;
244                                 collections.Add(coll);
245                             }
246
247                             nextAdapter = adapterAddresses.next;
248                         }
249                     }
250                 }
251                 finally
252                 {
253                     if (buffer != null)
254                         buffer.Close();
255                     buffer = null;
256                 }
257             }
258
259             if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData)
260             {
261                 throw new NetworkInformationException((int)result);
262             }
263
264             local = new IPAddress[total];
265             uint i = 0;
266             foreach (UnicastIPAddressInformationCollection coll in collections)
267             {
268                 foreach (IPAddressInformation info in coll)
269                 {
270                     local[i++] = info.Address;
271                 }
272             }
273             
274             return local;
275         }
276
277         internal static bool IsAddressLocal(IPAddress ipAddress) {
278             IPAddress[] localAddresses = NclUtilities.LocalAddresses;
279             for (int i = 0; i < localAddresses.Length; i++)
280             {
281                 if (ipAddress.Equals(localAddresses[i], false))
282                 {
283                     return true;
284                 }
285             }
286             return false;
287         }
288
289 #else // !FEATURE_PAL
290
291         internal static bool IsAddressLocal(IPAddress ipAddress) {
292             IPAddress[] localAddresses = NclUtilities.LocalAddresses;
293             for (int i = 0; i < localAddresses.Length; i++)
294             {
295                 if (ipAddress.Equals(localAddresses[i], false))
296                 {
297                     return true;
298                 }
299             }
300             return false;
301         }
302
303         private const int HostNameBufferLength = 256;
304         internal static string _LocalDomainName;
305
306         // Copied from the old version of DNS.cs
307         // Returns a list of our local addresses by calling gethostbyname with null.
308         //
309         private static IPHostEntry GetLocalHost()
310         {
311 #if MONO
312             return Dns.GetHostByName (Dns.GetHostName ());
313 #else
314             //
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.
318             //
319             if (Socket.SupportsIPv6)
320             {
321                 //
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.
326                 //
327                 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
328                 SocketError errorCode =
329                     UnsafeNclNativeMethods.OSSOCK.gethostname(
330                     hostname,
331                     HostNameBufferLength);
332
333                 if (errorCode != SocketError.Success)
334                 {
335                     throw new SocketException();
336                 }
337
338                 return Dns.GetHostByName(hostname.ToString());
339             }
340             else
341             {
342                 //
343                 // IPv6 disabled: use gethostbyname() to obtain information.
344                 //
345                 IntPtr nativePointer =
346                     UnsafeNclNativeMethods.OSSOCK.gethostbyname(
347                     null);
348
349                 if (nativePointer == IntPtr.Zero)
350                 {
351                     throw new SocketException();
352                 }
353
354                 return Dns.NativeToHostEntry(nativePointer);
355             }
356 #endif
357
358         } // GetLocalHost
359
360         internal static IPAddress[] LocalAddresses
361         {
362             get
363             {
364                 IPAddress[] local = _LocalAddresses;
365                 if (local != null)
366                 {
367                     return local;
368                 }
369
370                 lock (LocalAddressesLock)
371                 {
372                     local = _LocalAddresses;
373                     if (local != null)
374                     {
375                         return local;
376                     }
377
378                     List<IPAddress> localList = new List<IPAddress>();
379
380                         try
381                         {
382                             IPHostEntry hostEntry = GetLocalHost();
383                             if (hostEntry != null)
384                             {
385                                 if (hostEntry.HostName != null)
386                                 {
387                                     int dot = hostEntry.HostName.IndexOf('.');
388                                     if (dot != -1)
389                                     {
390                                         _LocalDomainName = hostEntry.HostName.Substring(dot);
391                                     }
392                                 }
393
394                                 IPAddress[] ipAddresses = hostEntry.AddressList;
395                                 if (ipAddresses != null)
396                                 {
397                                     foreach (IPAddress ipAddress in ipAddresses)
398                                     {
399                                         localList.Add(ipAddress);
400                                     }
401                                 }
402                             }
403                         }
404                         catch
405                         {
406                         }
407
408                     local = new IPAddress[localList.Count];
409                     int index = 0;
410                     foreach (IPAddress ipAddress in localList)
411                     {
412                         local[index] = ipAddress;
413                         index++;
414                     }
415                     _LocalAddresses = local;
416
417                     return local;
418                 }
419             }
420         }
421 #endif // !FEATURE_PAL
422
423         private static object LocalAddressesLock
424         {
425             get
426             {
427                 if (_LocalAddressesLock == null)
428                 {
429                     Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
430                 }
431                 return _LocalAddressesLock;
432             }
433         }
434     }
435
436     internal static class NclConstants
437     {
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];
441
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'};
444     }
445     
446     //
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.
449     //
450     internal struct InterlockedGate
451     {
452         private int m_State;
453
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.
466         
467 #if DEBUG
468         /* Consider removing
469         internal int State
470         {
471             get
472             {
473                 return m_State;
474             }
475         }
476         */
477 #endif
478         
479         // Only call when all threads are guaranteed to be done with the gate.
480         internal void Reset()
481         {
482             m_State = Open;
483         }
484
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)
487         {
488             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
489             if (exclusive && (gate == Triggering || gate == Triggered))
490             {
491                 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
492                 throw new InternalException();
493             }
494             return gate == Open;
495         }
496
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
500         // it in a finally.
501         //
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)
504         {
505             int gate = Interlocked.CompareExchange(ref m_State, Triggering, Open);
506             if (exclusive && (gate == Triggering || gate == Triggered))
507             {
508                 GlobalLog.Assert("InterlockedGate::StartTriggering", "Gate already triggered.");
509                 throw new InternalException();
510             }
511             return gate == Open;
512         }
513
514         // Gate must be held by StartTriggering().
515         internal void FinishTriggering()
516         {
517             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Triggering);
518             if (gate != Triggering)
519             {
520                 GlobalLog.Assert("InterlockedGate::FinishTriggering", "Gate not Triggering.");
521                 throw new InternalException();
522             }
523         }
524
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.
529         //
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)
532         {
533             int gate = Interlocked.CompareExchange(ref m_State, Signaling, Triggered);
534             if (exclusive && (gate == Signaling || gate == Signaled)) // 
535             {
536                 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already Signaled.");
537                 throw new InternalException();
538             }
539             Debug.Assert(gate != Triggering, "Still Triggering");
540             return gate == Triggered;
541         }
542
543         // Gate must be held by StartSignaling().
544         internal void FinishSignaling()
545         {
546             int gate = Interlocked.CompareExchange(ref m_State, Signaled, Signaling);
547             if (gate != Signaling)
548             {
549                 GlobalLog.Assert("InterlockedGate::FinishSignaling", "Gate not Signaling; " + gate);
550                 throw new InternalException();
551             }
552         }
553             
554         // Makes sure only one thread completes the opperation.
555         internal bool Complete()
556         {
557             int gate = Interlocked.CompareExchange(ref m_State, Completed, Signaled);
558             Debug.Assert(gate != Signaling, "Still Signaling");
559             return (gate == Signaled);
560         }
561     }
562
563 #if !FEATURE_PAL
564     //
565     // A polling implementation of NetworkAddressChange.
566     //
567     internal class NetworkAddressChangePolled : IDisposable
568     {
569         private bool disposed;
570         private SafeCloseSocketAndEvent ipv4Socket = null;
571         private SafeCloseSocketAndEvent ipv6Socket = null;
572
573
574         internal unsafe NetworkAddressChangePolled()
575         {
576             Socket.InitializeSockets();
577             int blocking;
578             if (Socket.OSSupportsIPv4)
579             {
580                 blocking = -1;
581                 ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
582                 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking);
583             }
584
585             if(Socket.OSSupportsIPv6){
586                 blocking = -1;
587                 ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
588                 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking);
589             }
590             Setup(StartIPOptions.Both);
591         }
592
593         private unsafe void Setup(StartIPOptions startIPOptions)
594         {
595             int length;
596             SocketError errorCode;
597
598
599             if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){
600                 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
601                     ipv4Socket.DangerousGetHandle(),
602                     (int) IOControlCode.AddressListChange,
603                     null, 0, null, 0,
604                     out length,
605                     SafeNativeOverlapped.Zero, IntPtr.Zero);
606
607                 if (errorCode != SocketError.Success) {
608                     NetworkInformationException exception = new NetworkInformationException();
609                     if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
610                         Dispose();
611                         return;
612                     }
613                 }
614
615                 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
616                 if (errorCode != SocketError.Success) {
617                     Dispose();
618                     return;
619                 }
620             }
621
622             if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
623                 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
624                     ipv6Socket.DangerousGetHandle(),
625                     (int) IOControlCode.AddressListChange,
626                     null, 0, null, 0,
627                     out length,
628                     SafeNativeOverlapped.Zero, IntPtr.Zero);
629
630                 if (errorCode != SocketError.Success) {
631                     NetworkInformationException exception = new NetworkInformationException();
632                     if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
633                         Dispose();
634                         return;
635                     }
636                 }
637
638                 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
639                 if (errorCode != SocketError.Success) {
640                     Dispose();
641                     return;
642                 }
643             }
644         }
645
646         internal bool CheckAndReset()
647         {
648             if(!disposed){
649                 lock (this){
650                     if (!disposed){
651                         StartIPOptions options = StartIPOptions.None;
652             
653                         if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){
654                             options|= StartIPOptions.StartIPv4;
655                         }
656                         if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false))
657                         {
658                             options|= StartIPOptions.StartIPv6;
659                         }
660             
661                         if(options != StartIPOptions.None){
662                             Setup(options);
663                             return true;
664                         }
665                     }
666                 }
667             }
668             return false;
669         }
670     
671         public void Dispose()
672         {
673             if(!disposed){
674                 lock (this){
675                     if (!disposed){
676                         if(ipv6Socket != null){
677                             ipv6Socket.Close();
678                             ipv6Socket = null;
679                         }
680                         if(ipv4Socket != null){
681                             ipv4Socket.Close();
682                             ipv6Socket = null;
683                         }
684                         disposed = true;
685                     }
686                 }
687             }
688         }
689     }
690 #endif // FEATURE_PAL
691
692
693
694 #if !FEATURE_PAL
695     internal static class ComNetOS
696     {
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";
704
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
711
712         // We use it safe so assert
713         [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
714         [ResourceExposure(ResourceScope.None)]
715         [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
716         static ComNetOS()
717         {
718             OperatingSystem operatingSystem = Environment.OSVersion;
719
720             GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString());
721
722             Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported");
723
724             //
725             // Detect ASP+ as a platform running under NT
726             //
727
728             try
729             {
730                 IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
731             }
732             catch { }
733             
734             IsWin7orLater = (operatingSystem.Version >= new Version(6, 1));
735
736             IsWin7Sp1orLater = (operatingSystem.Version >= new Version(6, 1, 7601));
737
738             IsWin8orLater = (operatingSystem.Version >= new Version(6, 2));
739
740             InstallationType = GetWindowsInstallType();
741             if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType));
742         }
743
744         [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)]
745         private static WindowsInstallationType GetWindowsInstallType()
746         {
747             try
748             {
749                 using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
750                 {
751                     string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string;
752
753                     if (string.IsNullOrEmpty(installType))
754                     {
755                         if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
756                         return WindowsInstallationType.Unknown;
757                     }
758                     else
759                     {
760                         if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0)
761                         {
762                             return WindowsInstallationType.Client;
763                         }
764                         if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
765                         {
766                             return WindowsInstallationType.Server;
767                         }
768                         if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0)
769                         {
770                             return WindowsInstallationType.ServerCore;
771                         }
772                         if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
773                         {
774                             return WindowsInstallationType.Embedded;
775                         }
776
777                         if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType));
778
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;
787                     }
788                 }
789             }
790             catch (UnauthorizedAccessException e)
791             {
792                 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
793                 return WindowsInstallationType.Unknown;
794             }
795             catch (SecurityException e)
796             {
797                 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
798                 return WindowsInstallationType.Unknown;
799             }
800         }
801     }
802 #endif
803
804
805     //
806     // support class for Validation related stuff.
807     //
808     internal static class ValidationHelper {
809
810         public static string [] EmptyArray = new string[0];
811
812         internal static readonly char[]  InvalidMethodChars =
813                 new char[]{
814                 ' ',
815                 '\r',
816                 '\n',
817                 '\t'
818                 };
819
820         // invalid characters that cannot be found in a valid method-verb or http header
821         internal static readonly char[]  InvalidParamChars =
822                 new char[]{
823                 '(',
824                 ')',
825                 '<',
826                 '>',
827                 '@',
828                 ',',
829                 ';',
830                 ':',
831                 '\\',
832                 '"',
833                 '\'',
834                 '/',
835                 '[',
836                 ']',
837                 '?',
838                 '=',
839                 '{',
840                 '}',
841                 ' ',
842                 '\t',
843                 '\r',
844                 '\n'};
845
846         public static string [] MakeEmptyArrayNull(string [] stringArray) {
847             if ( stringArray == null || stringArray.Length == 0 ) {
848                 return null;
849             } else {
850                 return stringArray;
851             }
852         }
853
854         public static string MakeStringNull(string stringValue) {
855             if ( stringValue == null || stringValue.Length == 0) {
856                 return null;
857             } else {
858                 return stringValue;
859             }
860         }
861
862         /*
863         // Consider removing.
864         public static string MakeStringEmpty(string stringValue) {
865             if ( stringValue == null || stringValue.Length == 0) {
866                 return String.Empty;
867             } else {
868                 return stringValue;
869             }
870         }
871         */
872
873 #if TRAVE
874         /*
875         // Consider removing.
876         public static int HashCode(object objectValue) {
877             if (objectValue == null) {
878                 return -1;
879             } else {
880                 return objectValue.GetHashCode();
881             }
882         }
883         */
884 #endif
885
886         public static string ExceptionMessage(Exception exception) {
887             if (exception==null) {
888                 return string.Empty;
889             }
890             if (exception.InnerException==null) {
891                 return exception.Message;
892             }
893             return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
894         }
895
896         public static string ToString(object objectValue) {
897             if (objectValue == null) {
898                 return "(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");
905             } else {
906                 return objectValue.ToString();
907             }
908         }
909         public static string HashString(object objectValue) {
910             if (objectValue == null) {
911                 return "(null)";
912             } else if (objectValue is string && ((string)objectValue).Length==0) {
913                 return "(string.empty)";
914             } else {
915                 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
916             }
917         }
918
919         public static bool IsInvalidHttpString(string stringValue) {
920             return stringValue.IndexOfAny(InvalidParamChars)!=-1;
921         }
922
923         public static bool IsBlankString(string stringValue) {
924             return stringValue==null || stringValue.Length==0;
925         }
926
927         /*
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;
932         }
933         */
934
935         public static bool ValidateTcpPort(int port) {
936             // on false, API should throw new ArgumentOutOfRangeException("port");
937             return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort;
938         }
939
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;
943         }
944
945         /*
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;
950         }
951         */
952
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");
958             }
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");
963             }
964         }
965     }
966
967     internal static class ExceptionHelper
968     {
969 #if FEATURE_MONO_CAS
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);
977 #endif
978         internal static NotImplementedException MethodNotImplementedException {
979             get {
980                 return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException));
981             }
982         }
983
984         internal static NotImplementedException PropertyNotImplementedException {
985             get {
986                 return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
987             }
988         }
989
990         internal static NotSupportedException MethodNotSupportedException {
991             get {
992                 return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException));
993             }
994         }
995
996         internal static NotSupportedException PropertyNotSupportedException {
997             get {
998                 return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException));
999             }
1000         }
1001
1002         internal static WebException IsolatedException {
1003             get {
1004                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
1005             }
1006         }
1007
1008         internal static WebException RequestAbortedException {
1009             get {
1010                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
1011             }
1012         }
1013
1014         internal static WebException CacheEntryNotFoundException {
1015             get {
1016                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
1017             }
1018         }
1019
1020         internal static WebException RequestProhibitedByCachePolicyException {
1021             get {
1022                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1023             }
1024         }
1025     }
1026
1027     internal enum WindowsInstallationType
1028     { 
1029         Unknown = 0,
1030         Client,
1031         Server,
1032         ServerCore,
1033         Embedded
1034     }
1035
1036     internal enum SecurityStatus
1037     {
1038         // Success / Informational
1039         OK                          =   0x00000000,
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),
1046         
1047         // Errors
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)
1080     }
1081
1082     internal enum ContentTypeValues {
1083         ChangeCipherSpec    = 0x14,
1084         Alert               = 0x15,
1085         HandShake           = 0x16,
1086         AppData             = 0x17,
1087         Unrecognized        = 0xFF,
1088     }
1089
1090     internal enum ContextAttribute {
1091         //
1092         // look into <sspi.h> and <schannel.h>
1093         //
1094         Sizes               = 0x00,
1095         Names               = 0x01,
1096         Lifespan            = 0x02,
1097         DceInfo             = 0x03,
1098         StreamSizes         = 0x04,
1099         //KeyInfo             = 0x05, must not be used, see ConnectionInfo instead
1100         Authority           = 0x06,
1101         // SECPKG_ATTR_PROTO_INFO          = 7,
1102         // SECPKG_ATTR_PASSWORD_EXPIRY     = 8,
1103         // SECPKG_ATTR_SESSION_KEY         = 9,
1104         PackageInfo         = 0x0A,
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,
1120         RootStore           = 0x55,
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  
1137     }
1138
1139     internal enum Endianness {
1140         Network             = 0x00,
1141         Native              = 0x10,
1142     }
1143
1144     internal enum CredentialUse {
1145         Inbound             = 0x1,
1146         Outbound            = 0x2,
1147         Both                = 0x3,
1148     }
1149
1150     internal enum BufferType {
1151         Empty               = 0x00,
1152         Data                = 0x01,
1153         Token               = 0x02,
1154         Parameters          = 0x03,
1155         Missing             = 0x04,
1156         Extra               = 0x05,
1157         Trailer             = 0x06,
1158         Header              = 0x07,
1159         Padding             = 0x09,    // non-data padding
1160         Stream              = 0x0A,
1161         ChannelBindings     = 0x0E,
1162         TargetHost          = 0x10,
1163         ReadOnlyFlag        = unchecked((int)0x80000000),
1164         ReadOnlyWithChecksum= 0x10000000
1165     }
1166
1167     internal enum ChainPolicyType {
1168         Base                = 1,
1169         Authenticode        = 2,
1170         Authenticode_TS     = 3,
1171         SSL                 = 4,
1172         BasicConstraints    = 5,
1173         NtAuth              = 6,
1174     }
1175
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,
1181
1182         all_not_time_valid          =
1183             not_time_valid          |
1184             ctl_not_time_valid      |
1185             not_time_nested,
1186
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,
1195
1196         all_rev_unknown             =
1197             end_rev_unknown         |
1198             ctl_signer_rev_unknown  |
1199             ca_rev_unknown          |
1200             root_rev_unknown,
1201         none =
1202             not_time_valid |
1203             ctl_not_time_valid |
1204             not_time_nested |
1205             invalid_basic_constraints |
1206             allow_unknown_ca |
1207             wrong_usage |
1208             invalid_name |
1209             invalid_policy |
1210             end_rev_unknown |
1211             ctl_signer_rev_unknown |
1212             ca_rev_unknown |
1213             root_rev_unknown
1214     }
1215
1216     internal enum CertUsage {
1217         MatchTypeAnd    = 0x00,
1218         MatchTypeOr     = 0x01,
1219     }
1220
1221 #if !FEATURE_PAL
1222
1223     [StructLayout(LayoutKind.Sequential)]
1224     internal unsafe struct ChainPolicyParameter {
1225         public uint cbSize;
1226         public uint dwFlags;
1227         public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1228
1229         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1230     }
1231
1232     [StructLayout(LayoutKind.Sequential)]
1233     internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1234
1235         [StructLayout(LayoutKind.Explicit)]
1236         internal struct U {
1237               [FieldOffset(0)] internal uint cbStruct;  //DWORD
1238               [FieldOffset(0)] internal uint cbSize;    //DWORD
1239         };
1240         internal U u;
1241         internal int    dwAuthType;  //DWORD
1242         internal uint   fdwChecks;   //DWORD
1243         internal char*  pwszServerName; //WCHAR* // used to check against CN=xxxx
1244
1245         internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1246         {
1247             u.cbStruct = StructSize;
1248             u.cbSize   = StructSize;
1249             //#      define      AUTHTYPE_CLIENT         1
1250             //#      define      AUTHTYPE_SERVER         2
1251             dwAuthType = amIServer? 1: 2;
1252             fdwChecks = 0;
1253             pwszServerName = null;
1254         }
1255         static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1256     }
1257
1258     [StructLayout(LayoutKind.Sequential)]
1259     internal unsafe struct ChainPolicyStatus {
1260         public uint   cbSize;
1261         public uint   dwError;
1262         public uint   lChainIndex;
1263         public uint   lElementIndex;
1264         public void*  pvExtraPolicyStatus;
1265
1266         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1267     }
1268
1269     [StructLayout(LayoutKind.Sequential)]
1270     internal unsafe struct CertEnhKeyUse {
1271
1272         public uint   cUsageIdentifier;
1273         public void*  rgpszUsageIdentifier;
1274
1275 #if TRAVE
1276         public override string ToString() {
1277             return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1278         }
1279 #endif
1280     };
1281
1282     [StructLayout(LayoutKind.Sequential)]
1283     internal struct CertUsageMatch {
1284         public CertUsage     dwType;
1285         public CertEnhKeyUse Usage;
1286 #if TRAVE
1287         public override string ToString() {
1288             return "dwType="+dwType.ToString()+" "+Usage.ToString();
1289         }
1290 #endif
1291     };
1292
1293     [StructLayout(LayoutKind.Sequential)]
1294     internal struct ChainParameters {
1295         public uint cbSize;
1296         public CertUsageMatch RequestedUsage;
1297         public CertUsageMatch RequestedIssuancePolicy;
1298         public uint           UrlRetrievalTimeout;
1299         public int            BoolCheckRevocationFreshnessTime;
1300         public uint           RevocationFreshnessTime;
1301
1302
1303         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1304 #if TRAVE
1305         public override string ToString() {
1306             return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1307         }
1308 #endif
1309     };
1310
1311     [StructLayout(LayoutKind.Sequential)]
1312     struct _CERT_CHAIN_ELEMENT
1313     {
1314         public uint cbSize;
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;
1322     }
1323
1324     // CRYPTOAPI_BLOB
1325     //[StructLayout(LayoutKind.Sequential)]
1326     //unsafe struct CryptoBlob {
1327     //    // public uint cbData;
1328     //    // public byte* pbData;
1329     //    public uint dataSize;
1330     //    public byte* dataBlob;
1331     //}
1332
1333     // SecPkgContext_IssuerListInfoEx
1334     [StructLayout(LayoutKind.Sequential)]
1335     unsafe struct IssuerListInfoEx {
1336         public SafeHandle aIssuers;
1337         public uint cIssuers;
1338
1339         public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1340             aIssuers = handle;
1341             fixed(byte* voidPtr = nativeBuffer) {
1342                 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1343                 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1344             }
1345         }
1346     }
1347
1348
1349     [StructLayout(LayoutKind.Sequential)]
1350     internal struct SecureCredential {
1351
1352 /*
1353 typedef struct _SCHANNEL_CRED
1354 {
1355     DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION
1356     DWORD           cCreds;
1357     PCCERT_CONTEXT *paCred;
1358     HCERTSTORE      hRootStore;
1359
1360     DWORD           cMappers;
1361     struct _HMAPPER **aphMappers;
1362
1363     DWORD           cSupportedAlgs;
1364     ALG_ID *        palgSupportedAlgs;
1365
1366     DWORD           grbitEnabledProtocols;
1367     DWORD           dwMinimumCipherStrength;
1368     DWORD           dwMaximumCipherStrength;
1369     DWORD           dwSessionLifespan;
1370     DWORD           dwFlags;
1371     DWORD           reserved;
1372 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1373 */
1374
1375         public const int CurrentVersion = 0x4;
1376
1377         public int version;
1378         public int cCreds;
1379
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;
1388
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;
1400
1401         [Flags]
1402         public enum Flags {
1403             Zero            = 0,
1404             NoSystemMapper  = 0x02,
1405             NoNameCheck     = 0x04,
1406             ValidateManual  = 0x08,
1407             NoDefaultCred   = 0x10,
1408             ValidateAuto    = 0x20,
1409             UseStrongCrypto = 0x00400000,
1410         }
1411
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;
1416
1417             if (policy == EncryptionPolicy.RequireEncryption) {
1418                 // Prohibit null encryption cipher
1419                 dwMinimumCipherStrength = 0;
1420                 dwMaximumCipherStrength = 0;
1421             }
1422             else if (policy == EncryptionPolicy.AllowNoEncryption) {
1423                 // Allow null encryption cipher in addition to other ciphers
1424                 dwMinimumCipherStrength = -1;
1425                 dwMaximumCipherStrength =  0;
1426             }
1427             else if (policy == EncryptionPolicy.NoEncryption) {
1428                 // Suppress all encryption and require null encryption cipher only
1429                 dwMinimumCipherStrength = -1;
1430                 dwMaximumCipherStrength = -1;
1431             }
1432             else {
1433                 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1434             }
1435             
1436             dwSessionLifespan = reserved = 0;
1437             this.version = version;
1438             dwFlags = flags;
1439             grbitEnabledProtocols = protocols;
1440             if (certificate != null) {
1441                 certContextArray = certificate.Handle;
1442                 cCreds = 1;
1443             }
1444         }
1445
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));
1463         }
1464
1465     } // SecureCredential
1466
1467 #endif // !FEATURE_PAL
1468
1469     [StructLayout(LayoutKind.Sequential)]
1470     internal unsafe struct SecurityBufferStruct {
1471         public int          count;
1472         public BufferType   type;
1473         public IntPtr       token;
1474
1475         public static readonly int Size = sizeof(SecurityBufferStruct);
1476     }
1477
1478     internal class SecurityBuffer {
1479         public int size;
1480         public BufferType type;
1481         public byte[] token;
1482         public SafeHandle unmanagedToken;
1483         public int offset;
1484
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 + "]");
1488                         
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;
1493         }
1494
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;
1499         }
1500
1501         public SecurityBuffer(int size, BufferType tokentype) {
1502             GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range.  [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1503
1504             this.size   = size;
1505             this.type   = tokentype;
1506             this.token  = size == 0 ? null : new byte[size];
1507         }
1508
1509         public SecurityBuffer(ChannelBinding binding) {
1510             this.size           = (binding == null ? 0 : binding.Size);
1511             this.type           = BufferType.ChannelBindings;
1512             this.unmanagedToken = binding;
1513         }
1514     }
1515
1516     [StructLayout(LayoutKind.Sequential)]
1517     internal unsafe class SecurityBufferDescriptor {
1518     /*
1519     typedef struct _SecBufferDesc {
1520         ULONG        ulVersion;
1521         ULONG        cBuffers;
1522         PSecBuffer   pBuffers;
1523     } SecBufferDesc, * PSecBufferDesc;
1524     */
1525             public  readonly    int     Version;
1526             public  readonly    int     Count;
1527             public  void*       UnmanagedPointer;
1528
1529         public SecurityBufferDescriptor(int count) {
1530             Version = 0;
1531             Count = count;
1532             UnmanagedPointer = null;
1533         }
1534
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"));
1541         }
1542     } // SecurityBufferDescriptor
1543
1544     internal  enum    CertificateEncoding {
1545         Zero                     = 0,
1546         X509AsnEncoding          = unchecked((int)0x00000001),
1547         X509NdrEncoding          = unchecked((int)0x00000002),
1548         Pkcs7AsnEncoding         = unchecked((int)0x00010000),
1549         Pkcs7NdrEncoding         = unchecked((int)0x00020000),
1550         AnyAsnEncoding           = X509AsnEncoding|Pkcs7AsnEncoding
1551     }
1552
1553     internal  enum    CertificateProblem {
1554         OK                          =   0x00000000,
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),
1575
1576         CryptNOREVOCATIONCHECK       = unchecked((int)0x80092012),
1577         CryptREVOCATIONOFFLINE       = unchecked((int)0x80092013),
1578
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),
1587     }
1588
1589     [StructLayout(LayoutKind.Sequential)]
1590     internal class SecChannelBindings
1591     {
1592         internal int dwInitiatorAddrType;
1593         internal int cbInitiatorLength;
1594         internal int dwInitiatorOffset;
1595
1596         internal int dwAcceptorAddrType;
1597         internal int cbAcceptorLength;
1598         internal int dwAcceptorOffset;
1599
1600         internal int cbApplicationDataLength;
1601         internal int dwApplicationDataOffset;
1602     }
1603
1604     //
1605     // WebRequestPrefixElement
1606     //
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.
1609     //
1610
1611     /// <devdoc>
1612     ///    <para>[To be supplied.]</para>
1613     /// </devdoc>
1614     // internal class WebRequestPrefixElement {
1615     internal class WebRequestPrefixElement  {
1616
1617         /// <devdoc>
1618         ///    <para>[To be supplied.]</para>
1619         /// </devdoc>
1620         public    string              Prefix;
1621         /// <devdoc>
1622         ///    <para>[To be supplied.]</para>
1623         /// </devdoc>
1624         internal    IWebRequestCreate   creator;
1625         /// <devdoc>
1626         ///    <para>[To be supplied.]</para>
1627         /// </devdoc>
1628         internal    Type   creatorType;
1629
1630         public IWebRequestCreate Creator {
1631             get {
1632                 if (creator == null && creatorType != null) {
1633                     lock(this) {
1634                         if (creator == null) {
1635                             creator = (IWebRequestCreate)Activator.CreateInstance(
1636                                                         creatorType,
1637                                                         BindingFlags.CreateInstance
1638                                                         | BindingFlags.Instance
1639                                                         | BindingFlags.NonPublic
1640                                                         | BindingFlags.Public,
1641                                                         null,          // Binder
1642                                                         new object[0], // no arguments
1643                                                         CultureInfo.InvariantCulture
1644                                                         );
1645                         }
1646                     }
1647                 }
1648
1649                 return creator;
1650             }
1651
1652             set {
1653                 creator = value;
1654             }
1655         }
1656
1657         public WebRequestPrefixElement(string P, Type creatorType) {
1658             // verify that its of the proper type of IWebRequestCreate
1659             if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1660             {
1661                 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1662                                                                 creatorType.AssemblyQualifiedName,
1663                                                                 "IWebRequestCreate"));
1664             }
1665
1666             Prefix = P;
1667             this.creatorType = creatorType;
1668         }
1669
1670         /// <devdoc>
1671         ///    <para>[To be supplied.]</para>
1672         /// </devdoc>
1673         public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1674             Prefix = P;
1675             Creator = C;
1676         }
1677
1678     } // class PrefixListElement
1679
1680
1681 #if MONO_FEATURE_WEB_STACK
1682
1683     //
1684     // HttpRequestCreator.
1685     //
1686     // This is the class that we use to create HTTP and HTTPS requests.
1687     //
1688
1689     internal class HttpRequestCreator : IWebRequestCreate {
1690
1691         /*++
1692
1693          Create - Create an HttpWebRequest.
1694
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.
1698
1699
1700             Input:
1701                     Uri             - Uri for request being created.
1702
1703             Returns:
1704                     The newly created HttpWebRequest.
1705
1706          --*/
1707
1708         public WebRequest Create( Uri Uri ) {
1709             //
1710             // Note, DNS permissions check will not happen on WebRequest
1711             //
1712             return new HttpWebRequest(Uri, null);
1713         }
1714
1715     } // class HttpRequestCreator
1716
1717     //
1718     // WebSocketHttpRequestCreator.
1719     //
1720     // This is the class that we use to create WebSocket connection requests.
1721     //
1722
1723     internal class WebSocketHttpRequestCreator : IWebRequestCreate
1724     {
1725         private string m_httpScheme;
1726
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)
1731         {
1732             m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1733         }
1734
1735         /*++
1736
1737          Create - Create an HttpWebRequest.
1738
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.
1743
1744
1745             Input:
1746                     Uri             - Uri for request being created.
1747
1748             Returns:
1749                     The newly created HttpWebRequest for WebSocket connection.
1750
1751          --*/
1752
1753         public WebRequest Create(Uri Uri)
1754         {
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);
1759             return request;
1760         }
1761
1762     } // class WebSocketHttpRequestCreator
1763
1764
1765
1766
1767     //
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
1771     //
1772     internal class CoreResponseData {
1773
1774         // Status Line Response Values
1775         public HttpStatusCode m_StatusCode;
1776         public string m_StatusDescription;
1777         public bool m_IsVersionHttp11;
1778
1779         // Content Length needed for semantics, -1 if chunked
1780         public long m_ContentLength;
1781
1782         // Response Headers
1783         public WebHeaderCollection m_ResponseHeaders;
1784
1785         // ConnectStream - for reading actual data
1786         public Stream m_ConnectStream;
1787
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;
1797         }
1798
1799     }
1800 #endif
1801
1802
1803     internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1804
1805     //
1806     // this class contains known header names
1807     //
1808
1809     internal static class HttpKnownHeaderNames {
1810
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"; 
1874     }
1875
1876     /// <devdoc>
1877     ///    <para>
1878     ///       Represents the method that will notify callers when a continue has been
1879     ///       received by the client.
1880     ///    </para>
1881     /// </devdoc>
1882     // Delegate type for us to notify callers when we receive a continue
1883     public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1884
1885     //
1886     // HttpWriteMode - used to control the way in which an entity Body is posted.
1887     //
1888     enum HttpWriteMode {
1889         Unknown         = 0,
1890         ContentLength   = 1,
1891         Chunked         = 2,
1892         Buffer          = 3,
1893         None            = 4,
1894     }
1895
1896     // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1897     delegate void UnlockConnectionDelegate();
1898
1899     enum HttpBehaviour : byte {
1900         Unknown                     = 0,
1901         HTTP10                      = 1,
1902         HTTP11PartiallyCompliant    = 2,
1903         HTTP11                      = 3,
1904     }
1905
1906     internal enum HttpProcessingResult {
1907         Continue  = 0,
1908         ReadWait  = 1,
1909         WriteWait = 2,
1910     }
1911
1912     //
1913     // HttpVerb - used to define various per Verb Properties
1914     //
1915
1916     //
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.
1920     //
1921     class KnownHttpVerb {
1922         internal string Name; // verb name
1923
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
1928
1929         internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1930             Name = name;
1931             RequireContentBody = requireContentBody;
1932             ContentBodyNotAllowed = contentBodyNotAllowed;
1933             ConnectRequest = connectRequest;
1934             ExpectNoContentResponse = expectNoContentResponse;
1935         }
1936
1937         // Force an an init, before we use them
1938         private static ListDictionary NamedHeaders;
1939
1940         // known verbs
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;
1947
1948         //
1949         // InitializeKnownVerbs - Does basic init for this object,
1950         //  such as creating defaultings and filling them
1951         //
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;
1966         }
1967
1968         public bool Equals(KnownHttpVerb verb) {
1969             return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1970         }
1971
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);
1977             }
1978             return knownHttpVerb;
1979         }
1980     }
1981
1982     //
1983     // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1984     //
1985
1986     internal class HttpProtocolUtils {
1987
1988         private HttpProtocolUtils() {
1989         }
1990
1991         //
1992         // extra buffers for build/parsing, recv/send HTTP data,
1993         //  at some point we should consolidate
1994         //
1995
1996
1997         // parse String to DateTime format.
1998         internal static DateTime string2date(String S) {
1999             DateTime dtOut;
2000             if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
2001                 return dtOut;
2002             }
2003             else {
2004                 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
2005             }
2006
2007         }
2008
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);
2013         }
2014     }
2015
2016 #if !FEATURE_PAL
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;
2023
2024         internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2025             this.fwdPolicy = policy;
2026             srvPoint = sp;
2027             request = wr;
2028         }
2029
2030         public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2031             return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2032         }
2033
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;
2038             int errorCode =
2039                 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2040                     (IntPtr) ChainPolicyType.SSL,
2041                     chainContext,
2042                     ref cpp,
2043                     ref status);
2044
2045             GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2046 #if TRAVE
2047             GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2048 #endif
2049             GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2050             return status.dwError;
2051         }
2052
2053         private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2054             switch ((CertificateProblem) errorCode) {
2055
2056                 case CertificateProblem.CertINVALIDNAME :
2057                 case CertificateProblem.CertCN_NO_MATCH :
2058                     return IgnoreCertProblem.invalid_name;
2059
2060                 case CertificateProblem.CertINVALIDPOLICY :
2061                 case CertificateProblem.CertPURPOSE :
2062                     return IgnoreCertProblem.invalid_policy;
2063
2064                 case CertificateProblem.CertEXPIRED :
2065                     return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2066
2067                 case CertificateProblem.CertVALIDITYPERIODNESTING :
2068                     return IgnoreCertProblem.not_time_nested;
2069
2070                 case CertificateProblem.CertCHAINING :
2071                 case CertificateProblem.CertUNTRUSTEDCA :
2072                 case CertificateProblem.CertUNTRUSTEDROOT :
2073                     return IgnoreCertProblem.allow_unknown_ca;
2074
2075                 case CertificateProblem.CertREVOKED :
2076                 case CertificateProblem.CertREVOCATION_FAILURE :
2077                 case CertificateProblem.CryptNOREVOCATIONCHECK:
2078                 case CertificateProblem.CryptREVOCATIONOFFLINE:
2079                     return IgnoreCertProblem.all_rev_unknown;
2080
2081                 case CertificateProblem.CertROLE:
2082                 case CertificateProblem.TrustBASICCONSTRAINTS:
2083                     return IgnoreCertProblem.invalid_basic_constraints;
2084
2085                 case CertificateProblem.CertWRONG_USAGE :
2086                     return IgnoreCertProblem.wrong_usage;
2087
2088                 default:
2089                     return 0;
2090             }
2091         }
2092
2093
2094         private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2095         {
2096             fatalError = false;
2097             SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2098             ArrayList certificateProblems = new ArrayList();
2099             unsafe {
2100                 uint status = 0;
2101                 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2102                 cppStruct.cbSize  = ChainPolicyParameter.StructSize;
2103                 cppStruct.dwFlags = 0;
2104
2105                 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2106                 cppStruct.pvExtraPolicyPara = &eppStruct;
2107
2108                 fixed (char* namePtr = hostName) {
2109                     if (ServicePointManager.CheckCertificateName){
2110                         eppStruct.pwszServerName = namePtr;
2111                     }
2112
2113                     while (true) {
2114                         status = VerifyChainPolicy(chainContext, ref cppStruct);
2115                         uint ignoreErrorMask = (uint)MapErrorCode(status);
2116
2117                         certificateProblems.Add(status);
2118
2119                         if (status == 0) {  // No more problems with the certificate?
2120                             break;          // Then break out of the callback loop
2121                         }
2122
2123                         if (ignoreErrorMask == 0) {  // Unrecognized error encountered
2124                             fatalError = true;
2125                             break;
2126                         }
2127                         else {
2128                             cppStruct.dwFlags |= ignoreErrorMask;
2129                             if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2130                                 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2131                             }
2132                         }
2133                     }
2134                 }
2135             }
2136
2137             return (uint[]) certificateProblems.ToArray(typeof(uint));
2138         }
2139
2140         internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2141         {
2142             if (sslPolicyErrors == 0)
2143                 return Accept(certificate, 0);
2144
2145             if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2146                 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2147             else {
2148                 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2149                     (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2150                 {
2151                     bool fatalError = false;
2152                     uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2153
2154                     if (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);
2158                         return false;
2159                     }
2160
2161
2162                     if (certificateProblems.Length == 0)
2163                         return Accept(certificate, (int) CertificateProblem.OK);
2164
2165                     // Run each error through Accept().
2166                     foreach (uint error in certificateProblems)
2167                         if (!Accept(certificate, (int) error))
2168                             return false;
2169                 }
2170                 return true;
2171             }
2172         }
2173
2174 /* CONSIDER: Use this code when we switch to managed X509 API
2175         internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2176         {
2177             switch (status)
2178             {
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
2203             }
2204         }
2205 ***/
2206     }
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;
2211         }
2212     }
2213 #endif // !FEATURE_PAL
2214
2215     internal enum TriState {
2216         Unspecified = -1,
2217         False = 0,
2218         True = 1
2219     }
2220
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
2229     }
2230
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;
2238     }
2239
2240
2241     [StructLayout(LayoutKind.Sequential)]
2242     internal struct Blob {
2243         public int cbSize;
2244         public int pBlobData;
2245     }
2246
2247
2248     // This is only for internal code path i.e. TLS stream.
2249     // See comments on GetNextBuffer() method below.
2250     //
2251     internal class SplitWritesState
2252     {
2253         private const int c_SplitEncryptedBuffersSize = 64*1024;
2254         private BufferOffsetSize[] _UserBuffers;
2255         private int _Index;
2256         private int _LastBufferConsumed;
2257         private BufferOffsetSize[] _RealBuffers;
2258
2259         //
2260         internal SplitWritesState(BufferOffsetSize[] buffers)
2261         {
2262             _UserBuffers    = buffers;
2263             _LastBufferConsumed = 0;
2264             _Index          = 0;
2265             _RealBuffers = null;
2266         }
2267         //
2268         // Everything was handled
2269         //
2270         internal bool IsDone {
2271             get {
2272                 if (_LastBufferConsumed != 0)
2273                     return false;
2274
2275                 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2276                     if (_UserBuffers[index].Size != 0)
2277                         return false;
2278
2279                 return true;
2280             }
2281         }
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.
2287         //
2288         //  Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2289         //
2290         //  Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2291         //
2292         internal BufferOffsetSize[] GetNextBuffers()
2293         {
2294             int curIndex = _Index;
2295             int currentTotalSize = 0;
2296             int lastChunkSize = 0;
2297
2298             int  firstBufferConsumed = _LastBufferConsumed;
2299
2300             for ( ;_Index < _UserBuffers.Length; ++_Index)
2301             {
2302                 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2303
2304                 currentTotalSize += lastChunkSize;
2305
2306                 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2307                 {
2308                     lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2309                     currentTotalSize = c_SplitEncryptedBuffersSize;
2310                     break;
2311                 }
2312
2313                 lastChunkSize = 0;
2314                 _LastBufferConsumed = 0;
2315             }
2316
2317             // Are we done done?
2318             if (currentTotalSize == 0)
2319                 return null;
2320
2321              // Do all buffers fit the limit?
2322             if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2323                 return _UserBuffers;
2324
2325             // We do have something to split and send out
2326             int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2327
2328             if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2329                 _RealBuffers = new BufferOffsetSize[buffersCount];
2330
2331             int j = 0;
2332             for (; curIndex < _Index; ++curIndex)
2333             {
2334                 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2335                 firstBufferConsumed = 0;
2336             }
2337
2338             if (lastChunkSize != 0)
2339             {
2340                 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2341                 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2342                 {
2343                     ++_Index;
2344                     _LastBufferConsumed = 0;
2345                 }
2346             }
2347
2348             return _RealBuffers;
2349
2350         }
2351     }
2352 }