Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Security / SecurityUtils.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.ServiceModel.Security
6 {
7     using System.Collections.Generic;
8     using System.Collections.ObjectModel;
9     using System.ComponentModel;
10     using System.Diagnostics;
11     using System.DirectoryServices.ActiveDirectory;
12     using System.Globalization;
13     using System.IdentityModel.Claims;
14     using System.IdentityModel.Policy;
15     using System.IdentityModel.Selectors;
16     using System.IdentityModel.Tokens;
17     using System.Net;
18     using System.Net.Security;
19     using System.Runtime;
20     using System.Security;
21     using System.Security.Authentication;
22     using System.Security.Authentication.ExtendedProtection;
23     using System.Security.Cryptography;
24     using System.Security.Cryptography.X509Certificates;
25     using System.Security.Permissions;
26     using System.Security.Principal;
27     using System.ServiceModel;
28     using System.ServiceModel.Channels;
29     using System.ServiceModel.Description;
30     using System.ServiceModel.Diagnostics;
31     using System.ServiceModel.Dispatcher;
32     using System.ServiceModel.Security.Tokens;
33     using System.Text;
34     using System.Threading;
35     using System.Xml;
36     using Microsoft.Win32;
37     using AuthIdentityEx = System.IdentityModel.AuthIdentityEx;
38     using CredentialUse = System.IdentityModel.CredentialUse;
39     using DictionaryManager = System.IdentityModel.DictionaryManager;
40     using SafeFreeCredentials = System.IdentityModel.SafeFreeCredentials;
41     using SspiWrapper = System.IdentityModel.SspiWrapper;
42
43     static class StoreLocationHelper
44     {
45         internal static bool IsDefined(StoreLocation value)
46         {
47             return (value == StoreLocation.CurrentUser
48                 || value == StoreLocation.LocalMachine);
49         }
50     }
51
52     static class ProtectionLevelHelper
53     {
54         internal static bool IsDefined(ProtectionLevel value)
55         {
56             return (value == ProtectionLevel.None
57                 || value == ProtectionLevel.Sign
58                 || value == ProtectionLevel.EncryptAndSign);
59         }
60
61         internal static void Validate(ProtectionLevel value)
62         {
63             if (!IsDefined(value))
64             {
65                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("value", (int)value,
66                     typeof(ProtectionLevel)));
67             }
68         }
69
70         internal static bool IsStronger(ProtectionLevel v1, ProtectionLevel v2)
71         {
72             return ((v1 == ProtectionLevel.EncryptAndSign && v2 != ProtectionLevel.EncryptAndSign)
73                     || (v1 == ProtectionLevel.Sign && v2 == ProtectionLevel.None));
74         }
75
76         internal static bool IsStrongerOrEqual(ProtectionLevel v1, ProtectionLevel v2)
77         {
78             return (v1 == ProtectionLevel.EncryptAndSign
79                     || (v1 == ProtectionLevel.Sign && v2 != ProtectionLevel.EncryptAndSign));
80         }
81
82         internal static ProtectionLevel Max(ProtectionLevel v1, ProtectionLevel v2)
83         {
84             return IsStronger(v1, v2) ? v1 : v2;
85         }
86
87         internal static int GetOrdinal(Nullable<ProtectionLevel> p)
88         {
89             if (p.HasValue)
90             {
91                 switch ((ProtectionLevel)p)
92                 {
93                     default:
94                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("p", (int)p,
95                         typeof(ProtectionLevel)));
96                     case ProtectionLevel.None:
97                         return 2;
98                     case ProtectionLevel.Sign:
99                         return 3;
100                     case ProtectionLevel.EncryptAndSign:
101                         return 4;
102                 }
103             }
104             else
105                 return 1;
106         }
107     }
108
109     static class SslProtocolsHelper
110     {
111         internal static bool IsDefined(SslProtocols value)
112         {
113             SslProtocols allValues = SslProtocols.None;
114             foreach (var protocol in Enum.GetValues(typeof(SslProtocols)))
115             {
116                 allValues |= (SslProtocols)protocol;
117             }
118             return (value & allValues) == value;
119         }
120
121         internal static void Validate(SslProtocols value)
122         {
123             if (!IsDefined(value))
124             {
125                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("value", (int)value,
126                     typeof(SslProtocols)));
127             }
128         }
129     }
130
131     static class TokenImpersonationLevelHelper
132     {
133         internal static bool IsDefined(TokenImpersonationLevel value)
134         {
135             return (value == TokenImpersonationLevel.None
136                 || value == TokenImpersonationLevel.Anonymous
137                 || value == TokenImpersonationLevel.Identification
138                 || value == TokenImpersonationLevel.Impersonation
139                 || value == TokenImpersonationLevel.Delegation);
140         }
141
142         internal static void Validate(TokenImpersonationLevel value)
143         {
144             if (!IsDefined(value))
145             {
146                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("value", (int)value,
147                     typeof(TokenImpersonationLevel)));
148             }
149         }
150
151         static TokenImpersonationLevel[] TokenImpersonationLevelOrder = new TokenImpersonationLevel[]
152             {
153                 TokenImpersonationLevel.None,
154                 TokenImpersonationLevel.Anonymous,
155                 TokenImpersonationLevel.Identification,
156                 TokenImpersonationLevel.Impersonation,
157                 TokenImpersonationLevel.Delegation
158             };
159
160         internal static string ToString(TokenImpersonationLevel impersonationLevel)
161         {
162             if (impersonationLevel == TokenImpersonationLevel.Identification)
163             {
164                 return "identification";
165             }
166             else if (impersonationLevel == TokenImpersonationLevel.None)
167             {
168                 return "none";
169             }
170             else if (impersonationLevel == TokenImpersonationLevel.Anonymous)
171             {
172                 return "anonymous";
173             }
174             else if (impersonationLevel == TokenImpersonationLevel.Impersonation)
175             {
176                 return "impersonation";
177             }
178             else if (impersonationLevel == TokenImpersonationLevel.Delegation)
179             {
180                 return "delegation";
181             }
182
183             Fx.Assert("unknown token impersonation level");
184             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("impersonationLevel", (int)impersonationLevel,
185             typeof(TokenImpersonationLevel)));
186         }
187
188         internal static bool IsGreaterOrEqual(TokenImpersonationLevel x, TokenImpersonationLevel y)
189         {
190             TokenImpersonationLevelHelper.Validate(x);
191             TokenImpersonationLevelHelper.Validate(y);
192
193             if (x == y)
194                 return true;
195
196             int px = 0;
197             int py = 0;
198             for (int i = 0; i < TokenImpersonationLevelOrder.Length; i++)
199             {
200                 if (x == TokenImpersonationLevelOrder[i])
201                     px = i;
202                 if (y == TokenImpersonationLevelOrder[i])
203                     py = i;
204             }
205
206             return (px > py);
207         }
208
209         internal static int Compare(TokenImpersonationLevel x, TokenImpersonationLevel y)
210         {
211             int result = 0;
212
213             if (x != y)
214             {
215                 switch (x)
216                 {
217                     case TokenImpersonationLevel.Identification:
218                         result = -1;
219                         break;
220                     case TokenImpersonationLevel.Impersonation:
221                         switch (y)
222                         {
223                             case TokenImpersonationLevel.Identification:
224                                 result = 1;
225                                 break;
226                             case TokenImpersonationLevel.Delegation:
227                                 result = -1;
228                                 break;
229                             default:
230                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("y", (int)y,
231                                     typeof(TokenImpersonationLevel)));
232
233                         }
234                         break;
235                     case TokenImpersonationLevel.Delegation:
236                         result = 1;
237                         break;
238                     default:
239                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("x", (int)x,
240                             typeof(TokenImpersonationLevel)));
241
242                 }
243             }
244
245             return result;
246         }
247     }
248
249     internal class ServiceModelDictionaryManager
250     {
251         static DictionaryManager dictionaryManager;
252
253         public static DictionaryManager Instance
254         {
255             get
256             {
257                 if (dictionaryManager == null)
258                     dictionaryManager = new DictionaryManager(BinaryMessageEncoderFactory.XmlDictionary);
259
260                 return dictionaryManager;
261             }
262         }
263     }
264
265     static class SecurityUtils
266     {
267         public const string Principal = "Principal";
268         public const string Identities = "Identities";
269         static bool computedDomain;
270         static string currentDomain;
271         static byte[] combinedHashLabel;
272         static IIdentity anonymousIdentity;
273         static NetworkCredential dummyNetworkCredential;
274         static object dummyNetworkCredentialLock = new object();
275         static X509SecurityTokenAuthenticator nonValidatingX509Authenticator;
276         static SecurityIdentifier administratorsSid;
277         const int WindowsServerMajorNumber = 5;
278         const int WindowsServerMinorNumber = 2;
279         const int XPMajorNumber = 5;
280         const int XPMinorNumber = 1;
281         const string ServicePack1 = "Service Pack 1";
282         const string ServicePack2 = "Service Pack 2";
283         volatile static bool shouldValidateSslCipherStrength;
284         volatile static bool isSslValidationRequirementDetermined = false;
285         static readonly int MinimumSslCipherStrength = 128;
286
287         // these are kept in sync with IIS70
288         public const string AuthTypeNTLM = "NTLM";
289         public const string AuthTypeNegotiate = "Negotiate";
290         public const string AuthTypeKerberos = "Kerberos";
291         public const string AuthTypeAnonymous = "";
292         public const string AuthTypeCertMap = "SSL/PCT"; // mapped from a cert
293         public const string AuthTypeBasic = "Basic"; //LogonUser
294
295         public static ChannelBinding GetChannelBindingFromMessage(Message message)
296         {
297             if (message == null)
298             {
299                 return null;
300             }
301
302             ChannelBindingMessageProperty channelBindingMessageProperty = null;
303             ChannelBindingMessageProperty.TryGet(message, out channelBindingMessageProperty);
304             ChannelBinding channelBinding = null;
305
306             if (channelBindingMessageProperty != null)
307             {
308                 channelBinding = channelBindingMessageProperty.ChannelBinding;
309             }
310
311             return channelBinding;
312         }
313
314         internal static bool IsOsGreaterThanXP()
315         {
316             return ((Environment.OSVersion.Version.Major >= SecurityUtils.XPMajorNumber && Environment.OSVersion.Version.Minor > SecurityUtils.XPMinorNumber) ||
317                     Environment.OSVersion.Version.Major > SecurityUtils.XPMajorNumber);
318         }
319
320         internal static bool IsOSGreaterThanOrEqualToWin7()
321         {
322             Version windows7Version = new Version(6, 1, 0, 0);
323             return (Environment.OSVersion.Version.Major >= windows7Version.Major && Environment.OSVersion.Version.Minor >= windows7Version.Minor);
324         }
325
326         internal static bool IsCurrentlyTimeEffective(DateTime effectiveTime, DateTime expirationTime, TimeSpan maxClockSkew)
327         {
328             DateTime curEffectiveTime = (effectiveTime < DateTime.MinValue.Add(maxClockSkew)) ? effectiveTime : effectiveTime.Subtract(maxClockSkew);
329             DateTime curExpirationTime = (expirationTime > DateTime.MaxValue.Subtract(maxClockSkew)) ? expirationTime : expirationTime.Add(maxClockSkew);
330             DateTime curTime = DateTime.UtcNow;
331
332             return (curEffectiveTime.ToUniversalTime() <= curTime) && (curTime < curExpirationTime.ToUniversalTime());
333         }
334
335         internal static X509SecurityTokenAuthenticator NonValidatingX509Authenticator
336         {
337             get
338             {
339                 if (nonValidatingX509Authenticator == null)
340                 {
341                     nonValidatingX509Authenticator = new X509SecurityTokenAuthenticator(X509CertificateValidator.None);
342                 }
343                 return nonValidatingX509Authenticator;
344             }
345         }
346
347         public static SecurityIdentifier AdministratorsSid
348         {
349             get
350             {
351                 if (administratorsSid == null)
352                     administratorsSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
353                 return administratorsSid;
354             }
355         }
356
357         internal static IIdentity AnonymousIdentity
358         {
359             get
360             {
361                 if (anonymousIdentity == null)
362                 {
363                     anonymousIdentity = SecurityUtils.CreateIdentity(String.Empty);
364                 }
365                 return anonymousIdentity;
366             }
367         }
368
369         public static DateTime MaxUtcDateTime
370         {
371             get
372             {
373                 // + and -  TimeSpan.TicksPerDay is to compensate the DateTime.ParseExact (to localtime) overflow.
374                 return new DateTime(DateTime.MaxValue.Ticks - TimeSpan.TicksPerDay, DateTimeKind.Utc);
375             }
376         }
377
378         public static DateTime MinUtcDateTime
379         {
380             get
381             {
382                 // + and -  TimeSpan.TicksPerDay is to compensate the DateTime.ParseExact (to localtime) overflow.
383                 return new DateTime(DateTime.MinValue.Ticks + TimeSpan.TicksPerDay, DateTimeKind.Utc);
384             }
385         }
386
387         internal static IIdentity CreateIdentity(string name, string authenticationType)
388         {
389             return new GenericIdentity(name, authenticationType);
390         }
391
392         internal static IIdentity CreateIdentity(string name)
393         {
394             return new GenericIdentity(name);
395         }
396
397         internal static EndpointIdentity CreateWindowsIdentity()
398         {
399             return CreateWindowsIdentity(false);
400         }
401
402         internal static EndpointIdentity CreateWindowsIdentity(NetworkCredential serverCredential)
403         {
404             if (serverCredential != null && !NetworkCredentialHelper.IsDefault(serverCredential))
405             {
406                 string upn;
407                 if (serverCredential.Domain != null && serverCredential.Domain.Length > 0)
408                 {
409                     upn = serverCredential.UserName + "@" + serverCredential.Domain;
410                 }
411                 else
412                 {
413                     upn = serverCredential.UserName;
414                 }
415                 return EndpointIdentity.CreateUpnIdentity(upn);
416             }
417             else
418             {
419                 return SecurityUtils.CreateWindowsIdentity();
420             }
421         }
422
423         static bool IsSystemAccount(WindowsIdentity self)
424         {
425             SecurityIdentifier sid = self.User;
426             if (sid == null)
427             {
428                 return false;
429             }
430             // S-1-5-82 is the prefix for the sid that represents the identity that IIS 7.5 Apppool thread runs under.
431             return (sid.IsWellKnown(WellKnownSidType.LocalSystemSid)
432                     || sid.IsWellKnown(WellKnownSidType.NetworkServiceSid)
433                     || sid.IsWellKnown(WellKnownSidType.LocalServiceSid)
434                     || self.User.Value.StartsWith("S-1-5-82", StringComparison.OrdinalIgnoreCase));
435         }
436
437         internal static EndpointIdentity CreateWindowsIdentity(bool spnOnly)
438         {
439             EndpointIdentity identity = null;
440             using (WindowsIdentity self = WindowsIdentity.GetCurrent())
441             {
442                 bool isSystemAccount = IsSystemAccount(self);
443                 if (spnOnly || isSystemAccount)
444                 {
445                     identity = EndpointIdentity.CreateSpnIdentity(String.Format(CultureInfo.InvariantCulture, "host/{0}", DnsCache.MachineName));
446                 }
447                 else
448                 {
449                     // Save windowsIdentity for delay lookup
450                     identity = new UpnEndpointIdentity(CloneWindowsIdentityIfNecessary(self));
451                 }
452             }
453
454             return identity;
455         }
456
457         [Fx.Tag.SecurityNote(Critical = "Calls two critical methods: UnsafeGetWindowsIdentityToken and UnsafeCreateWindowsIdentityFromToken.",
458             Safe = "'Clone' operation is considered safe despite using WindowsIdentity IntPtr token. Must not let IntPtr token leak in or out.")]
459         [SecuritySafeCritical]
460         internal static WindowsIdentity CloneWindowsIdentityIfNecessary(WindowsIdentity wid)
461         {
462             return SecurityUtils.CloneWindowsIdentityIfNecessary(wid, null);
463         }
464
465         [Fx.Tag.SecurityNote(Critical = "Calls two critical methods: UnsafeGetWindowsIdentityToken and UnsafeCreateWindowsIdentityFromToken.",
466             Safe = "'Clone' operation is considered safe despite using WindowsIdentity IntPtr token. Must not let IntPtr token leak in or out.")]
467         [SecuritySafeCritical]
468         internal static WindowsIdentity CloneWindowsIdentityIfNecessary(WindowsIdentity wid, string authType)
469         {
470             if (wid != null)
471             {
472                 IntPtr token = UnsafeGetWindowsIdentityToken(wid);
473                 if (token != IntPtr.Zero)
474                 {
475                     return UnsafeCreateWindowsIdentityFromToken(token, authType);
476                 }
477             }
478             return wid;
479         }
480
481         [Fx.Tag.SecurityNote(Critical = "Elevates in order to return the WindowsIdentity.Token property, caller must protect return value.")]
482         [SecurityCritical]
483         [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
484         static IntPtr UnsafeGetWindowsIdentityToken(WindowsIdentity wid)
485         {
486             return wid.Token;
487         }
488
489         [Fx.Tag.SecurityNote(Critical = "Elevates in order to return the SecurityIdentifier of the current user as a string, caller must protect return value.")]
490         [SecurityCritical]
491         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
492         static string UnsafeGetCurrentUserSidAsString()
493         {
494             using (WindowsIdentity self = WindowsIdentity.GetCurrent())
495             {
496                 return self.User.Value;
497             }
498         }
499
500         [Fx.Tag.SecurityNote(Critical = "Elevates in order to return the WindowsIdentity.Token property, caller must protect return value.")]
501         [SecurityCritical]
502         [SecurityPermission(SecurityAction.Assert, ControlPrincipal = true, UnmanagedCode = true)]
503         static WindowsIdentity UnsafeCreateWindowsIdentityFromToken(IntPtr token, string authType)
504         {
505             if (authType != null)
506                 return new WindowsIdentity(token, authType);
507             else
508                 return new WindowsIdentity(token);
509         }
510
511         internal static bool AllowsImpersonation(WindowsIdentity windowsIdentity, TokenImpersonationLevel impersonationLevel)
512         {
513             if (windowsIdentity == null)
514                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("windowsIdentity");
515
516             TokenImpersonationLevelHelper.Validate(impersonationLevel);
517
518             if (impersonationLevel == TokenImpersonationLevel.Identification)
519                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("impersonationLevel"));
520
521             bool result = true;
522
523             switch (windowsIdentity.ImpersonationLevel)
524             {
525                 case TokenImpersonationLevel.None:
526                 case TokenImpersonationLevel.Anonymous:
527                 case TokenImpersonationLevel.Identification:
528                     result = false; break;
529                 case TokenImpersonationLevel.Impersonation:
530                     if (impersonationLevel == TokenImpersonationLevel.Delegation)
531                         result = false;
532                     break;
533                 case TokenImpersonationLevel.Delegation:
534                     break;
535                 default:
536                     result = false;
537                     break;
538             }
539
540             return result;
541         }
542
543         internal static byte[] CombinedHashLabel
544         {
545             get
546             {
547                 if (combinedHashLabel == null)
548                     combinedHashLabel = Encoding.UTF8.GetBytes(TrustApr2004Strings.CombinedHashLabel);
549                 return combinedHashLabel;
550             }
551         }
552
553         internal static T GetSecurityKey<T>(SecurityToken token)
554             where T : SecurityKey
555         {
556             T result = null;
557             if (token.SecurityKeys != null)
558             {
559                 for (int i = 0; i < token.SecurityKeys.Count; ++i)
560                 {
561                     T temp = (token.SecurityKeys[i] as T);
562                     if (temp != null)
563                     {
564                         if (result != null)
565                         {
566                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MultipleMatchingCryptosFound, typeof(T).ToString())));
567                         }
568                         else
569                         {
570                             result = temp;
571                         }
572                     }
573                 }
574             }
575             return result;
576         }
577
578         internal static bool HasSymmetricSecurityKey(SecurityToken token)
579         {
580             return GetSecurityKey<SymmetricSecurityKey>(token) != null;
581         }
582
583         internal static void EnsureExpectedSymmetricMatch(SecurityToken t1, SecurityToken t2, Message message)
584         {
585             // nulls are not mismatches
586             if (t1 == null || t2 == null || ReferenceEquals(t1, t2))
587             {
588                 return;
589             }
590             // check for interop flexibility
591             SymmetricSecurityKey c1 = SecurityUtils.GetSecurityKey<SymmetricSecurityKey>(t1);
592             SymmetricSecurityKey c2 = SecurityUtils.GetSecurityKey<SymmetricSecurityKey>(t2);
593             if (c1 == null || c2 == null || !CryptoHelper.IsEqual(c1.GetSymmetricKey(), c2.GetSymmetricKey()))
594             {
595                 throw System.ServiceModel.Diagnostics.TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.TokenNotExpectedInSecurityHeader, t2)), message);
596             }
597         }
598
599         internal static SymmetricAlgorithm GetSymmetricAlgorithm(string algorithm, SecurityToken token)
600         {
601             SymmetricSecurityKey securityKey = SecurityUtils.GetSecurityKey<SymmetricSecurityKey>(token);
602             if (securityKey != null && securityKey.IsSupportedAlgorithm(algorithm))
603             {
604                 return securityKey.GetSymmetricAlgorithm(algorithm);
605             }
606             else
607             {
608                 return null;
609             }
610         }
611
612         internal static KeyedHashAlgorithm GetKeyedHashAlgorithm(string algorithm, SecurityToken token)
613         {
614             SymmetricSecurityKey securityKey = SecurityUtils.GetSecurityKey<SymmetricSecurityKey>(token);
615             if (securityKey != null && securityKey.IsSupportedAlgorithm(algorithm))
616             {
617                 return securityKey.GetKeyedHashAlgorithm(algorithm);
618             }
619             else
620             {
621                 return null;
622             }
623         }
624
625         internal static ReadOnlyCollection<SecurityKey> CreateSymmetricSecurityKeys(byte[] key)
626         {
627             List<SecurityKey> temp = new List<SecurityKey>(1);
628             temp.Add(new InMemorySymmetricSecurityKey(key));
629             return temp.AsReadOnly();
630         }
631
632         internal static byte[] DecryptKey(SecurityToken unwrappingToken, string encryptionMethod, byte[] wrappedKey, out SecurityKey unwrappingSecurityKey)
633         {
634             unwrappingSecurityKey = null;
635             if (unwrappingToken.SecurityKeys != null)
636             {
637                 for (int i = 0; i < unwrappingToken.SecurityKeys.Count; ++i)
638                 {
639                     if (unwrappingToken.SecurityKeys[i].IsSupportedAlgorithm(encryptionMethod))
640                     {
641                         unwrappingSecurityKey = unwrappingToken.SecurityKeys[i];
642                         break;
643                     }
644                 }
645             }
646             if (unwrappingSecurityKey == null)
647             {
648                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CannotFindMatchingCrypto, encryptionMethod)));
649             }
650             return unwrappingSecurityKey.DecryptKey(encryptionMethod, wrappedKey);
651         }
652
653         internal static byte[] EncryptKey(SecurityToken wrappingToken, string encryptionMethod, byte[] keyToWrap)
654         {
655             SecurityKey wrappingSecurityKey = null;
656             if (wrappingToken.SecurityKeys != null)
657             {
658                 for (int i = 0; i < wrappingToken.SecurityKeys.Count; ++i)
659                 {
660                     if (wrappingToken.SecurityKeys[i].IsSupportedAlgorithm(encryptionMethod))
661                     {
662                         wrappingSecurityKey = wrappingToken.SecurityKeys[i];
663                         break;
664                     }
665                 }
666             }
667             if (wrappingSecurityKey == null)
668             {
669                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.CannotFindMatchingCrypto, encryptionMethod));
670             }
671             return wrappingSecurityKey.EncryptKey(encryptionMethod, keyToWrap);
672         }
673
674         internal static byte[] ReadContentAsBase64(XmlDictionaryReader reader, long maxBufferSize)
675         {
676             if (reader == null)
677                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
678
679             // Code cloned from System.Xml.XmlDictionaryReder.
680             byte[][] buffers = new byte[32][];
681             byte[] buffer;
682             // Its best to read in buffers that are a multiple of 3 so we don't break base64 boundaries when converting text
683             int count = 384;
684             int bufferCount = 0;
685             int totalRead = 0;
686             while (true)
687             {
688                 buffer = new byte[count];
689                 buffers[bufferCount++] = buffer;
690                 int read = 0;
691                 while (read < buffer.Length)
692                 {
693                     int actual = reader.ReadContentAsBase64(buffer, read, buffer.Length - read);
694                     if (actual == 0)
695                         break;
696                     read += actual;
697                 }
698                 if (totalRead > maxBufferSize - read)
699                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(SR.GetString(SR.BufferQuotaExceededReadingBase64, maxBufferSize)));
700                 totalRead += read;
701                 if (read < buffer.Length)
702                     break;
703                 count = count * 2;
704             }
705             buffer = new byte[totalRead];
706             int offset = 0;
707             for (int i = 0; i < bufferCount - 1; i++)
708             {
709                 Buffer.BlockCopy(buffers[i], 0, buffer, offset, buffers[i].Length);
710                 offset += buffers[i].Length;
711             }
712             Buffer.BlockCopy(buffers[bufferCount - 1], 0, buffer, offset, totalRead - offset);
713             return buffer;
714         }
715
716         internal static byte[] GenerateDerivedKey(SecurityToken tokenToDerive, string derivationAlgorithm, byte[] label, byte[] nonce,
717             int keySize, int offset)
718         {
719             SymmetricSecurityKey symmetricSecurityKey = SecurityUtils.GetSecurityKey<SymmetricSecurityKey>(tokenToDerive);
720             if (symmetricSecurityKey == null || !symmetricSecurityKey.IsSupportedAlgorithm(derivationAlgorithm))
721             {
722                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CannotFindMatchingCrypto, derivationAlgorithm)));
723             }
724             return symmetricSecurityKey.GenerateDerivedKey(derivationAlgorithm, label, nonce, keySize, offset);
725         }
726
727         internal static string GetSpnFromIdentity(EndpointIdentity identity, EndpointAddress target)
728         {
729             bool foundSpn = false;
730             string spn = null;
731             if (identity != null)
732             {
733                 if (ClaimTypes.Spn.Equals(identity.IdentityClaim.ClaimType))
734                 {
735                     spn = (string)identity.IdentityClaim.Resource;
736                     foundSpn = true;
737                 }
738                 else if (ClaimTypes.Upn.Equals(identity.IdentityClaim.ClaimType))
739                 {
740                     spn = (string)identity.IdentityClaim.Resource;
741                     foundSpn = true;
742                 }
743                 else if (ClaimTypes.Dns.Equals(identity.IdentityClaim.ClaimType))
744                 {
745                     spn = String.Format(CultureInfo.InvariantCulture, "host/{0}", (string)identity.IdentityClaim.Resource);
746                     foundSpn = true;
747                 }
748             }
749             if (!foundSpn)
750             {
751                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.CannotDetermineSPNBasedOnAddress, target)));
752             }
753             return spn;
754         }
755
756         internal static string GetSpnFromTarget(EndpointAddress target)
757         {
758             if (target == null)
759             {
760                 throw Fx.AssertAndThrow("target should not be null - expecting an EndpointAddress");
761             }
762
763             return string.Format(CultureInfo.InvariantCulture, "host/{0}", target.Uri.DnsSafeHost);
764         }
765
766         internal static bool IsSupportedAlgorithm(string algorithm, SecurityToken token)
767         {
768             if (token.SecurityKeys == null)
769             {
770                 return false;
771             }
772             for (int i = 0; i < token.SecurityKeys.Count; ++i)
773             {
774                 if (token.SecurityKeys[i].IsSupportedAlgorithm(algorithm))
775                 {
776                     return true;
777                 }
778             }
779             return false;
780         }
781
782         internal static Claim GetPrimaryIdentityClaim(ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies)
783         {
784             return GetPrimaryIdentityClaim(AuthorizationContext.CreateDefaultAuthorizationContext(authorizationPolicies));
785         }
786
787         internal static Claim GetPrimaryIdentityClaim(AuthorizationContext authContext)
788         {
789             if (authContext != null)
790             {
791                 for (int i = 0; i < authContext.ClaimSets.Count; ++i)
792                 {
793                     ClaimSet claimSet = authContext.ClaimSets[i];
794                     foreach (Claim claim in claimSet.FindClaims(null, Rights.Identity))
795                     {
796                         return claim;
797                     }
798                 }
799             }
800             return null;
801         }
802
803         internal static int GetServiceAddressAndViaHash(EndpointAddress sr)
804         {
805             if (sr == null)
806             {
807                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("sr");
808             }
809             return sr.GetHashCode();
810         }
811
812         internal static string GenerateId()
813         {
814             return SecurityUniqueId.Create().Value;
815         }
816
817         internal static string GenerateIdWithPrefix(string prefix)
818         {
819             return SecurityUniqueId.Create(prefix).Value;
820         }
821
822         internal static UniqueId GenerateUniqueId()
823         {
824             return new UniqueId();
825         }
826
827         internal static string GetPrimaryDomain()
828         {
829             using (WindowsIdentity wid = WindowsIdentity.GetCurrent())
830             {
831                 return GetPrimaryDomain(IsSystemAccount(wid));
832             }
833         }
834
835         internal static string GetPrimaryDomain(bool isSystemAccount)
836         {
837             if (computedDomain == false)
838             {
839                 try
840                 {
841                     if (isSystemAccount)
842                     {
843                         currentDomain = Domain.GetComputerDomain().Name;
844                     }
845                     else
846                     {
847                         currentDomain = Domain.GetCurrentDomain().Name;
848                     }
849                 }
850 #pragma warning suppress 56500 // covered by FxCOP
851                 catch (Exception e)
852                 {
853                     if (Fx.IsFatal(e))
854                     {
855                         throw;
856                     }
857                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
858                 }
859                 finally
860                 {
861                     computedDomain = true;
862                 }
863             }
864             return currentDomain;
865         }
866
867         internal static void EnsureCertificateCanDoKeyExchange(X509Certificate2 certificate)
868         {
869             if (certificate == null)
870             {
871                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("certificate");
872             }
873             bool canDoKeyExchange = false;
874             Exception innerException = null;
875             if (certificate.HasPrivateKey)
876             {
877                 try
878                 {
879                     canDoKeyExchange = CanKeyDoKeyExchange(certificate);
880                 }
881                 // exceptions can be due to ACLs on the key etc
882                 catch (System.Security.SecurityException e)
883                 {
884                     innerException = e;
885                 }
886                 catch (CryptographicException e)
887                 {
888                     innerException = e;
889                 }
890             }
891             if (!canDoKeyExchange)
892             {
893                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SslCertMayNotDoKeyExchange, certificate.SubjectName.Name), innerException));
894             }
895         }
896
897         [Fx.Tag.SecurityNote(Critical = "Calls critical method GetKeyContainerInfo.",
898             Safe = "Info is not leaked.")]
899         [SecuritySafeCritical]
900         static bool CanKeyDoKeyExchange(X509Certificate2 certificate)
901         {
902             bool canDoKeyExchange = false;
903
904             if (!LocalAppContextSwitches.DisableCngCertificates)
905             {
906                 X509KeyUsageExtension keyUsageExtension = null;
907                 for (int i = 0; i < certificate.Extensions.Count; i++)
908                 {
909                     keyUsageExtension = certificate.Extensions[i] as X509KeyUsageExtension;
910                     if (keyUsageExtension != null)
911                     {
912                         break;
913                     }
914                 }
915
916                 // No KeyUsage extension means most usages are permitted including key exchange.
917                 // See RFC 5280 section 4.2.1.3 (Key Usage) for details. If the extension is non-critical
918                 // then it's non-enforcing and meant as an aid in choosing the best certificate when
919                 // there are multiple certificates to choose from. 
920                 if (keyUsageExtension == null || !keyUsageExtension.Critical)
921                 {
922                     return true;
923                 }
924
925                 // One of KeyAgreement, KeyEncipherment or DigitalSignature need to be allowed depending on the cipher
926                 // being used. See RFC 5246 section 7.4.6 for more details.
927                 // Additionally, according to msdn docs for PFXImportCertStore, the key specification is set to AT_KEYEXCHANGE
928                 // when the data encipherment usage is set.
929                 canDoKeyExchange = (keyUsageExtension.KeyUsages &
930                     (X509KeyUsageFlags.KeyAgreement | X509KeyUsageFlags.KeyEncipherment |
931                      X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment)) != X509KeyUsageFlags.None;
932             }
933
934             if (!canDoKeyExchange)
935             {
936                 CspKeyContainerInfo info = GetKeyContainerInfo(certificate);
937                 canDoKeyExchange = info != null && info.KeyNumber == KeyNumber.Exchange;
938             }
939
940             return canDoKeyExchange;
941         }
942
943         [Fx.Tag.SecurityNote(Critical = "Elevates to call properties: X509Certificate2.PrivateKey and CspKeyContainerInfo. Caller must protect the return value.")]
944         [SecurityCritical]
945         [KeyContainerPermission(SecurityAction.Assert, Flags = KeyContainerPermissionFlags.Open)]
946         static CspKeyContainerInfo GetKeyContainerInfo(X509Certificate2 certificate)
947         {
948             RSACryptoServiceProvider rsa = certificate.PrivateKey as RSACryptoServiceProvider;
949             if (rsa != null)
950             {
951                 return rsa.CspKeyContainerInfo;
952             }
953
954             return null;
955         }
956
957         internal static string GetCertificateId(X509Certificate2 certificate)
958         {
959             StringBuilder str = new StringBuilder(256);
960             AppendCertificateIdentityName(str, certificate);
961             return str.ToString();
962         }
963
964         internal static ReadOnlyCollection<IAuthorizationPolicy> CreatePrincipalNameAuthorizationPolicies(string principalName)
965         {
966             if (principalName == null)
967                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("principalName");
968
969             Claim identityClaim;
970             Claim primaryPrincipal;
971             if (principalName.Contains("@") || principalName.Contains(@"\"))
972             {
973                 identityClaim = new Claim(ClaimTypes.Upn, principalName, Rights.Identity);
974                 primaryPrincipal = Claim.CreateUpnClaim(principalName);
975             }
976             else
977             {
978                 identityClaim = new Claim(ClaimTypes.Spn, principalName, Rights.Identity);
979                 primaryPrincipal = Claim.CreateSpnClaim(principalName);
980             }
981
982             List<Claim> claims = new List<Claim>(2);
983             claims.Add(identityClaim);
984             claims.Add(primaryPrincipal);
985
986             List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
987             policies.Add(new UnconditionalPolicy(SecurityUtils.CreateIdentity(principalName), new DefaultClaimSet(ClaimSet.Anonymous, claims)));
988             return policies.AsReadOnly();
989         }
990
991         internal static string GetIdentityNamesFromPolicies(IList<IAuthorizationPolicy> authPolicies)
992         {
993             return GetIdentityNamesFromContext(AuthorizationContext.CreateDefaultAuthorizationContext(authPolicies));
994         }
995
996         internal static string GetIdentityNamesFromContext(AuthorizationContext authContext)
997         {
998             if (authContext == null)
999                 return String.Empty;
1000
1001             StringBuilder str = new StringBuilder(256);
1002             for (int i = 0; i < authContext.ClaimSets.Count; ++i)
1003             {
1004                 ClaimSet claimSet = authContext.ClaimSets[i];
1005
1006                 // Windows
1007                 WindowsClaimSet windows = claimSet as WindowsClaimSet;
1008                 if (windows != null)
1009                 {
1010                     if (str.Length > 0)
1011                         str.Append(", ");
1012
1013                     AppendIdentityName(str, windows.WindowsIdentity);
1014                 }
1015                 else
1016                 {
1017                     // X509
1018                     X509CertificateClaimSet x509 = claimSet as X509CertificateClaimSet;
1019                     if (x509 != null)
1020                     {
1021                         if (str.Length > 0)
1022                             str.Append(", ");
1023
1024                         AppendCertificateIdentityName(str, x509.X509Certificate);
1025                     }
1026                 }
1027             }
1028
1029             if (str.Length <= 0)
1030             {
1031                 List<IIdentity> identities = null;
1032                 object obj;
1033                 if (authContext.Properties.TryGetValue(SecurityUtils.Identities, out obj))
1034                 {
1035                     identities = obj as List<IIdentity>;
1036                 }
1037                 if (identities != null)
1038                 {
1039                     for (int i = 0; i < identities.Count; ++i)
1040                     {
1041                         IIdentity identity = identities[i];
1042                         if (identity != null)
1043                         {
1044                             if (str.Length > 0)
1045                                 str.Append(", ");
1046
1047                             AppendIdentityName(str, identity);
1048                         }
1049                     }
1050                 }
1051             }
1052             return str.Length <= 0 ? String.Empty : str.ToString();
1053         }
1054
1055         internal static void AppendCertificateIdentityName(StringBuilder str, X509Certificate2 certificate)
1056         {
1057             string value = certificate.SubjectName.Name;
1058             if (String.IsNullOrEmpty(value))
1059             {
1060                 value = certificate.GetNameInfo(X509NameType.DnsName, false);
1061                 if (String.IsNullOrEmpty(value))
1062                 {
1063                     value = certificate.GetNameInfo(X509NameType.SimpleName, false);
1064                     if (String.IsNullOrEmpty(value))
1065                     {
1066                         value = certificate.GetNameInfo(X509NameType.EmailName, false);
1067                         if (String.IsNullOrEmpty(value))
1068                         {
1069                             value = certificate.GetNameInfo(X509NameType.UpnName, false);
1070                         }
1071                     }
1072                 }
1073             }
1074             // Same format as X509Identity
1075             str.Append(String.IsNullOrEmpty(value) ? "<x509>" : value);
1076             str.Append("; ");
1077             str.Append(certificate.Thumbprint);
1078         }
1079
1080         internal static void AppendIdentityName(StringBuilder str, IIdentity identity)
1081         {
1082             string name = null;
1083             try
1084             {
1085                 name = identity.Name;
1086             }
1087 #pragma warning suppress 56500
1088             catch (Exception e)
1089             {
1090                 if (Fx.IsFatal(e))
1091                 {
1092                     throw;
1093                 }
1094                 // suppress exception, this is just info.
1095             }
1096
1097             str.Append(String.IsNullOrEmpty(name) ? "<null>" : name);
1098
1099             WindowsIdentity windows = identity as WindowsIdentity;
1100             if (windows != null)
1101             {
1102                 if (windows.User != null)
1103                 {
1104                     str.Append("; ");
1105                     str.Append(windows.User.ToString());
1106                 }
1107             }
1108             else
1109             {
1110                 WindowsSidIdentity sid = identity as WindowsSidIdentity;
1111                 if (sid != null)
1112                 {
1113                     str.Append("; ");
1114                     str.Append(sid.SecurityIdentifier.ToString());
1115                 }
1116             }
1117         }
1118
1119         [Fx.Tag.SecurityNote(Critical = "Calls critical methods UnsafeGetDomain, UnsafeGetUserName, UnsafeGetPassword and UnsafeGetCurrentUserSidAsString.")]
1120         [SecurityCritical]
1121         internal static string AppendWindowsAuthenticationInfo(string inputString, NetworkCredential credential,
1122             AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel)
1123         {
1124             const string delimiter = "\0"; // nonprintable characters are invalid for SSPI Domain/UserName/Password
1125
1126             if (IsDefaultNetworkCredential(credential))
1127             {
1128                 string sid = UnsafeGetCurrentUserSidAsString();
1129                 return string.Concat(inputString, delimiter,
1130                     sid, delimiter,
1131                     AuthenticationLevelHelper.ToString(authenticationLevel), delimiter,
1132                     TokenImpersonationLevelHelper.ToString(impersonationLevel));
1133             }
1134             else
1135             {
1136                 return string.Concat(inputString, delimiter,
1137                     NetworkCredentialHelper.UnsafeGetDomain(credential), delimiter,
1138                     NetworkCredentialHelper.UnsafeGetUsername(credential), delimiter,
1139                     NetworkCredentialHelper.UnsafeGetPassword(credential), delimiter,
1140                     AuthenticationLevelHelper.ToString(authenticationLevel), delimiter,
1141                     TokenImpersonationLevelHelper.ToString(impersonationLevel));
1142             }
1143         }
1144
1145         internal static string GetIdentityName(IIdentity identity)
1146         {
1147             StringBuilder str = new StringBuilder(256);
1148             AppendIdentityName(str, identity);
1149             return str.ToString();
1150         }
1151
1152         /// <SecurityNote>
1153         /// Critical - Calls an UnsafeNativeMethod and a Critical method (GetFipsAlgorithmPolicyKeyFromRegistry)
1154         /// Safe - processes the return and just returns a bool, which is safe
1155         /// </SecurityNote>
1156         internal static bool IsChannelBindingDisabled
1157         {
1158             [SecuritySafeCritical]
1159             get
1160             {
1161                 return ((GetSuppressChannelBindingValue() & 0x1) != 0);
1162             }
1163         }
1164
1165         const string suppressChannelBindingRegistryKey = @"System\CurrentControlSet\Control\Lsa";
1166
1167         /// <SecurityNote>
1168         /// Critical - Asserts to get a value from the registry
1169         /// </SecurityNote>
1170         [SecurityCritical]
1171         [RegistryPermission(SecurityAction.Assert, Read = @"HKEY_LOCAL_MACHINE\" + suppressChannelBindingRegistryKey)]
1172         internal static int GetSuppressChannelBindingValue()
1173         {
1174             int channelBindingPolicyKeyValue = 0;
1175
1176             try
1177             {
1178                 using (RegistryKey channelBindingPolicyKey = Registry.LocalMachine.OpenSubKey(suppressChannelBindingRegistryKey, false))
1179                 {
1180                     if (channelBindingPolicyKey != null)
1181                     {
1182                         object data = channelBindingPolicyKey.GetValue("SuppressChannelBindingInfo");
1183                         if (data != null)
1184                             channelBindingPolicyKeyValue = (int)data;
1185                     }
1186                 }
1187             }
1188 #pragma warning suppress 56500
1189             catch (Exception e)
1190             {
1191                 if (Fx.IsFatal(e))
1192                     throw;
1193             }
1194
1195             return channelBindingPolicyKeyValue;
1196         }
1197
1198         internal static bool IsSecurityBindingSuitableForChannelBinding(TransportSecurityBindingElement securityBindingElement)
1199         {
1200             if (securityBindingElement == null)
1201             {
1202                 return false;
1203             }
1204
1205             // channel binding of OperationSupportingTokenParameters, OptionalEndpointSupportingTokenParameters, or OptionalOperationSupportingTokenParameters
1206             // is not supported in Win7
1207             if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.Endorsing))
1208             {
1209                 return true;
1210             }
1211
1212             if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.Signed))
1213             {
1214                 return true;
1215             }
1216
1217             if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted))
1218             {
1219                 return true;
1220             }
1221
1222             if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.SignedEndorsing))
1223             {
1224                 return true;
1225             }
1226
1227             return false;
1228         }
1229
1230         internal static bool AreSecurityTokenParametersSuitableForChannelBinding(Collection<SecurityTokenParameters> tokenParameters)
1231         {
1232             if (tokenParameters == null)
1233             {
1234                 return false;
1235             }
1236
1237             foreach (SecurityTokenParameters stp in tokenParameters)
1238             {
1239                 if (stp is SspiSecurityTokenParameters || stp is KerberosSecurityTokenParameters)
1240                 {
1241                     return true;
1242                 }
1243
1244                 SecureConversationSecurityTokenParameters scstp = stp as SecureConversationSecurityTokenParameters;
1245                 if (scstp != null)
1246                 {
1247                     return IsSecurityBindingSuitableForChannelBinding(scstp.BootstrapSecurityBindingElement as TransportSecurityBindingElement);
1248                 }
1249             }
1250
1251             return false;
1252         }
1253
1254         internal static void ThrowIfNegotiationFault(Message message, EndpointAddress target)
1255         {
1256             if (message.IsFault)
1257             {
1258                 MessageFault fault = MessageFault.CreateFault(message, TransportDefaults.MaxSecurityFaultSize);
1259                 Exception faultException = new FaultException(fault, message.Headers.Action);
1260                 if (fault.Code != null && fault.Code.IsReceiverFault && fault.Code.SubCode != null)
1261                 {
1262                     FaultCode subCode = fault.Code.SubCode;
1263                     if (subCode.Name == DotNetSecurityStrings.SecurityServerTooBusyFault && subCode.Namespace == DotNetSecurityStrings.Namespace)
1264                     {
1265                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServerTooBusyException(SR.GetString(SR.SecurityServerTooBusy, target), faultException));
1266                     }
1267                     else if (subCode.Name == AddressingStrings.EndpointUnavailable && subCode.Namespace == message.Version.Addressing.Namespace)
1268                     {
1269                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.SecurityEndpointNotFound, target), faultException));
1270                     }
1271                 }
1272                 throw TraceUtility.ThrowHelperError(faultException, message);
1273             }
1274         }
1275
1276         internal static bool IsSecurityFault(MessageFault fault, SecurityStandardsManager standardsManager)
1277         {
1278             if (fault.Code.IsSenderFault)
1279             {
1280                 FaultCode subCode = fault.Code.SubCode;
1281                 if (subCode != null)
1282                 {
1283                     return (subCode.Namespace == standardsManager.SecurityVersion.HeaderNamespace.Value
1284                         || subCode.Namespace == standardsManager.SecureConversationDriver.Namespace.Value
1285                         || subCode.Namespace == standardsManager.TrustDriver.Namespace.Value
1286                         || subCode.Namespace == DotNetSecurityStrings.Namespace);
1287                 }
1288             }
1289             return false;
1290         }
1291
1292         internal static Exception CreateSecurityFaultException(Message unverifiedMessage)
1293         {
1294             MessageFault fault = MessageFault.CreateFault(unverifiedMessage, TransportDefaults.MaxSecurityFaultSize);
1295             return CreateSecurityFaultException(fault);
1296         }
1297
1298         internal static Exception CreateSecurityFaultException(MessageFault fault)
1299         {
1300             FaultException faultException = FaultException.CreateFault(fault, typeof(string), typeof(object));
1301             return new MessageSecurityException(SR.GetString(SR.UnsecuredMessageFaultReceived), faultException);
1302         }
1303
1304         internal static MessageFault CreateSecurityContextNotFoundFault(SecurityStandardsManager standardsManager, string action)
1305         {
1306             SecureConversationDriver scDriver = standardsManager.SecureConversationDriver;
1307             FaultCode subCode = new FaultCode(scDriver.BadContextTokenFaultCode.Value, scDriver.Namespace.Value);
1308             FaultReason reason;
1309             if (action != null)
1310             {
1311                 reason = new FaultReason(SR.GetString(SR.BadContextTokenOrActionFaultReason, action), CultureInfo.CurrentCulture);
1312             }
1313             else
1314             {
1315                 reason = new FaultReason(SR.GetString(SR.BadContextTokenFaultReason), CultureInfo.CurrentCulture);
1316             }
1317             FaultCode senderCode = FaultCode.CreateSenderFaultCode(subCode);
1318             return MessageFault.CreateFault(senderCode, reason);
1319         }
1320
1321         internal static MessageFault CreateSecurityMessageFault(Exception e, SecurityStandardsManager standardsManager)
1322         {
1323             bool isSecurityError = false;
1324             bool isTokenValidationError = false;
1325             bool isGenericTokenError = false;
1326             FaultException faultException = null;
1327             while (e != null)
1328             {
1329                 if (e is SecurityTokenValidationException)
1330                 {
1331                     if (e is SecurityContextTokenValidationException)
1332                     {
1333                         return CreateSecurityContextNotFoundFault(SecurityStandardsManager.DefaultInstance, null);
1334                     }
1335                     isSecurityError = true;
1336                     isTokenValidationError = true;
1337                     break;
1338                 }
1339                 else if (e is SecurityTokenException)
1340                 {
1341                     isSecurityError = true;
1342                     isGenericTokenError = true;
1343                     break;
1344                 }
1345                 else if (e is MessageSecurityException)
1346                 {
1347                     MessageSecurityException ms = (MessageSecurityException)e;
1348                     if (ms.Fault != null)
1349                     {
1350                         return ms.Fault;
1351                     }
1352                     isSecurityError = true;
1353                 }
1354                 else if (e is FaultException)
1355                 {
1356                     faultException = (FaultException)e;
1357                     break;
1358                 }
1359                 e = e.InnerException;
1360             }
1361             if (!isSecurityError && faultException == null)
1362             {
1363                 return null;
1364             }
1365             FaultCode subCode;
1366             FaultReason reason;
1367             SecurityVersion wss = standardsManager.SecurityVersion;
1368             if (isTokenValidationError)
1369             {
1370                 subCode = new FaultCode(wss.FailedAuthenticationFaultCode.Value, wss.HeaderNamespace.Value);
1371                 reason = new FaultReason(SR.GetString(SR.FailedAuthenticationFaultReason), CultureInfo.CurrentCulture);
1372             }
1373             else if (isGenericTokenError)
1374             {
1375                 subCode = new FaultCode(wss.InvalidSecurityTokenFaultCode.Value, wss.HeaderNamespace.Value);
1376                 reason = new FaultReason(SR.GetString(SR.InvalidSecurityTokenFaultReason), CultureInfo.CurrentCulture);
1377             }
1378             else if (faultException != null)
1379             {
1380                 // Only support Code and Reason.  No detail or action customization.
1381                 return MessageFault.CreateFault(faultException.Code, faultException.Reason);
1382             }
1383             else
1384             {
1385                 subCode = new FaultCode(wss.InvalidSecurityFaultCode.Value, wss.HeaderNamespace.Value);
1386                 reason = new FaultReason(SR.GetString(SR.InvalidSecurityFaultReason), CultureInfo.CurrentCulture);
1387             }
1388             FaultCode senderCode = FaultCode.CreateSenderFaultCode(subCode);
1389             return MessageFault.CreateFault(senderCode, reason);
1390         }
1391
1392         internal static bool IsCompositeDuplexBinding(BindingContext context)
1393         {
1394             return ((context.Binding.Elements.Find<CompositeDuplexBindingElement>() != null)
1395                     || (context.Binding.Elements.Find<InternalDuplexBindingElement>() != null));
1396         }
1397
1398         // The method checks TransportToken, ProtectionToken and all SupportingTokens to find a
1399         // UserNameSecurityToken. If found, it sets the password of the UserNameSecurityToken to null. 
1400         // Custom UserNameSecurityToken are skipped. 
1401         internal static void ErasePasswordInUsernameTokenIfPresent(SecurityMessageProperty messageProperty)
1402         {
1403             if (messageProperty == null)
1404             {
1405                 // Nothing to fix.
1406                 return;
1407             }
1408
1409             if (messageProperty.TransportToken != null)
1410             {
1411                 UserNameSecurityToken token = messageProperty.TransportToken.SecurityToken as UserNameSecurityToken;
1412                 if ((token != null) && !messageProperty.TransportToken.SecurityToken.GetType().IsSubclassOf(typeof(UserNameSecurityToken)))
1413                 {
1414                     messageProperty.TransportToken = new SecurityTokenSpecification(new UserNameSecurityToken(token.UserName, null, token.Id), messageProperty.TransportToken.SecurityTokenPolicies);
1415                 }
1416             }
1417
1418             if (messageProperty.ProtectionToken != null)
1419             {
1420                 UserNameSecurityToken token = messageProperty.ProtectionToken.SecurityToken as UserNameSecurityToken;
1421                 if ((token != null) && !messageProperty.ProtectionToken.SecurityToken.GetType().IsSubclassOf(typeof(UserNameSecurityToken)))
1422                 {
1423                     messageProperty.ProtectionToken = new SecurityTokenSpecification(new UserNameSecurityToken(token.UserName, null, token.Id), messageProperty.ProtectionToken.SecurityTokenPolicies);
1424                 }
1425             }
1426
1427             if (messageProperty.HasIncomingSupportingTokens)
1428             {
1429                 for (int i = 0; i < messageProperty.IncomingSupportingTokens.Count; ++i)
1430                 {
1431                     SupportingTokenSpecification supportingTokenSpecification = messageProperty.IncomingSupportingTokens[i];
1432                     UserNameSecurityToken token = supportingTokenSpecification.SecurityToken as UserNameSecurityToken;
1433                     if ((token != null) && !supportingTokenSpecification.SecurityToken.GetType().IsSubclassOf(typeof(UserNameSecurityToken)))
1434                     {
1435                         messageProperty.IncomingSupportingTokens[i] = new SupportingTokenSpecification(new UserNameSecurityToken(token.UserName, null, token.Id), supportingTokenSpecification.SecurityTokenPolicies, supportingTokenSpecification.SecurityTokenAttachmentMode, supportingTokenSpecification.SecurityTokenParameters);
1436                     }
1437                 }
1438             }
1439         }
1440
1441         // work-around to Windows SE Bug 141614
1442         [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method UnsafeGetPassword to access the credential password without a Demand.",
1443             Safe = "Only uses the password to construct a cloned NetworkCredential instance, does not leak password value.")]
1444         [SecuritySafeCritical]
1445         internal static void FixNetworkCredential(ref NetworkCredential credential)
1446         {
1447             if (credential == null)
1448             {
1449                 return;
1450             }
1451             string username = NetworkCredentialHelper.UnsafeGetUsername(credential);
1452             string domain = NetworkCredentialHelper.UnsafeGetDomain(credential);
1453             if (!string.IsNullOrEmpty(username) && string.IsNullOrEmpty(domain))
1454             {
1455                 // do the splitting only if there is exactly 1 \ or exactly 1 @
1456                 string[] partsWithSlashDelimiter = username.Split('\\');
1457                 string[] partsWithAtDelimiter = username.Split('@');
1458                 if (partsWithSlashDelimiter.Length == 2 && partsWithAtDelimiter.Length == 1)
1459                 {
1460                     if (!string.IsNullOrEmpty(partsWithSlashDelimiter[0]) && !string.IsNullOrEmpty(partsWithSlashDelimiter[1]))
1461                     {
1462                         credential = new NetworkCredential(partsWithSlashDelimiter[1], NetworkCredentialHelper.UnsafeGetPassword(credential), partsWithSlashDelimiter[0]);
1463                     }
1464                 }
1465                 else if (partsWithSlashDelimiter.Length == 1 && partsWithAtDelimiter.Length == 2)
1466                 {
1467                     if (!string.IsNullOrEmpty(partsWithAtDelimiter[0]) && !string.IsNullOrEmpty(partsWithAtDelimiter[1]))
1468                     {
1469                         credential = new NetworkCredential(partsWithAtDelimiter[0], NetworkCredentialHelper.UnsafeGetPassword(credential), partsWithAtDelimiter[1]);
1470                     }
1471                 }
1472             }
1473         }
1474
1475         // WORKAROUND, Microsoft, VSWhidbey 561276: The first NetworkCredential must be created in a lock.
1476         internal static void PrepareNetworkCredential()
1477         {
1478             if (dummyNetworkCredential == null)
1479             {
1480                 PrepareNetworkCredentialWorker();
1481             }
1482         }
1483
1484         // Since this takes a lock, it probably won't be inlined, but the typical case will be.
1485         static void PrepareNetworkCredentialWorker()
1486         {
1487             lock (dummyNetworkCredentialLock)
1488             {
1489                 dummyNetworkCredential = new NetworkCredential("dummy", "dummy");
1490             }
1491         }
1492
1493         // This is the workaround, Since store.Certificates returns a full collection
1494         // of certs in store.  These are holding native resources.
1495         internal static void ResetAllCertificates(X509Certificate2Collection certificates)
1496         {
1497             if (certificates != null)
1498             {
1499                 for (int i = 0; i < certificates.Count; ++i)
1500                 {
1501                     ResetCertificate(certificates[i]);
1502                 }
1503             }
1504         }
1505
1506         [Fx.Tag.SecurityNote(Critical = "Calls critical method X509Certificate2.Reset.",
1507             Safe = "Per review from CLR security team, this method does nothing unsafe.")]
1508         [SecuritySafeCritical]
1509         internal static void ResetCertificate(X509Certificate2 certificate)
1510         {
1511             certificate.Reset();
1512         }
1513
1514         internal static bool IsDefaultNetworkCredential(NetworkCredential credential)
1515         {
1516             return NetworkCredentialHelper.IsDefault(credential);
1517         }
1518
1519         internal static void OpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout)
1520         {
1521             OpenCommunicationObject(tokenProvider as ICommunicationObject, timeout);
1522         }
1523
1524         internal static IAsyncResult BeginOpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout,
1525             AsyncCallback callback, object state)
1526         {
1527             return new OpenCommunicationObjectAsyncResult(tokenProvider, timeout, callback, state);
1528         }
1529
1530         internal static void EndOpenTokenProviderIfRequired(IAsyncResult result)
1531         {
1532             OpenCommunicationObjectAsyncResult.End(result);
1533         }
1534
1535         internal static IAsyncResult BeginCloseTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout,
1536             AsyncCallback callback, object state)
1537         {
1538             return new CloseCommunicationObjectAsyncResult(tokenProvider, timeout, callback, state);
1539         }
1540
1541         internal static void EndCloseTokenProviderIfRequired(IAsyncResult result)
1542         {
1543             CloseCommunicationObjectAsyncResult.End(result);
1544         }
1545
1546         internal static void CloseTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout)
1547         {
1548             CloseCommunicationObject(tokenProvider, false, timeout);
1549         }
1550
1551         internal static void CloseTokenProviderIfRequired(SecurityTokenProvider tokenProvider, bool aborted, TimeSpan timeout)
1552         {
1553             CloseCommunicationObject(tokenProvider, aborted, timeout);
1554         }
1555
1556         internal static void AbortTokenProviderIfRequired(SecurityTokenProvider tokenProvider)
1557         {
1558             CloseCommunicationObject(tokenProvider, true, TimeSpan.Zero);
1559         }
1560
1561         internal static void OpenTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout)
1562         {
1563             OpenCommunicationObject(tokenAuthenticator as ICommunicationObject, timeout);
1564         }
1565
1566         internal static void CloseTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout)
1567         {
1568             CloseTokenAuthenticatorIfRequired(tokenAuthenticator, false, timeout);
1569         }
1570
1571         internal static void CloseTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, bool aborted, TimeSpan timeout)
1572         {
1573             CloseCommunicationObject(tokenAuthenticator, aborted, timeout);
1574         }
1575
1576         internal static IAsyncResult BeginOpenTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout,
1577             AsyncCallback callback, object state)
1578         {
1579             return new OpenCommunicationObjectAsyncResult(tokenAuthenticator, timeout, callback, state);
1580         }
1581
1582         internal static void EndOpenTokenAuthenticatorIfRequired(IAsyncResult result)
1583         {
1584             OpenCommunicationObjectAsyncResult.End(result);
1585         }
1586
1587         internal static IAsyncResult BeginCloseTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout,
1588             AsyncCallback callback, object state)
1589         {
1590             return new CloseCommunicationObjectAsyncResult(tokenAuthenticator, timeout, callback, state);
1591         }
1592
1593         internal static void EndCloseTokenAuthenticatorIfRequired(IAsyncResult result)
1594         {
1595             CloseCommunicationObjectAsyncResult.End(result);
1596         }
1597
1598         internal static void AbortTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator)
1599         {
1600             CloseCommunicationObject(tokenAuthenticator, true, TimeSpan.Zero);
1601         }
1602
1603         static void OpenCommunicationObject(ICommunicationObject obj, TimeSpan timeout)
1604         {
1605             if (obj != null)
1606                 obj.Open(timeout);
1607         }
1608
1609         static void CloseCommunicationObject(Object obj, bool aborted, TimeSpan timeout)
1610         {
1611             if (obj != null)
1612             {
1613                 ICommunicationObject co = obj as ICommunicationObject;
1614                 if (co != null)
1615                 {
1616                     if (aborted)
1617                     {
1618                         try
1619                         {
1620                             co.Abort();
1621                         }
1622                         catch (CommunicationException e)
1623                         {
1624                             DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
1625                         }
1626                     }
1627                     else
1628                     {
1629                         co.Close(timeout);
1630                     }
1631                 }
1632                 else if (obj is IDisposable)
1633                 {
1634                     ((IDisposable)obj).Dispose();
1635                 }
1636             }
1637         }
1638
1639         class OpenCommunicationObjectAsyncResult : AsyncResult
1640         {
1641             ICommunicationObject communicationObject;
1642             static AsyncCallback onOpen;
1643
1644             public OpenCommunicationObjectAsyncResult(object obj, TimeSpan timeout, AsyncCallback callback, object state)
1645                 : base(callback, state)
1646             {
1647                 this.communicationObject = obj as ICommunicationObject;
1648
1649                 bool completeSelf = false;
1650                 if (this.communicationObject == null)
1651                 {
1652                     completeSelf = true;
1653                 }
1654                 else
1655                 {
1656                     if (onOpen == null)
1657                     {
1658                         onOpen = Fx.ThunkCallback(new AsyncCallback(OnOpen));
1659                     }
1660
1661                     IAsyncResult result = this.communicationObject.BeginOpen(timeout, onOpen, this);
1662                     if (result.CompletedSynchronously)
1663                     {
1664                         this.communicationObject.EndOpen(result);
1665                         completeSelf = true;
1666                     }
1667                 }
1668
1669                 if (completeSelf)
1670                 {
1671                     base.Complete(true);
1672                 }
1673             }
1674
1675             public static void End(IAsyncResult result)
1676             {
1677                 AsyncResult.End<OpenCommunicationObjectAsyncResult>(result);
1678             }
1679
1680             static void OnOpen(IAsyncResult result)
1681             {
1682                 if (result.CompletedSynchronously)
1683                 {
1684                     return;
1685                 }
1686
1687                 OpenCommunicationObjectAsyncResult thisPtr =
1688                     (OpenCommunicationObjectAsyncResult)result.AsyncState;
1689
1690                 Exception completionException = null;
1691                 try
1692                 {
1693                     thisPtr.communicationObject.EndOpen(result);
1694                 }
1695 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1696                 catch (Exception e)
1697                 {
1698                     if (Fx.IsFatal(e))
1699                     {
1700                         throw;
1701                     }
1702
1703                     completionException = e;
1704                 }
1705                 thisPtr.Complete(false, completionException);
1706             }
1707         }
1708
1709         class CloseCommunicationObjectAsyncResult : AsyncResult
1710         {
1711             ICommunicationObject communicationObject;
1712             static AsyncCallback onClose;
1713
1714             public CloseCommunicationObjectAsyncResult(object obj, TimeSpan timeout, AsyncCallback callback, object state)
1715                 : base(callback, state)
1716             {
1717                 this.communicationObject = obj as ICommunicationObject;
1718
1719                 bool completeSelf = false;
1720                 if (this.communicationObject == null)
1721                 {
1722                     IDisposable disposable = obj as IDisposable;
1723                     if (disposable != null)
1724                     {
1725                         disposable.Dispose();
1726                     }
1727                     completeSelf = true;
1728                 }
1729                 else
1730                 {
1731                     if (onClose == null)
1732                     {
1733                         onClose = Fx.ThunkCallback(new AsyncCallback(OnClose));
1734                     }
1735
1736                     IAsyncResult result = this.communicationObject.BeginClose(timeout, onClose, this);
1737                     if (result.CompletedSynchronously)
1738                     {
1739                         this.communicationObject.EndClose(result);
1740                         completeSelf = true;
1741                     }
1742                 }
1743
1744                 if (completeSelf)
1745                 {
1746                     base.Complete(true);
1747                 }
1748             }
1749
1750             public static void End(IAsyncResult result)
1751             {
1752                 AsyncResult.End<CloseCommunicationObjectAsyncResult>(result);
1753             }
1754
1755             static void OnClose(IAsyncResult result)
1756             {
1757                 if (result.CompletedSynchronously)
1758                 {
1759                     return;
1760                 }
1761
1762                 CloseCommunicationObjectAsyncResult thisPtr =
1763                     (CloseCommunicationObjectAsyncResult)result.AsyncState;
1764
1765                 Exception completionException = null;
1766                 try
1767                 {
1768                     thisPtr.communicationObject.EndClose(result);
1769                 }
1770 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1771                 catch (Exception e)
1772                 {
1773                     if (Fx.IsFatal(e))
1774                     {
1775                         throw;
1776                     }
1777
1778                     completionException = e;
1779                 }
1780                 thisPtr.Complete(false, completionException);
1781             }
1782         }
1783
1784         internal static void MatchRstWithEndpointFilter(Message rst, IMessageFilterTable<EndpointAddress> endpointFilterTable, Uri listenUri)
1785         {
1786             if (endpointFilterTable == null)
1787             {
1788                 return;
1789             }
1790             Collection<EndpointAddress> result = new Collection<EndpointAddress>();
1791             if (!endpointFilterTable.GetMatchingValues(rst, result))
1792             {
1793                 throw TraceUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.RequestSecurityTokenDoesNotMatchEndpointFilters, listenUri)), rst);
1794             }
1795         }
1796
1797         // match the RST with the endpoint filters in case there is at least 1 asymmetric signature in the message
1798         internal static bool ShouldMatchRstWithEndpointFilter(SecurityBindingElement sbe)
1799         {
1800             foreach (SecurityTokenParameters parameters in new SecurityTokenParametersEnumerable(sbe, true))
1801             {
1802                 if (parameters.HasAsymmetricKey)
1803                 {
1804                     return true;
1805                 }
1806             }
1807             return false;
1808         }
1809
1810         internal static SecurityStandardsManager CreateSecurityStandardsManager(MessageSecurityVersion securityVersion, SecurityTokenManager tokenManager)
1811         {
1812             SecurityTokenSerializer tokenSerializer = tokenManager.CreateSecurityTokenSerializer(securityVersion.SecurityTokenVersion);
1813             return new SecurityStandardsManager(securityVersion, tokenSerializer);
1814         }
1815
1816         internal static SecurityStandardsManager CreateSecurityStandardsManager(SecurityTokenRequirement requirement, SecurityTokenManager tokenManager)
1817         {
1818             MessageSecurityTokenVersion securityVersion = (MessageSecurityTokenVersion)requirement.GetProperty<MessageSecurityTokenVersion>(ServiceModelSecurityTokenRequirement.MessageSecurityVersionProperty);
1819             if (securityVersion == MessageSecurityTokenVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005BasicSecurityProfile10)
1820                 return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, tokenManager);
1821             else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005)
1822                 return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11, tokenManager);
1823             else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005BasicSecurityProfile10)
1824                 return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, tokenManager);
1825             else if (securityVersion == MessageSecurityTokenVersion.WSSecurity10WSTrust13WSSecureConversation13BasicSecurityProfile10)
1826                 return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10, tokenManager);
1827             else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrust13WSSecureConversation13)
1828                 return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12, tokenManager);
1829             else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrust13WSSecureConversation13BasicSecurityProfile10)
1830                 return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10, tokenManager);
1831             else
1832                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1833         }
1834
1835         internal static SecurityStandardsManager CreateSecurityStandardsManager(MessageSecurityVersion securityVersion, SecurityTokenSerializer securityTokenSerializer)
1836         {
1837             if (securityVersion == null)
1838             {
1839                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("securityVersion"));
1840             }
1841             if (securityTokenSerializer == null)
1842             {
1843                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenSerializer");
1844             }
1845             return new SecurityStandardsManager(securityVersion, securityTokenSerializer);
1846         }
1847
1848         static bool TryCreateIdentity(ClaimSet claimSet, string claimType, out EndpointIdentity identity)
1849         {
1850             identity = null;
1851             foreach (Claim claim in claimSet.FindClaims(claimType, null))
1852             {
1853                 identity = EndpointIdentity.CreateIdentity(claim);
1854                 return true;
1855             }
1856             return false;
1857         }
1858
1859         internal static EndpointIdentity GetServiceCertificateIdentity(X509Certificate2 certificate)
1860         {
1861             using (X509CertificateClaimSet claimSet = new X509CertificateClaimSet(certificate))
1862             {
1863                 EndpointIdentity identity;
1864                 if (!TryCreateIdentity(claimSet, ClaimTypes.Dns, out identity))
1865                 {
1866                     TryCreateIdentity(claimSet, ClaimTypes.Rsa, out identity);
1867                 }
1868                 return identity;
1869             }
1870         }
1871
1872         [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method UnsafeGetPassword to access the credential password without a Demand.",
1873             Safe = "Only uses the password to construct a new NetworkCredential which will then protect access, password does not leak from this method.")]
1874         [SecuritySafeCritical]
1875         internal static NetworkCredential GetNetworkCredentialsCopy(NetworkCredential networkCredential)
1876         {
1877             NetworkCredential result;
1878             if (networkCredential != null && !NetworkCredentialHelper.IsDefault(networkCredential))
1879             {
1880                 result = new NetworkCredential(NetworkCredentialHelper.UnsafeGetUsername(networkCredential), NetworkCredentialHelper.UnsafeGetPassword(networkCredential), NetworkCredentialHelper.UnsafeGetDomain(networkCredential));
1881             }
1882             else
1883             {
1884                 result = networkCredential;
1885             }
1886             return result;
1887         }
1888
1889         internal static NetworkCredential GetNetworkCredentialOrDefault(NetworkCredential credential)
1890         {
1891             // because of VSW 564452, we dont use CredentialCache.DefaultNetworkCredentials in our OM. Instead we
1892             // use an empty NetworkCredential to denote the default credentials
1893             if (NetworkCredentialHelper.IsNullOrEmpty(credential))
1894             {
1895                 // FYI: this will fail with SecurityException in PT due to Demand for EnvironmentPermission.
1896                 // Typically a PT app should not have access to DefaultNetworkCredentials. If there is a valid reason,
1897                 // see UnsafeGetDefaultNetworkCredentials.
1898                 return CredentialCache.DefaultNetworkCredentials;
1899             }
1900             else
1901             {
1902                 return credential;
1903             }
1904         }
1905
1906         public static bool CanReadPrivateKey(X509Certificate2 certificate)
1907         {
1908             if (!certificate.HasPrivateKey)
1909                 return false;
1910
1911             try
1912             {
1913                 // CNG key, CNG permissions tests
1914                 using (RSA rsa = CngLightup.GetRSAPrivateKey(certificate))
1915                 {
1916                     if (rsa != null)
1917                     {
1918                         return true;
1919                     }
1920                 }
1921
1922                 using (DSA dsa = CngLightup.GetDSAPrivateKey(certificate))
1923                 {
1924                     if (dsa != null)
1925                     {
1926                         return true;
1927                     }
1928                 }
1929
1930                 using (ECDsa ecdsa = CngLightup.GetECDsaPrivateKey(certificate))
1931                 {
1932                     if (ecdsa != null)
1933                     {
1934                         return true;
1935                     }
1936                 }
1937
1938                 // CAPI key, CAPI permissions test
1939                 if (certificate.PrivateKey != null)
1940                 {
1941                     return true;
1942                 }
1943
1944                 return false;
1945             }
1946             catch (CryptographicException)
1947             {
1948                 return false;
1949             }
1950         }
1951
1952         static class NetworkCredentialHelper
1953         {
1954             [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical methods UnsafeGetUsername, UnsafeGetPassword, and UnsafeGetDomain to access the credential details without a Demand.",
1955                 Safe = "Only uses the protected values to test for null/empty.  Does not leak.")]
1956             [SecuritySafeCritical]
1957             static internal bool IsNullOrEmpty(NetworkCredential credential)
1958             {
1959                 return credential == null ||
1960                         (
1961                             String.IsNullOrEmpty(UnsafeGetUsername(credential)) &&
1962                             String.IsNullOrEmpty(UnsafeGetDomain(credential)) &&
1963                             String.IsNullOrEmpty(UnsafeGetPassword(credential))
1964                         );
1965             }
1966
1967             [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method UnsafeGetDefaultNetworkCredentials to access the default network credentials without a Demand.",
1968                 Safe = "Only uses the default credentials to test for equality and uses the system credential's .Equals, not the caller's.")]
1969             [SecuritySafeCritical]
1970             static internal bool IsDefault(NetworkCredential credential)
1971             {
1972                 return UnsafeGetDefaultNetworkCredentials().Equals(credential);
1973             }
1974
1975             [Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission(UnmanagedCode) in order to get the NetworkCredential password."
1976                 + "This is used for example to test for empty/null or to construct a cloned NetworkCredential."
1977                 + "Callers absolutely must not leak the return value.")]
1978             [SecurityCritical]
1979             [EnvironmentPermission(SecurityAction.Assert, Read = "USERNAME")]
1980             static internal string UnsafeGetUsername(NetworkCredential credential)
1981             {
1982                 return credential.UserName;
1983             }
1984
1985             [Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission(UnmanagedCode) in order to get the NetworkCredential password."
1986                 + "This is used for example to test for empty/null or to construct a cloned NetworkCredential."
1987                 + "Callers absolutely must not leak the return value.")]
1988             [SecurityCritical]
1989             [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
1990             static internal string UnsafeGetPassword(NetworkCredential credential)
1991             {
1992                 return credential.Password;
1993             }
1994
1995             [Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission(UnmanagedCode) in order to get the NetworkCredential password."
1996                 + "This is used for example to test for empty/null or to construct a cloned NetworkCredential."
1997                 + "Callers absolutely must not leak the return value.")]
1998             [SecurityCritical]
1999             [EnvironmentPermission(SecurityAction.Assert, Read = "USERDOMAIN")]
2000             static internal string UnsafeGetDomain(NetworkCredential credential)
2001             {
2002                 return credential.Domain;
2003             }
2004
2005             [Fx.Tag.SecurityNote(Critical = "Asserts EnvironmentPermission(Read='USERNAME') in order to get the DefaultNetworkCredentials in PT."
2006                 + "This is used for example to test for instance equality with a specific NetworkCredential."
2007                 + "Callers absolutely must not leak the return value.")]
2008             [SecurityCritical]
2009             [EnvironmentPermission(SecurityAction.Assert, Read = "USERNAME")]
2010             static NetworkCredential UnsafeGetDefaultNetworkCredentials()
2011             {
2012                 return CredentialCache.DefaultNetworkCredentials;
2013             }
2014         }
2015
2016         internal static SafeFreeCredentials GetCredentialsHandle(string package, NetworkCredential credential, bool isServer, params string[] additionalPackages)
2017         {
2018             SafeFreeCredentials credentialsHandle;
2019             CredentialUse credentialUse = isServer ? CredentialUse.Inbound : CredentialUse.Outbound;
2020             if (credential == null || NetworkCredentialHelper.IsDefault(credential))
2021             {
2022                 AuthIdentityEx authIdentity = new AuthIdentityEx(null, null, null, additionalPackages);
2023                 credentialsHandle = SspiWrapper.AcquireCredentialsHandle(package, credentialUse, ref authIdentity);
2024             }
2025             else
2026             {
2027                 SecurityUtils.FixNetworkCredential(ref credential);
2028
2029                 // we're not using DefaultCredentials, we need a
2030                 // AuthIdentity struct to contain credentials
2031                 AuthIdentityEx authIdentity = new AuthIdentityEx(credential.UserName, credential.Password, credential.Domain);
2032                 credentialsHandle = SspiWrapper.AcquireCredentialsHandle(package, credentialUse, ref authIdentity);
2033             }
2034             return credentialsHandle;
2035         }
2036
2037         internal static SafeFreeCredentials GetCredentialsHandle(Binding binding, KeyedByTypeCollection<IEndpointBehavior> behaviors)
2038         {
2039             ClientCredentials clientCredentials = (behaviors == null) ? null : behaviors.Find<ClientCredentials>();
2040             return GetCredentialsHandle(binding, clientCredentials);
2041         }
2042
2043         internal static SafeFreeCredentials GetCredentialsHandle(Binding binding, ClientCredentials clientCredentials)
2044         {
2045             SecurityBindingElement sbe = (binding == null) ? null : binding.CreateBindingElements().Find<SecurityBindingElement>();
2046             return GetCredentialsHandle(sbe, clientCredentials);
2047         }
2048
2049         internal static SafeFreeCredentials GetCredentialsHandle(SecurityBindingElement sbe, BindingContext context)
2050         {
2051             ClientCredentials clientCredentials = (context == null) ? null : context.BindingParameters.Find<ClientCredentials>();
2052             return GetCredentialsHandle(sbe, clientCredentials);
2053         }
2054
2055         internal static SafeFreeCredentials GetCredentialsHandle(SecurityBindingElement sbe, ClientCredentials clientCredentials)
2056         {
2057             if (sbe == null)
2058             {
2059                 return null;
2060             }
2061
2062             bool isSspi = false;
2063             bool isKerberos = false;
2064             foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true))
2065             {
2066                 if (stp is SecureConversationSecurityTokenParameters)
2067                 {
2068                     SafeFreeCredentials result = GetCredentialsHandle(((SecureConversationSecurityTokenParameters)stp).BootstrapSecurityBindingElement, clientCredentials);
2069                     if (result != null)
2070                     {
2071                         return result;
2072                     }
2073                     continue;
2074                 }
2075                 else if (stp is IssuedSecurityTokenParameters)
2076                 {
2077                     SafeFreeCredentials result = GetCredentialsHandle(((IssuedSecurityTokenParameters)stp).IssuerBinding, clientCredentials);
2078                     if (result != null)
2079                     {
2080                         return result;
2081                     }
2082                     continue;
2083                 }
2084                 else if (stp is SspiSecurityTokenParameters)
2085                 {
2086                     isSspi = true;
2087                     break;
2088                 }
2089                 else if (stp is KerberosSecurityTokenParameters)
2090                 {
2091                     isKerberos = true;
2092                     break;
2093                 }
2094             }
2095             if (!isSspi && !isKerberos)
2096             {
2097                 return null;
2098             }
2099
2100             NetworkCredential credential = null;
2101             if (clientCredentials != null)
2102             {
2103                 credential = SecurityUtils.GetNetworkCredentialOrDefault(clientCredentials.Windows.ClientCredential);
2104             }
2105
2106             if (isKerberos)
2107             {
2108                 return SecurityUtils.GetCredentialsHandle("Kerberos", credential, false);
2109             }
2110             // if OS is less that Vista cannot use !NTLM, Windows SE 142400
2111
2112 // To disable AllowNtlm warning.
2113 #pragma warning disable 618
2114
2115             else if (clientCredentials != null && !clientCredentials.Windows.AllowNtlm)
2116             {
2117                 if (SecurityUtils.IsOsGreaterThanXP())
2118                 {
2119                     return SecurityUtils.GetCredentialsHandle("Negotiate", credential, false, "!NTLM");
2120                 }
2121                 else
2122                 {
2123                     return SecurityUtils.GetCredentialsHandle("Kerberos", credential, false);
2124                 }
2125             }
2126
2127 #pragma warning restore 618
2128
2129             return SecurityUtils.GetCredentialsHandle("Negotiate", credential, false);
2130         }
2131
2132         internal static byte[] CloneBuffer(byte[] buffer)
2133         {
2134             byte[] copy = DiagnosticUtility.Utility.AllocateByteArray(buffer.Length);
2135             Buffer.BlockCopy(buffer, 0, copy, 0, buffer.Length);
2136             return copy;
2137         }
2138
2139         internal static X509Certificate2 GetCertificateFromStore(StoreName storeName, StoreLocation storeLocation,
2140             X509FindType findType, object findValue, EndpointAddress target)
2141         {
2142             X509Certificate2 certificate = GetCertificateFromStoreCore(storeName, storeLocation, findType, findValue, target, true);
2143             if (certificate == null)
2144                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotFindCert, storeName, storeLocation, findType, findValue)));
2145
2146             return certificate;
2147         }
2148
2149         internal static bool TryGetCertificateFromStore(StoreName storeName, StoreLocation storeLocation,
2150             X509FindType findType, object findValue, EndpointAddress target, out X509Certificate2 certificate)
2151         {
2152             certificate = GetCertificateFromStoreCore(storeName, storeLocation, findType, findValue, target, false);
2153             return (certificate != null);
2154         }
2155
2156         static X509Certificate2 GetCertificateFromStoreCore(StoreName storeName, StoreLocation storeLocation,
2157             X509FindType findType, object findValue, EndpointAddress target, bool throwIfMultipleOrNoMatch)
2158         {
2159             if (findValue == null)
2160             {
2161                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("findValue");
2162             }
2163             X509CertificateStore store = new X509CertificateStore(storeName, storeLocation);
2164             X509Certificate2Collection certs = null;
2165             try
2166             {
2167                 store.Open(OpenFlags.ReadOnly);
2168                 certs = store.Find(findType, findValue, false);
2169                 if (certs.Count == 1)
2170                 {
2171                     return new X509Certificate2(certs[0]);
2172                 }
2173                 if (throwIfMultipleOrNoMatch)
2174                 {
2175                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateCertificateLoadException(
2176                         storeName, storeLocation, findType, findValue, target, certs.Count));
2177                 }
2178                 else
2179                 {
2180                     return null;
2181                 }
2182             }
2183             finally
2184             {
2185                 SecurityUtils.ResetAllCertificates(certs);
2186                 store.Close();
2187             }
2188         }
2189
2190         static Exception CreateCertificateLoadException(StoreName storeName, StoreLocation storeLocation,
2191             X509FindType findType, object findValue, EndpointAddress target, int certCount)
2192         {
2193             if (certCount == 0)
2194             {
2195                 if (target == null)
2196                 {
2197                     return new InvalidOperationException(SR.GetString(SR.CannotFindCert, storeName, storeLocation, findType, findValue));
2198                 }
2199                 else
2200                 {
2201                     return new InvalidOperationException(SR.GetString(SR.CannotFindCertForTarget, storeName, storeLocation, findType, findValue, target));
2202                 }
2203             }
2204             else
2205             {
2206                 if (target == null)
2207                 {
2208                     return new InvalidOperationException(SR.GetString(SR.FoundMultipleCerts, storeName, storeLocation, findType, findValue));
2209                 }
2210                 else
2211                 {
2212                     return new InvalidOperationException(SR.GetString(SR.FoundMultipleCertsForTarget, storeName, storeLocation, findType, findValue, target));
2213                 }
2214             }
2215         }
2216
2217         public static SecurityBindingElement GetIssuerSecurityBindingElement(ServiceModelSecurityTokenRequirement requirement)
2218         {
2219             SecurityBindingElement bindingElement = requirement.SecureConversationSecurityBindingElement;
2220             if (bindingElement != null)
2221             {
2222                 return bindingElement;
2223             }
2224
2225             Binding binding = requirement.IssuerBinding;
2226             if (binding == null)
2227             {
2228                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.IssuerBindingNotPresentInTokenRequirement, requirement));
2229             }
2230             BindingElementCollection bindingElements = binding.CreateBindingElements();
2231             return bindingElements.Find<SecurityBindingElement>();
2232         }
2233
2234         public static int GetMaxNegotiationBufferSize(BindingContext bindingContext)
2235         {
2236             TransportBindingElement transport = bindingContext.RemainingBindingElements.Find<TransportBindingElement>();
2237             Fx.Assert(transport != null, "TransportBindingElement is null!");
2238             int maxNegoMessageSize;
2239             if (transport is ConnectionOrientedTransportBindingElement)
2240             {
2241                 maxNegoMessageSize = ((ConnectionOrientedTransportBindingElement)transport).MaxBufferSize;
2242             }
2243             else if (transport is HttpTransportBindingElement)
2244             {
2245                 maxNegoMessageSize = ((HttpTransportBindingElement)transport).MaxBufferSize;
2246             }
2247             else
2248             {
2249                 maxNegoMessageSize = TransportDefaults.MaxBufferSize;
2250             }
2251             return maxNegoMessageSize;
2252         }
2253
2254         public static bool TryCreateKeyFromIntrinsicKeyClause(SecurityKeyIdentifierClause keyIdentifierClause, SecurityTokenResolver resolver, out SecurityKey key)
2255         {
2256             key = null;
2257             if (keyIdentifierClause.CanCreateKey)
2258             {
2259                 key = keyIdentifierClause.CreateKey();
2260                 return true;
2261             }
2262             if (keyIdentifierClause is EncryptedKeyIdentifierClause)
2263             {
2264                 EncryptedKeyIdentifierClause keyClause = (EncryptedKeyIdentifierClause)keyIdentifierClause;
2265                 // PreSharp Bug: Parameter 'keyClause' to this public method must be validated: A null-dereference can occur here.
2266 #pragma warning suppress 56506 // keyClause will not be null due to the if condition above.
2267                 for (int i = 0; i < keyClause.EncryptingKeyIdentifier.Count; i++)
2268                 {
2269                     SecurityKey unwrappingSecurityKey = null;
2270                     if (resolver.TryResolveSecurityKey(keyClause.EncryptingKeyIdentifier[i], out unwrappingSecurityKey))
2271                     {
2272                         byte[] wrappedKey = keyClause.GetEncryptedKey();
2273                         string wrappingAlgorithm = keyClause.EncryptionMethod;
2274                         byte[] unwrappedKey = unwrappingSecurityKey.DecryptKey(wrappingAlgorithm, wrappedKey);
2275                         key = new InMemorySymmetricSecurityKey(unwrappedKey, false);
2276                         return true;
2277                     }
2278                 }
2279             }
2280             return false;
2281         }
2282
2283         public static WrappedKeySecurityToken CreateTokenFromEncryptedKeyClause(EncryptedKeyIdentifierClause keyClause, SecurityToken unwrappingToken)
2284         {
2285             SecurityKeyIdentifier wrappingTokenReference = keyClause.EncryptingKeyIdentifier;
2286             byte[] wrappedKey = keyClause.GetEncryptedKey();
2287             SecurityKey unwrappingSecurityKey = unwrappingToken.SecurityKeys[0];
2288             string wrappingAlgorithm = keyClause.EncryptionMethod;
2289             byte[] unwrappedKey = unwrappingSecurityKey.DecryptKey(wrappingAlgorithm, wrappedKey);
2290             return new WrappedKeySecurityToken(SecurityUtils.GenerateId(), unwrappedKey, wrappingAlgorithm,
2291                 unwrappingToken, wrappingTokenReference, wrappedKey, unwrappingSecurityKey
2292                     );
2293         }
2294
2295         public static void ValidateAnonymityConstraint(WindowsIdentity identity, bool allowUnauthenticatedCallers)
2296         {
2297             if (!allowUnauthenticatedCallers && identity.User.IsWellKnown(WellKnownSidType.AnonymousSid))
2298             {
2299                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(
2300                     new SecurityTokenValidationException(SR.GetString(SR.AnonymousLogonsAreNotAllowed)));
2301             }
2302         }
2303
2304         static bool ComputeSslCipherStrengthRequirementFlag()
2305         {
2306             // validate only for  XP versions < XP SP3 and windows server versions < Win2K3 SP2
2307             if ((Environment.OSVersion.Version.Major > WindowsServerMajorNumber)
2308                 || (Environment.OSVersion.Version.Major == WindowsServerMajorNumber && Environment.OSVersion.Version.Minor > WindowsServerMinorNumber))
2309             {
2310                 return false;
2311             }
2312             // version <= Win2K3
2313             if (Environment.OSVersion.Version.Major == XPMajorNumber && Environment.OSVersion.Version.Minor == XPMinorNumber)
2314             {
2315                 if ((Environment.OSVersion.ServicePack == string.Empty) || String.Equals(Environment.OSVersion.ServicePack, ServicePack1, StringComparison.OrdinalIgnoreCase) || String.Equals(Environment.OSVersion.ServicePack, ServicePack2, StringComparison.OrdinalIgnoreCase))
2316                 {
2317                     return true;
2318                 }
2319                 else
2320                 {
2321                     // the OS is XP SP3 or higher
2322                     return false;
2323                 }
2324             }
2325             else if (Environment.OSVersion.Version.Major == WindowsServerMajorNumber && Environment.OSVersion.Version.Minor == WindowsServerMinorNumber)
2326             {
2327                 if (Environment.OSVersion.ServicePack == string.Empty || String.Equals(Environment.OSVersion.ServicePack, ServicePack1, StringComparison.OrdinalIgnoreCase))
2328                 {
2329                     return true;
2330                 }
2331                 else
2332                 {
2333                     // the OS is Win2K3 SP2 or higher
2334                     return false;
2335                 }
2336             }
2337             else
2338             {
2339                 // this is <= XP. We should never get here but if we do validate SSL strength
2340                 return true;
2341             }
2342         }
2343
2344         public static bool ShouldValidateSslCipherStrength()
2345         {
2346             if (!isSslValidationRequirementDetermined)
2347             {
2348                 shouldValidateSslCipherStrength = ComputeSslCipherStrengthRequirementFlag();
2349                 Thread.MemoryBarrier();
2350                 isSslValidationRequirementDetermined = true;
2351             }
2352             return shouldValidateSslCipherStrength;
2353         }
2354
2355         public static void ValidateSslCipherStrength(int keySizeInBits)
2356         {
2357             if (ShouldValidateSslCipherStrength() && keySizeInBits < MinimumSslCipherStrength)
2358             {
2359                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.SslCipherKeyTooSmall, keySizeInBits, MinimumSslCipherStrength)));
2360             }
2361         }
2362
2363         public static bool TryCreateX509CertificateFromRawData(byte[] rawData, out X509Certificate2 certificate)
2364         {
2365             certificate = (rawData == null || rawData.Length == 0) ? null : new X509Certificate2(rawData);
2366             return certificate != null && certificate.Handle != IntPtr.Zero;
2367         }
2368
2369         internal static string GetKeyDerivationAlgorithm(SecureConversationVersion version)
2370         {
2371             string derivationAlgorithm = null;
2372             if (version == SecureConversationVersion.WSSecureConversationFeb2005)
2373             {
2374                 derivationAlgorithm = SecurityAlgorithms.Psha1KeyDerivation;
2375             }
2376             else if (version == SecureConversationVersion.WSSecureConversation13)
2377             {
2378                 derivationAlgorithm = SecurityAlgorithms.Psha1KeyDerivationDec2005;
2379             }
2380             else
2381             {
2382                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
2383             }
2384
2385             return derivationAlgorithm;
2386         }
2387
2388     }
2389
2390     struct SecurityUniqueId
2391     {
2392         static long nextId = 0;
2393         static string commonPrefix = "uuid-" + Guid.NewGuid().ToString() + "-";
2394
2395         long id;
2396         string prefix;
2397         string val;
2398
2399         SecurityUniqueId(string prefix, long id)
2400         {
2401             this.id = id;
2402             this.prefix = prefix;
2403             this.val = null;
2404         }
2405
2406         public static SecurityUniqueId Create()
2407         {
2408             return SecurityUniqueId.Create(commonPrefix);
2409         }
2410
2411         public static SecurityUniqueId Create(string prefix)
2412         {
2413             return new SecurityUniqueId(prefix, Interlocked.Increment(ref nextId));
2414         }
2415
2416         public string Value
2417         {
2418             get
2419             {
2420                 if (this.val == null)
2421                     this.val = this.prefix + this.id.ToString(CultureInfo.InvariantCulture);
2422
2423                 return this.val;
2424             }
2425         }
2426     }
2427
2428     static class EmptyReadOnlyCollection<T>
2429     {
2430         public static ReadOnlyCollection<T> Instance = new ReadOnlyCollection<T>(new List<T>());
2431     }
2432
2433     class OperationWithTimeoutAsyncResult : TraceAsyncResult
2434     {
2435         static readonly Action<object> scheduledCallback = new Action<object>(OnScheduled);
2436         TimeoutHelper timeoutHelper;
2437         OperationWithTimeoutCallback operationWithTimeout;
2438
2439         public OperationWithTimeoutAsyncResult(OperationWithTimeoutCallback operationWithTimeout, TimeSpan timeout, AsyncCallback callback, object state)
2440             : base(callback, state)
2441         {
2442             this.operationWithTimeout = operationWithTimeout;
2443             this.timeoutHelper = new TimeoutHelper(timeout);
2444             ActionItem.Schedule(scheduledCallback, this);
2445         }
2446
2447         static void OnScheduled(object state)
2448         {
2449             OperationWithTimeoutAsyncResult thisResult = (OperationWithTimeoutAsyncResult)state;
2450             Exception completionException = null;
2451             try
2452             {
2453                 using (thisResult.CallbackActivity == null ? null : ServiceModelActivity.BoundOperation(thisResult.CallbackActivity))
2454                 {
2455                     thisResult.operationWithTimeout(thisResult.timeoutHelper.RemainingTime());
2456                 }
2457             }
2458 #pragma warning suppress 56500 // covered by FxCOP
2459             catch (Exception e)
2460             {
2461                 if (Fx.IsFatal(e))
2462                 {
2463                     throw;
2464                 }
2465
2466                 completionException = e;
2467             }
2468             thisResult.Complete(false, completionException);
2469         }
2470
2471         public static void End(IAsyncResult result)
2472         {
2473             AsyncResult.End<OperationWithTimeoutAsyncResult>(result);
2474         }
2475     }
2476 }