Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.IdentityModel / System / IdentityModel / SspiWrapper.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.IdentityModel
6 {
7     using System.Runtime.InteropServices;
8     using System.Diagnostics;
9     using System.ComponentModel;
10     using System.Security.Permissions;
11     using System.Globalization;
12     using System.Security.Authentication.ExtendedProtection;
13     using System.Net;
14     using System.Runtime.CompilerServices;
15
16
17     //From Schannel.h
18     internal enum SchProtocols
19     {
20         Zero = 0,
21         PctClient = 0x00000002,
22         PctServer = 0x00000001,
23         Pct = (PctClient | PctServer),
24         Ssl2Client = 0x00000008,
25         Ssl2Server = 0x00000004,
26         Ssl2 = (Ssl2Client | Ssl2Server),
27         Ssl3Client = 0x00000020,
28         Ssl3Server = 0x00000010,
29         Ssl3 = (Ssl3Client | Ssl3Server),
30         TlsClient = 0x00000080,
31         TlsServer = 0x00000040,
32         Tls = (TlsClient | TlsServer),
33         Ssl3Tls = (Ssl3 | Tls),
34         Tls11Client = 0x00000200,
35         Tls11Server = 0x00000100,
36         Tls11 = (Tls11Client | Tls11Server),
37         Tls12Client = 0x00000800,
38         Tls12Server = 0x00000400,
39         Tls12 = (Tls12Client | Tls12Server),
40         UniClient = unchecked((int)0x80000000),
41         UniServer = 0x40000000,
42         Unified = (UniClient | UniServer),
43         ClientMask = (PctClient | Ssl2Client | Ssl3Client | TlsClient | Tls11Client | Tls12Client | UniClient),
44         ServerMask = (PctServer | Ssl2Server | Ssl3Server | TlsServer | Tls11Server | Tls12Server | UniServer)
45     };
46
47     //From WinCrypt.h
48     internal enum Alg
49     {
50         Any = 0,
51         ClassSignture = (1 << 13),
52         ClassEncrypt = (3 << 13),
53         ClassHash = (4 << 13),
54         ClassKeyXch = (5 << 13),
55         TypeRSA = (2 << 9),
56         TypeBlock = (3 << 9),
57         TypeStream = (4 << 9),
58         TypeDH = (5 << 9),
59
60         NameDES = 1,
61         NameRC2 = 2,
62         NameRC4 = 1,
63         NameSkipJack = 10,
64
65         // want to ensure MD5 is never used
66         // NameMD5         = 3,
67         NameSHA = 4,
68
69         NameDH_Ephem = 2,
70         Fortezza = 4
71     }
72
73     [StructLayout(LayoutKind.Sequential)]
74     internal struct SecurityPackageInfo
75     {
76         // see SecPkgInfoW in <sspi.h>
77         internal int Capabilities;
78         internal short Version;
79         internal short RPCID;
80         internal int MaxToken;
81         internal IntPtr Name;
82         internal IntPtr Comment;
83
84         internal static readonly int Size = Marshal.SizeOf(typeof(SecurityPackageInfo));
85         internal static readonly int NameOffest = (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Name");
86     }
87
88     [StructLayout(LayoutKind.Sequential)]
89     internal struct LifeSpan_Struct
90     {
91         internal long start;
92         internal long end;
93
94         internal static readonly int Size = Marshal.SizeOf(typeof(LifeSpan_Struct));
95     }
96
97     [StructLayout(LayoutKind.Sequential)]
98     internal struct NegotiationInfo
99     {
100         // see SecPkgContext_NegotiationInfoW in <sspi.h>
101
102         // [MarshalAs(UnmanagedType.LPStruct)] internal SecurityPackageInfo PackageInfo;
103         internal IntPtr PackageInfo;
104         internal uint NegotiationState;
105         internal static readonly int Size = Marshal.SizeOf(typeof(NegotiationInfo));
106         internal static readonly int NegotiationStateOffset = (int)Marshal.OffsetOf(typeof(NegotiationInfo), "NegotiationState");
107     }
108
109     // Note: pack=0 since the first member (SessionKeyLength) is C's long (platform dependent).
110     [StructLayout(LayoutKind.Sequential, Pack = 0)]
111     internal struct SecPkgContext_SessionKey
112     {
113         //[MarshalAs(UnmanagedType.SysUInt)] internal uint SessionKeyLength;
114         internal uint SessionKeyLength;
115         internal IntPtr Sessionkey;
116         internal static readonly int Size = Marshal.SizeOf(typeof(SecPkgContext_SessionKey));
117         internal static readonly int SessionkeyOffset = (int)Marshal.OffsetOf(typeof(SecPkgContext_SessionKey), "Sessionkey");
118     }
119
120     internal class LifeSpan
121     {
122         DateTime effectiveTimeUtc;
123         DateTime expiryTimeUtc;
124
125         internal DateTime EffectiveTimeUtc
126         {
127             get
128             {
129                 return this.effectiveTimeUtc;
130             }
131         }
132
133         internal DateTime ExpiryTimeUtc
134         {
135             get
136             {
137                 return this.expiryTimeUtc;
138             }
139         }
140
141         internal unsafe LifeSpan(byte[] buffer)
142         {
143             fixed (byte* pbuffer = &buffer[0])
144             {
145                 IntPtr ptr = new IntPtr(pbuffer);
146                 LifeSpan_Struct lifeSpan = (LifeSpan_Struct)Marshal.PtrToStructure(ptr, typeof(LifeSpan_Struct));
147                 // start and end times are expressed as local file times.
148                 // however dateTime.FromFileTime* expects the file time to be in UTC.
149                 // so we need to add the difference to the DateTime 
150                 this.effectiveTimeUtc = DateTime.FromFileTimeUtc(lifeSpan.start) + (DateTime.UtcNow - DateTime.Now);
151                 this.expiryTimeUtc = DateTime.FromFileTimeUtc(lifeSpan.end) + (DateTime.UtcNow - DateTime.Now);
152             }
153         }
154     }
155
156     internal class SecurityPackageInfoClass
157     {
158         internal int Capabilities = 0;
159         internal short Version = 0;
160         internal short RPCID = 0;
161         internal int MaxToken = 0;
162         internal string Name = null;
163         internal string Comment = null;
164
165         internal SecurityPackageInfoClass(SafeHandle safeHandle, int index)
166         {
167             if (safeHandle.IsInvalid)
168             {
169                 return;
170             }
171             IntPtr unmanagedAddress = IntPtrHelper.Add(safeHandle.DangerousGetHandle(), SecurityPackageInfo.Size * index);
172             Capabilities = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Capabilities"));
173             Version = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Version"));
174             RPCID = Marshal.ReadInt16(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "RPCID"));
175             MaxToken = Marshal.ReadInt32(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "MaxToken"));
176
177             IntPtr unmanagedString;
178             unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Name"));
179             if (unmanagedString != IntPtr.Zero)
180             {
181                 Name = Marshal.PtrToStringUni(unmanagedString);
182             }
183
184             unmanagedString = Marshal.ReadIntPtr(unmanagedAddress, (int)Marshal.OffsetOf(typeof(SecurityPackageInfo), "Comment"));
185             if (unmanagedString != IntPtr.Zero)
186             {
187
188                 Comment = Marshal.PtrToStringUni(unmanagedString);
189             }
190         }
191
192     }
193
194
195     // we keep it simple since we use this only to know if NTLM or
196     // Kerberos are used in the context of a Negotiate handshake
197     internal class NegotiationInfoClass
198     {
199         internal const string NTLM = "NTLM";
200         internal const string Kerberos = "Kerberos";
201         internal string AuthenticationPackage;
202
203         internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState)
204         {
205             if (safeHandle.IsInvalid)
206             {
207                 return;
208             }
209             IntPtr packageInfo = safeHandle.DangerousGetHandle();
210
211             const int SECPKG_NEGOTIATION_COMPLETE = 0;
212             const int SECPKG_NEGOTIATION_OPTIMISTIC = 1;
213             // const int SECPKG_NEGOTIATION_IN_PROGRESS     = 2;
214             // const int SECPKG_NEGOTIATION_DIRECT          = 3;
215             // const int SECPKG_NEGOTIATION_TRY_MULTICRED   = 4;
216
217             if (negotiationState == SECPKG_NEGOTIATION_COMPLETE || negotiationState == SECPKG_NEGOTIATION_OPTIMISTIC)
218             {
219                 IntPtr unmanagedString = Marshal.ReadIntPtr(packageInfo, SecurityPackageInfo.NameOffest);
220                 string name = null;
221                 if (unmanagedString != IntPtr.Zero)
222                 {
223                     name = Marshal.PtrToStringUni(unmanagedString);
224                 }
225                 // an optimization for future string comparisons
226                 if (string.Compare(name, "Kerberos", StringComparison.OrdinalIgnoreCase) == 0)
227                 {
228                     AuthenticationPackage = Kerberos;
229                 }
230                 else if (string.Compare(name, "NTLM", StringComparison.OrdinalIgnoreCase) == 0)
231                 {
232                     AuthenticationPackage = NTLM;
233                 }
234                 else
235                 {
236                     AuthenticationPackage = name;
237                 }
238             }
239         }
240     }
241
242     internal class SecuritySessionKeyClass
243     {
244         byte[] sessionKey;
245
246         internal SecuritySessionKeyClass(SafeHandle safeHandle, int sessionKeyLength)
247         {
248             byte[] sessionKey = new byte[sessionKeyLength];
249             Marshal.Copy(safeHandle.DangerousGetHandle(), sessionKey, 0, sessionKeyLength);
250             this.sessionKey = sessionKey;
251         }
252
253         internal byte[] SessionKey
254         {
255             get { return this.sessionKey; }
256         }
257     }
258
259     [StructLayout(LayoutKind.Sequential)]
260     internal class StreamSizes
261     {
262         public int header;
263         public int trailer;
264         public int maximumMessage;
265         public int buffersCount;
266         public int blockSize;
267
268         internal unsafe StreamSizes(byte[] memory)
269         {
270             fixed (void* voidPtr = memory)
271             {
272                 IntPtr unmanagedAddress = new IntPtr(voidPtr);
273                 header = Marshal.ReadInt32(unmanagedAddress);
274                 trailer = Marshal.ReadInt32(unmanagedAddress, 4);
275                 maximumMessage = Marshal.ReadInt32(unmanagedAddress, 8);
276                 buffersCount = Marshal.ReadInt32(unmanagedAddress, 12);
277                 blockSize = Marshal.ReadInt32(unmanagedAddress, 16);
278             }
279         }
280         public static readonly int SizeOf = Marshal.SizeOf(typeof(StreamSizes));
281     }
282
283     internal static class SspiWrapper
284     {
285         const int SECPKG_FLAG_NEGOTIABLE2 = 0x00200000;
286
287         static SecurityPackageInfoClass[] securityPackages;
288
289         public static SecurityPackageInfoClass[] SecurityPackages
290         {
291             get
292             {
293                 return securityPackages;
294             }
295             set
296             {
297                 securityPackages = value;
298             }
299         }
300
301         static SecurityPackageInfoClass[] EnumerateSecurityPackages()
302         {
303             if (SecurityPackages != null)
304             {
305                 return SecurityPackages;
306             }
307
308             int moduleCount = 0;
309             SafeFreeContextBuffer arrayBaseHandle = null;
310             try
311             {
312                 int errorCode = SafeFreeContextBuffer.EnumeratePackages(out moduleCount, out arrayBaseHandle);
313                 if (errorCode != 0)
314                 {
315                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
316                 }
317
318                 SecurityPackageInfoClass[] securityPackages = new SecurityPackageInfoClass[moduleCount];
319                 for (int i = 0; i < moduleCount; i++)
320                 {
321                     securityPackages[i] = new SecurityPackageInfoClass(arrayBaseHandle, i);
322                 }
323                 SecurityPackages = securityPackages;
324             }
325             finally
326             {
327                 if (arrayBaseHandle != null)
328                 {
329                     arrayBaseHandle.Close();
330                 }
331             }
332
333             return SecurityPackages;
334         }
335
336         public static SecurityPackageInfoClass GetVerifyPackageInfo(string packageName)
337         {
338             SecurityPackageInfoClass[] supportedSecurityPackages = EnumerateSecurityPackages();
339             if (supportedSecurityPackages != null)
340             {
341                 for (int i = 0; i < supportedSecurityPackages.Length; i++)
342                 {
343                     if (String.Compare(supportedSecurityPackages[i].Name, packageName, StringComparison.OrdinalIgnoreCase) == 0)
344                     {
345                         return supportedSecurityPackages[i];
346                     }
347                 }
348             }
349
350             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SSPIPackageNotSupported, packageName)));
351         }
352
353         public static bool IsNegotiateExPackagePresent()
354         {
355             SecurityPackageInfoClass[] supportedSecurityPackages = EnumerateSecurityPackages();
356
357             if (supportedSecurityPackages != null)
358             {
359                 int nego2FlagIntValue = (int)SECPKG_FLAG_NEGOTIABLE2;
360
361                 for (int i = 0; i < supportedSecurityPackages.Length; i++)
362                 {
363                     // if the package is a nego2 package
364                     if ((supportedSecurityPackages[i].Capabilities & nego2FlagIntValue) != 0)
365                     {
366                         return true;
367                     }
368                 }
369             }
370
371             return false;
372         }
373
374         public static SafeFreeCredentials AcquireDefaultCredential(
375             string package,
376             CredentialUse intent,
377             params string[] additionalPackages)
378         {
379             SafeFreeCredentials outCredential = null;
380             AuthIdentityEx authIdentity = new AuthIdentityEx(null, null, null, additionalPackages);
381             int errorCode = SafeFreeCredentials.AcquireDefaultCredential(package, intent, ref authIdentity, out outCredential);
382             if (errorCode != 0)
383             {
384                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
385             }
386             return outCredential;
387         }
388
389         public static SafeFreeCredentials AcquireCredentialsHandle(
390             string package,
391             CredentialUse intent,
392             ref AuthIdentityEx authdata)
393         {
394             SafeFreeCredentials credentialsHandle = null;
395             int errorCode = SafeFreeCredentials.AcquireCredentialsHandle(package,
396                 intent,
397                 ref authdata,
398                 out credentialsHandle
399                 );
400             if (errorCode != 0)
401             {
402                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
403             }
404             return credentialsHandle;
405         }
406
407         public static SafeFreeCredentials AcquireCredentialsHandle(
408             string package,
409             CredentialUse intent,
410             SecureCredential scc)
411         {
412             SafeFreeCredentials outCredential = null;
413             int errorCode = SafeFreeCredentials.AcquireCredentialsHandle(
414                 package,
415                 intent,
416                 ref scc,
417                 out outCredential
418                 );
419             if (errorCode != 0)
420             {
421                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
422             }
423             return outCredential;
424         }
425
426         public static SafeFreeCredentials AcquireCredentialsHandle(
427         string package,
428         CredentialUse intent,
429         ref IntPtr ppAuthIdentity)
430         {
431             SafeFreeCredentials outCredential = null;
432             int errorCode = SafeFreeCredentials.AcquireCredentialsHandle(
433                 package,
434                 intent,
435                 ref ppAuthIdentity,
436                 out outCredential
437                 );
438             if (errorCode != 0)
439             {
440                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
441             }
442             return outCredential;
443         }
444
445         internal static int InitializeSecurityContext(
446             SafeFreeCredentials credential,
447             ref SafeDeleteContext context,
448             string targetName,
449             SspiContextFlags inFlags,
450             Endianness datarep,
451             SecurityBuffer inputBuffer,
452             SecurityBuffer outputBuffer,
453             ref SspiContextFlags outFlags)
454         {
455             return SafeDeleteContext.InitializeSecurityContext(credential, ref context, targetName, inFlags, datarep, inputBuffer, null, outputBuffer, ref outFlags);
456         }
457
458         internal static int InitializeSecurityContext(
459             SafeFreeCredentials credential,
460             ref SafeDeleteContext context,
461             string targetName,
462             SspiContextFlags inFlags,
463             Endianness datarep,
464             SecurityBuffer[] inputBuffers,
465             SecurityBuffer outputBuffer,
466             ref SspiContextFlags outFlags)
467         {
468             return SafeDeleteContext.InitializeSecurityContext(credential, ref context, targetName, inFlags, datarep, null, inputBuffers, outputBuffer, ref outFlags);
469         }
470
471         internal static int AcceptSecurityContext(
472             SafeFreeCredentials credential,
473             ref SafeDeleteContext refContext,
474             SspiContextFlags inFlags,
475             Endianness datarep,
476             SecurityBuffer inputBuffer,
477             SecurityBuffer outputBuffer,
478             ref SspiContextFlags outFlags)
479         {
480             return SafeDeleteContext.AcceptSecurityContext(credential, ref refContext, inFlags, datarep, inputBuffer, null, outputBuffer, ref outFlags);
481         }
482
483         internal static int AcceptSecurityContext(
484             SafeFreeCredentials credential,
485             ref SafeDeleteContext refContext,
486             SspiContextFlags inFlags,
487             Endianness datarep,
488             SecurityBuffer[] inputBuffers,
489             SecurityBuffer outputBuffer,
490             ref SspiContextFlags outFlags)
491         {
492             return SafeDeleteContext.AcceptSecurityContext(credential, ref refContext, inFlags, datarep, null, inputBuffers, outputBuffer, ref outFlags);
493         }
494
495         public static int QuerySecurityContextToken(
496             SafeDeleteContext context,
497             out SafeCloseHandle token)
498         {
499             return context.GetSecurityContextToken(out token);
500         }
501
502         static unsafe int QueryContextAttributes(SafeDeleteContext phContext, ContextAttribute attribute, byte[] buffer, Type handleType, out SafeHandle refHandle)
503         {
504             refHandle = null;
505             if (handleType != null)
506             {
507                 if (handleType == typeof(SafeFreeContextBuffer))
508                 {
509                     refHandle = SafeFreeContextBuffer.CreateEmptyHandle();
510                 }
511                 else if (handleType == typeof(SafeFreeCertContext))
512                 {
513                     refHandle = new SafeFreeCertContext();
514                 }
515                 else
516                 {
517                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("handleType", SR.GetString(SR.ValueMustBeOf2Types, typeof(SafeFreeContextBuffer).ToString(), typeof(SafeFreeCertContext).ToString())));
518                 }
519             }
520             fixed (byte* bufferPtr = buffer)
521             {
522                 return SafeFreeContextBuffer.QueryContextAttributes(phContext, attribute, bufferPtr, refHandle);
523             }
524         }
525
526         public static unsafe object QueryContextAttributes(
527             SafeDeleteContext securityContext,
528             ContextAttribute contextAttribute)
529         {
530             int nativeBlockSize = IntPtr.Size;
531             Type handleType = null;
532
533             switch (contextAttribute)
534             {
535                 case ContextAttribute.Flags:
536                     break;
537                 case ContextAttribute.Sizes:
538                     nativeBlockSize = SecSizes.SizeOf;
539                     break;
540                 case ContextAttribute.StreamSizes:
541                     nativeBlockSize = StreamSizes.SizeOf;
542                     break;
543                 case ContextAttribute.Names:
544                     handleType = typeof(SafeFreeContextBuffer);
545                     break;
546                 case ContextAttribute.PackageInfo:
547                     handleType = typeof(SafeFreeContextBuffer);
548                     break;
549                 case ContextAttribute.NegotiationInfo:
550                     handleType = typeof(SafeFreeContextBuffer);
551                     nativeBlockSize = Marshal.SizeOf(typeof(NegotiationInfo));
552                     break;
553                 case ContextAttribute.RemoteCertificate:
554                     handleType = typeof(SafeFreeCertContext);
555                     break;
556                 case ContextAttribute.LocalCertificate:
557                     handleType = typeof(SafeFreeCertContext);
558                     break;
559                 case ContextAttribute.ConnectionInfo:
560                     nativeBlockSize = Marshal.SizeOf(typeof(SslConnectionInfo));
561                     break;
562                 case ContextAttribute.Lifespan:
563                     nativeBlockSize = LifeSpan_Struct.Size;
564                     break;
565                 case ContextAttribute.SessionKey:
566                     handleType = typeof(SafeFreeContextBuffer);
567                     nativeBlockSize = SecPkgContext_SessionKey.Size;
568                     break;
569                 default:
570                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("contextAttribute", (int)contextAttribute,
571                     typeof(ContextAttribute)));
572             }
573
574             SafeHandle sspiHandle = null;
575             object attribute = null;
576             try
577             {
578                 byte[] nativeBuffer = new byte[nativeBlockSize];
579                 int errorCode = QueryContextAttributes(securityContext, contextAttribute, nativeBuffer, handleType, out sspiHandle);
580                 if (errorCode != 0)
581                 {
582                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
583                 }
584
585                 switch (contextAttribute)
586                 {
587                     case ContextAttribute.Flags:
588                         fixed (byte* pnativeBuffer = nativeBuffer)
589                         {
590                             attribute = (object)Marshal.ReadInt32(new IntPtr(pnativeBuffer));
591                         }
592                         break;
593                     case ContextAttribute.Sizes:
594                         attribute = new SecSizes(nativeBuffer);
595                         break;
596                     case ContextAttribute.StreamSizes:
597                         attribute = new StreamSizes(nativeBuffer);
598                         break;
599                     case ContextAttribute.Names:
600                         attribute = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle());
601                         break;
602                     case ContextAttribute.PackageInfo:
603                         attribute = new SecurityPackageInfoClass(sspiHandle, 0);
604                         break;
605                     case ContextAttribute.NegotiationInfo:
606                         unsafe
607                         {
608                             fixed (void* ptr = nativeBuffer)
609                             {
610                                 attribute = new NegotiationInfoClass(sspiHandle, Marshal.ReadInt32(new IntPtr(ptr), NegotiationInfo.NegotiationStateOffset));
611                             }
612                         }
613                         break;
614                     case ContextAttribute.LocalCertificate:
615                         goto case ContextAttribute.RemoteCertificate;
616                     case ContextAttribute.RemoteCertificate:
617                         attribute = sspiHandle;
618                         sspiHandle = null;
619                         break;
620                     case ContextAttribute.ConnectionInfo:
621                         attribute = new SslConnectionInfo(nativeBuffer);
622                         break;
623                     case ContextAttribute.Lifespan:
624                         attribute = new LifeSpan(nativeBuffer);
625                         break;
626                     case ContextAttribute.SessionKey:
627                         unsafe
628                         {
629                             fixed (void* ptr = nativeBuffer)
630                             {
631                                 attribute = new SecuritySessionKeyClass(sspiHandle, Marshal.ReadInt32(new IntPtr(ptr)));
632                             }
633                         }
634                         break;
635                     default:
636                         // will return null
637                         break;
638                 }
639             }
640             finally
641             {
642                 if (sspiHandle != null)
643                 {
644                     sspiHandle.Close();
645                 }
646             }
647             return attribute;
648         }
649
650         /// <summary>
651         /// Queries the security context for the target name (SPN for kerb)
652         /// </summary>
653         /// <param name="securityContext">security context to query</param>
654         /// <param name="specifiedTarget">output parameter for the name</param>
655         /// <returns>the status code returned from querying the context</returns>
656         public static unsafe int QuerySpecifiedTarget(SafeDeleteContext securityContext, out string specifiedTarget)
657         {
658             int nativeBlockSize = IntPtr.Size;
659             Type handleType = typeof(SafeFreeContextBuffer);
660             SafeHandle sspiHandle = null;
661             int errorCode;
662
663             specifiedTarget = null;
664             try
665             {
666                 byte[] nativeBuffer = new byte[nativeBlockSize];
667                 errorCode = QueryContextAttributes(securityContext, ContextAttribute.SpecifiedTarget, nativeBuffer, handleType, out sspiHandle);
668                 if (errorCode != (int)SecurityStatus.OK)
669                 {
670                     return errorCode;
671                 }
672
673                 specifiedTarget = Marshal.PtrToStringUni(sspiHandle.DangerousGetHandle()) as string;
674             }
675             finally
676             {
677                 if (sspiHandle != null)
678                 {
679                     sspiHandle.Close();
680                 }
681             }
682             return errorCode;
683         }
684
685         public static void ImpersonateSecurityContext(
686             SafeDeleteContext context)
687         {
688             int errorCode = SafeDeleteContext.ImpersonateSecurityContext(context);
689             if (errorCode != (int)SecurityStatus.OK)
690             {
691                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
692             }
693         }
694
695         public static unsafe int EncryptDecryptHelper(SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber, bool encrypt, bool isGssBlob)
696         {
697             SecurityBufferDescriptor sdcInOut = new SecurityBufferDescriptor(input.Length);
698             SecurityBufferStruct[] unmanagedBuffer = new SecurityBufferStruct[input.Length];
699             byte[][] buffers = new byte[input.Length][];
700             fixed (void* unmanagedBufferPtr = unmanagedBuffer)
701             {
702                 sdcInOut.UnmanagedPointer = unmanagedBufferPtr;
703                 GCHandle[] pinnedBuffers = new GCHandle[input.Length];
704                 try
705                 {
706                     for (int i = 0; i < input.Length; ++i)
707                     {
708                         SecurityBuffer iBuffer = input[i];
709                         unmanagedBuffer[i].count = iBuffer.size;
710                         unmanagedBuffer[i].type = iBuffer.type;
711                         if (iBuffer.token == null || iBuffer.token.Length == 0)
712                         {
713                             unmanagedBuffer[i].token = IntPtr.Zero;
714                         }
715                         else
716                         {
717                             pinnedBuffers[i] = GCHandle.Alloc(iBuffer.token, GCHandleType.Pinned);
718                             unmanagedBuffer[i].token = Marshal.UnsafeAddrOfPinnedArrayElement(iBuffer.token, iBuffer.offset);
719                             buffers[i] = iBuffer.token;
720                         }
721                     }
722                     int errorCode;
723                     if (encrypt)
724                     {
725                         errorCode = SafeDeleteContext.EncryptMessage(context, sdcInOut, sequenceNumber);
726                     }
727                     else
728                     {
729                         errorCode = SafeDeleteContext.DecryptMessage(context, sdcInOut, sequenceNumber);
730                     }
731                     // Marshalling back returned sizes (do not marshal the "token" field)
732                     for (int i = 0; i < input.Length; ++i)
733                     {
734                         SecurityBuffer iBuffer = input[i];
735                         iBuffer.size = unmanagedBuffer[i].count;
736                         iBuffer.type = unmanagedBuffer[i].type;
737                         if (iBuffer.size == 0)
738                         {
739                             iBuffer.offset = 0;
740                             iBuffer.token = null;
741                         }
742                         else if (isGssBlob && !encrypt && iBuffer.type == BufferType.Data)
743                         {
744                             iBuffer.token = DiagnosticUtility.Utility.AllocateByteArray(iBuffer.size);
745                             Marshal.Copy(unmanagedBuffer[i].token, iBuffer.token, 0, iBuffer.size);
746                         }
747                         else checked
748                             {
749                                 // Find the buffer this is inside of.  Usually they all point inside buffer 0.
750                                 int j;
751                                 for (j = 0; j < input.Length; j++)
752                                 {
753                                     if (buffers[j] == null)
754                                     {
755                                         continue;
756                                     }
757
758                                     byte* bufferAddress = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(buffers[j], 0);
759                                     if ((byte*)unmanagedBuffer[i].token >= bufferAddress &&
760                                         (byte*)unmanagedBuffer[i].token + iBuffer.size <= bufferAddress + buffers[j].Length)
761                                     {
762                                         iBuffer.offset = (int)((byte*)unmanagedBuffer[i].token - bufferAddress);
763                                         iBuffer.token = buffers[j];
764                                         break;
765                                     }
766                                 }
767
768                                 if (j >= input.Length)
769                                 {
770                                     iBuffer.size = 0;
771                                     iBuffer.offset = 0;
772                                     iBuffer.token = null;
773                                 }
774                                 if (!(iBuffer.offset >= 0 && iBuffer.offset <= (iBuffer.token == null ? 0 : iBuffer.token.Length)))
775                                 {
776                                     DiagnosticUtility.DebugAssert(SR.GetString(SR.SspiWrapperEncryptDecryptAssert1, iBuffer.offset));
777                                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SspiWrapperEncryptDecryptAssert1, iBuffer.offset)));
778
779                                 }
780                                 if (!(iBuffer.size >= 0 && iBuffer.size <= (iBuffer.token == null ? 0 : iBuffer.token.Length - iBuffer.offset)))
781                                 {
782                                     DiagnosticUtility.DebugAssert(SR.GetString(SR.SspiWrapperEncryptDecryptAssert2, iBuffer.size));
783                                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SspiWrapperEncryptDecryptAssert2, iBuffer.size)));
784                                 }
785                             }
786                     }
787                     return errorCode;
788                 }
789                 finally
790                 {
791                     for (int i = 0; i < pinnedBuffers.Length; ++i)
792                     {
793                         if (pinnedBuffers[i].IsAllocated)
794                         {
795                             pinnedBuffers[i].Free();
796                         }
797                     }
798                 }
799             }
800         }
801
802         public static unsafe int EncryptMessage(SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber)
803         {
804             return EncryptDecryptHelper(context, input, sequenceNumber, true, false);
805         }
806
807         public static unsafe int DecryptMessage(SafeDeleteContext context, SecurityBuffer[] input, uint sequenceNumber, bool isGssBlob)
808         {
809             return EncryptDecryptHelper(context, input, sequenceNumber, false, isGssBlob);
810         }
811
812         public static unsafe uint SspiPromptForCredential(string targetName, string packageName, out IntPtr ppAuthIdentity, ref bool saveCredentials)
813         {
814             CREDUI_INFO credui_Info = new CREDUI_INFO();
815             credui_Info.cbSize = Marshal.SizeOf(typeof(CREDUI_INFO));
816
817             credui_Info.pszCaptionText = SR.GetString(SR.SspiLoginPromptHeaderMessage); // Login
818             credui_Info.pszMessageText = "";
819             uint retCode = uint.MaxValue;
820             retCode = NativeMethods.SspiPromptForCredentials(targetName, ref credui_Info, 0, packageName, IntPtr.Zero, out ppAuthIdentity, ref saveCredentials, 0);
821             return retCode;
822         }
823
824         public static unsafe bool IsSspiPromptingNeeded(uint ErrorOrNtStatus)
825         {
826             return NativeMethods.SspiIsPromptingNeeded(ErrorOrNtStatus);
827         }
828
829         //public static string ErrorDescription(int errorCode) 
830         //{
831         //    if (errorCode == -1) 
832         //    {
833         //        return "An exception when invoking Win32 API";
834         //    }
835         //    switch ((SecurityStatus) errorCode) 
836         //    {
837         //        case SecurityStatus.InvalidHandle:
838         //            return "Invalid handle";
839         //        case SecurityStatus.InvalidToken:
840         //            return "Invalid token";
841         //        case SecurityStatus.ContinueNeeded:
842         //            return "Continue needed";
843         //        case SecurityStatus.IncompleteMessage:
844         //            return "Message incomplete";
845         //        case SecurityStatus.WrongPrincipal:
846         //            return "Wrong principal";
847         //        case SecurityStatus.TargetUnknown:
848         //            return "Target unknown";
849         //        case SecurityStatus.PackageNotFound:
850         //            return "Package not found";
851         //        case SecurityStatus.BufferNotEnough:
852         //            return "Buffer not enough";
853         //        case SecurityStatus.MessageAltered:
854         //            return "Message altered";
855         //        case SecurityStatus.UntrustedRoot:
856         //            return "Untrusted root";
857         //        default:
858         //            return "0x" + errorCode.ToString("x", NumberFormatInfo.InvariantInfo);
859         //    }
860         //}
861     }
862
863     //From Schannel.h
864     [StructLayout(LayoutKind.Sequential)]
865     internal class SslConnectionInfo
866     {
867         public readonly int Protocol;
868         public readonly int DataCipherAlg;
869         public readonly int DataKeySize;
870         public readonly int DataHashAlg;
871         public readonly int DataHashKeySize;
872         public readonly int KeyExchangeAlg;
873         public readonly int KeyExchKeySize;
874
875         internal unsafe SslConnectionInfo(byte[] nativeBuffer)
876         {
877             fixed (void* voidPtr = nativeBuffer)
878             {
879                 IntPtr unmanagedAddress = new IntPtr(voidPtr);
880                 Protocol = Marshal.ReadInt32(unmanagedAddress);
881                 DataCipherAlg = Marshal.ReadInt32(unmanagedAddress, 4);
882                 DataKeySize = Marshal.ReadInt32(unmanagedAddress, 8);
883                 DataHashAlg = Marshal.ReadInt32(unmanagedAddress, 12);
884                 DataHashKeySize = Marshal.ReadInt32(unmanagedAddress, 16);
885                 KeyExchangeAlg = Marshal.ReadInt32(unmanagedAddress, 20);
886                 KeyExchKeySize = Marshal.ReadInt32(unmanagedAddress, 24);
887             }
888         }
889     }
890
891     [StructLayout(LayoutKind.Sequential)]
892     internal class SecSizes
893     {
894         public int MaxToken;
895         public int MaxSignature;
896         public int BlockSize;
897         public int SecurityTrailer;
898
899         internal unsafe SecSizes(byte[] memory)
900         {
901             fixed (void* voidPtr = memory)
902             {
903                 IntPtr unmanagedAddress = new IntPtr(voidPtr);
904                 MaxToken = Marshal.ReadInt32(unmanagedAddress);
905                 MaxSignature = Marshal.ReadInt32(unmanagedAddress, 4);
906                 BlockSize = Marshal.ReadInt32(unmanagedAddress, 8);
907                 SecurityTrailer = Marshal.ReadInt32(unmanagedAddress, 12);
908             }
909         }
910         public static readonly int SizeOf = Marshal.SizeOf(typeof(SecSizes));
911     }
912
913     [StructLayout(LayoutKind.Sequential)]
914     internal struct Bindings
915     {
916         // see SecPkgContext_Bindings in <sspi.h>
917         internal int BindingsLength;
918         internal IntPtr pBindings;
919     }
920 }