//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Security { using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.DirectoryServices.ActiveDirectory; using System.Globalization; using System.IdentityModel.Claims; using System.IdentityModel.Policy; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Net; using System.Net.Security; using System.Runtime; using System.Security; using System.Security.Authentication; using System.Security.Authentication.ExtendedProtection; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Security.Principal; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; using System.ServiceModel.Dispatcher; using System.ServiceModel.Security.Tokens; using System.Text; using System.Threading; using System.Xml; using Microsoft.Win32; using AuthIdentityEx = System.IdentityModel.AuthIdentityEx; using CredentialUse = System.IdentityModel.CredentialUse; using DictionaryManager = System.IdentityModel.DictionaryManager; using SafeFreeCredentials = System.IdentityModel.SafeFreeCredentials; using SspiWrapper = System.IdentityModel.SspiWrapper; static class StoreLocationHelper { internal static bool IsDefined(StoreLocation value) { return (value == StoreLocation.CurrentUser || value == StoreLocation.LocalMachine); } } static class ProtectionLevelHelper { internal static bool IsDefined(ProtectionLevel value) { return (value == ProtectionLevel.None || value == ProtectionLevel.Sign || value == ProtectionLevel.EncryptAndSign); } internal static void Validate(ProtectionLevel value) { if (!IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("value", (int)value, typeof(ProtectionLevel))); } } internal static bool IsStronger(ProtectionLevel v1, ProtectionLevel v2) { return ((v1 == ProtectionLevel.EncryptAndSign && v2 != ProtectionLevel.EncryptAndSign) || (v1 == ProtectionLevel.Sign && v2 == ProtectionLevel.None)); } internal static bool IsStrongerOrEqual(ProtectionLevel v1, ProtectionLevel v2) { return (v1 == ProtectionLevel.EncryptAndSign || (v1 == ProtectionLevel.Sign && v2 != ProtectionLevel.EncryptAndSign)); } internal static ProtectionLevel Max(ProtectionLevel v1, ProtectionLevel v2) { return IsStronger(v1, v2) ? v1 : v2; } internal static int GetOrdinal(Nullable p) { if (p.HasValue) { switch ((ProtectionLevel)p) { default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("p", (int)p, typeof(ProtectionLevel))); case ProtectionLevel.None: return 2; case ProtectionLevel.Sign: return 3; case ProtectionLevel.EncryptAndSign: return 4; } } else return 1; } } static class SslProtocolsHelper { internal static bool IsDefined(SslProtocols value) { SslProtocols allValues = SslProtocols.None; foreach (var protocol in Enum.GetValues(typeof(SslProtocols))) { allValues |= (SslProtocols)protocol; } return (value & allValues) == value; } internal static void Validate(SslProtocols value) { if (!IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("value", (int)value, typeof(SslProtocols))); } } } static class TokenImpersonationLevelHelper { internal static bool IsDefined(TokenImpersonationLevel value) { return (value == TokenImpersonationLevel.None || value == TokenImpersonationLevel.Anonymous || value == TokenImpersonationLevel.Identification || value == TokenImpersonationLevel.Impersonation || value == TokenImpersonationLevel.Delegation); } internal static void Validate(TokenImpersonationLevel value) { if (!IsDefined(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("value", (int)value, typeof(TokenImpersonationLevel))); } } static TokenImpersonationLevel[] TokenImpersonationLevelOrder = new TokenImpersonationLevel[] { TokenImpersonationLevel.None, TokenImpersonationLevel.Anonymous, TokenImpersonationLevel.Identification, TokenImpersonationLevel.Impersonation, TokenImpersonationLevel.Delegation }; internal static string ToString(TokenImpersonationLevel impersonationLevel) { if (impersonationLevel == TokenImpersonationLevel.Identification) { return "identification"; } else if (impersonationLevel == TokenImpersonationLevel.None) { return "none"; } else if (impersonationLevel == TokenImpersonationLevel.Anonymous) { return "anonymous"; } else if (impersonationLevel == TokenImpersonationLevel.Impersonation) { return "impersonation"; } else if (impersonationLevel == TokenImpersonationLevel.Delegation) { return "delegation"; } Fx.Assert("unknown token impersonation level"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("impersonationLevel", (int)impersonationLevel, typeof(TokenImpersonationLevel))); } internal static bool IsGreaterOrEqual(TokenImpersonationLevel x, TokenImpersonationLevel y) { TokenImpersonationLevelHelper.Validate(x); TokenImpersonationLevelHelper.Validate(y); if (x == y) return true; int px = 0; int py = 0; for (int i = 0; i < TokenImpersonationLevelOrder.Length; i++) { if (x == TokenImpersonationLevelOrder[i]) px = i; if (y == TokenImpersonationLevelOrder[i]) py = i; } return (px > py); } internal static int Compare(TokenImpersonationLevel x, TokenImpersonationLevel y) { int result = 0; if (x != y) { switch (x) { case TokenImpersonationLevel.Identification: result = -1; break; case TokenImpersonationLevel.Impersonation: switch (y) { case TokenImpersonationLevel.Identification: result = 1; break; case TokenImpersonationLevel.Delegation: result = -1; break; default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("y", (int)y, typeof(TokenImpersonationLevel))); } break; case TokenImpersonationLevel.Delegation: result = 1; break; default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnumArgumentException("x", (int)x, typeof(TokenImpersonationLevel))); } } return result; } } internal class ServiceModelDictionaryManager { static DictionaryManager dictionaryManager; public static DictionaryManager Instance { get { if (dictionaryManager == null) dictionaryManager = new DictionaryManager(BinaryMessageEncoderFactory.XmlDictionary); return dictionaryManager; } } } static class SecurityUtils { public const string Principal = "Principal"; public const string Identities = "Identities"; static bool computedDomain; static string currentDomain; static byte[] combinedHashLabel; static IIdentity anonymousIdentity; static NetworkCredential dummyNetworkCredential; static object dummyNetworkCredentialLock = new object(); static X509SecurityTokenAuthenticator nonValidatingX509Authenticator; static SecurityIdentifier administratorsSid; const int WindowsServerMajorNumber = 5; const int WindowsServerMinorNumber = 2; const int XPMajorNumber = 5; const int XPMinorNumber = 1; const string ServicePack1 = "Service Pack 1"; const string ServicePack2 = "Service Pack 2"; volatile static bool shouldValidateSslCipherStrength; volatile static bool isSslValidationRequirementDetermined = false; static readonly int MinimumSslCipherStrength = 128; // these are kept in [....] with IIS70 public const string AuthTypeNTLM = "NTLM"; public const string AuthTypeNegotiate = "Negotiate"; public const string AuthTypeKerberos = "Kerberos"; public const string AuthTypeAnonymous = ""; public const string AuthTypeCertMap = "SSL/PCT"; // mapped from a cert public const string AuthTypeBasic = "Basic"; //LogonUser public static ChannelBinding GetChannelBindingFromMessage(Message message) { if (message == null) { return null; } ChannelBindingMessageProperty channelBindingMessageProperty = null; ChannelBindingMessageProperty.TryGet(message, out channelBindingMessageProperty); ChannelBinding channelBinding = null; if (channelBindingMessageProperty != null) { channelBinding = channelBindingMessageProperty.ChannelBinding; } return channelBinding; } internal static bool IsOsGreaterThanXP() { return ((Environment.OSVersion.Version.Major >= SecurityUtils.XPMajorNumber && Environment.OSVersion.Version.Minor > SecurityUtils.XPMinorNumber) || Environment.OSVersion.Version.Major > SecurityUtils.XPMajorNumber); } internal static bool IsOSGreaterThanOrEqualToWin7() { Version windows7Version = new Version(6, 1, 0, 0); return (Environment.OSVersion.Version.Major >= windows7Version.Major && Environment.OSVersion.Version.Minor >= windows7Version.Minor); } internal static bool IsCurrentlyTimeEffective(DateTime effectiveTime, DateTime expirationTime, TimeSpan maxClockSkew) { DateTime curEffectiveTime = (effectiveTime < DateTime.MinValue.Add(maxClockSkew)) ? effectiveTime : effectiveTime.Subtract(maxClockSkew); DateTime curExpirationTime = (expirationTime > DateTime.MaxValue.Subtract(maxClockSkew)) ? expirationTime : expirationTime.Add(maxClockSkew); DateTime curTime = DateTime.UtcNow; return (curEffectiveTime.ToUniversalTime() <= curTime) && (curTime < curExpirationTime.ToUniversalTime()); } internal static X509SecurityTokenAuthenticator NonValidatingX509Authenticator { get { if (nonValidatingX509Authenticator == null) { nonValidatingX509Authenticator = new X509SecurityTokenAuthenticator(X509CertificateValidator.None); } return nonValidatingX509Authenticator; } } public static SecurityIdentifier AdministratorsSid { get { if (administratorsSid == null) administratorsSid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null); return administratorsSid; } } internal static IIdentity AnonymousIdentity { get { if (anonymousIdentity == null) { anonymousIdentity = SecurityUtils.CreateIdentity(String.Empty); } return anonymousIdentity; } } public static DateTime MaxUtcDateTime { get { // + and - TimeSpan.TicksPerDay is to compensate the DateTime.ParseExact (to localtime) overflow. return new DateTime(DateTime.MaxValue.Ticks - TimeSpan.TicksPerDay, DateTimeKind.Utc); } } public static DateTime MinUtcDateTime { get { // + and - TimeSpan.TicksPerDay is to compensate the DateTime.ParseExact (to localtime) overflow. return new DateTime(DateTime.MinValue.Ticks + TimeSpan.TicksPerDay, DateTimeKind.Utc); } } internal static IIdentity CreateIdentity(string name, string authenticationType) { return new GenericIdentity(name, authenticationType); } internal static IIdentity CreateIdentity(string name) { return new GenericIdentity(name); } internal static EndpointIdentity CreateWindowsIdentity() { return CreateWindowsIdentity(false); } internal static EndpointIdentity CreateWindowsIdentity(NetworkCredential serverCredential) { if (serverCredential != null && !NetworkCredentialHelper.IsDefault(serverCredential)) { string upn; if (serverCredential.Domain != null && serverCredential.Domain.Length > 0) { upn = serverCredential.UserName + "@" + serverCredential.Domain; } else { upn = serverCredential.UserName; } return EndpointIdentity.CreateUpnIdentity(upn); } else { return SecurityUtils.CreateWindowsIdentity(); } } static bool IsSystemAccount(WindowsIdentity self) { SecurityIdentifier sid = self.User; if (sid == null) { return false; } // S-1-5-82 is the prefix for the sid that represents the identity that IIS 7.5 Apppool thread runs under. return (sid.IsWellKnown(WellKnownSidType.LocalSystemSid) || sid.IsWellKnown(WellKnownSidType.NetworkServiceSid) || sid.IsWellKnown(WellKnownSidType.LocalServiceSid) || self.User.Value.StartsWith("S-1-5-82", StringComparison.OrdinalIgnoreCase)); } internal static EndpointIdentity CreateWindowsIdentity(bool spnOnly) { EndpointIdentity identity = null; using (WindowsIdentity self = WindowsIdentity.GetCurrent()) { bool isSystemAccount = IsSystemAccount(self); if (spnOnly || isSystemAccount) { identity = EndpointIdentity.CreateSpnIdentity(String.Format(CultureInfo.InvariantCulture, "host/{0}", DnsCache.MachineName)); } else { // Save windowsIdentity for delay lookup identity = new UpnEndpointIdentity(CloneWindowsIdentityIfNecessary(self)); } } return identity; } [Fx.Tag.SecurityNote(Critical = "Calls two critical methods: UnsafeGetWindowsIdentityToken and UnsafeCreateWindowsIdentityFromToken.", Safe = "'Clone' operation is considered safe despite using WindowsIdentity IntPtr token. Must not let IntPtr token leak in or out.")] [SecuritySafeCritical] internal static WindowsIdentity CloneWindowsIdentityIfNecessary(WindowsIdentity wid) { return SecurityUtils.CloneWindowsIdentityIfNecessary(wid, null); } [Fx.Tag.SecurityNote(Critical = "Calls two critical methods: UnsafeGetWindowsIdentityToken and UnsafeCreateWindowsIdentityFromToken.", Safe = "'Clone' operation is considered safe despite using WindowsIdentity IntPtr token. Must not let IntPtr token leak in or out.")] [SecuritySafeCritical] internal static WindowsIdentity CloneWindowsIdentityIfNecessary(WindowsIdentity wid, string authType) { if (wid != null) { IntPtr token = UnsafeGetWindowsIdentityToken(wid); if (token != IntPtr.Zero) { return UnsafeCreateWindowsIdentityFromToken(token, authType); } } return wid; } [Fx.Tag.SecurityNote(Critical = "Elevates in order to return the WindowsIdentity.Token property, caller must protect return value.")] [SecurityCritical] [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] static IntPtr UnsafeGetWindowsIdentityToken(WindowsIdentity wid) { return wid.Token; } [Fx.Tag.SecurityNote(Critical = "Elevates in order to return the SecurityIdentifier of the current user as a string, caller must protect return value.")] [SecurityCritical] [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] static string UnsafeGetCurrentUserSidAsString() { using (WindowsIdentity self = WindowsIdentity.GetCurrent()) { return self.User.Value; } } [Fx.Tag.SecurityNote(Critical = "Elevates in order to return the WindowsIdentity.Token property, caller must protect return value.")] [SecurityCritical] [SecurityPermission(SecurityAction.Assert, ControlPrincipal = true, UnmanagedCode = true)] static WindowsIdentity UnsafeCreateWindowsIdentityFromToken(IntPtr token, string authType) { if (authType != null) return new WindowsIdentity(token, authType); else return new WindowsIdentity(token); } internal static bool AllowsImpersonation(WindowsIdentity windowsIdentity, TokenImpersonationLevel impersonationLevel) { if (windowsIdentity == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("windowsIdentity"); TokenImpersonationLevelHelper.Validate(impersonationLevel); if (impersonationLevel == TokenImpersonationLevel.Identification) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("impersonationLevel")); bool result = true; switch (windowsIdentity.ImpersonationLevel) { case TokenImpersonationLevel.None: case TokenImpersonationLevel.Anonymous: case TokenImpersonationLevel.Identification: result = false; break; case TokenImpersonationLevel.Impersonation: if (impersonationLevel == TokenImpersonationLevel.Delegation) result = false; break; case TokenImpersonationLevel.Delegation: break; default: result = false; break; } return result; } internal static byte[] CombinedHashLabel { get { if (combinedHashLabel == null) combinedHashLabel = Encoding.UTF8.GetBytes(TrustApr2004Strings.CombinedHashLabel); return combinedHashLabel; } } internal static T GetSecurityKey(SecurityToken token) where T : SecurityKey { T result = null; if (token.SecurityKeys != null) { for (int i = 0; i < token.SecurityKeys.Count; ++i) { T temp = (token.SecurityKeys[i] as T); if (temp != null) { if (result != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MultipleMatchingCryptosFound, typeof(T).ToString()))); } else { result = temp; } } } } return result; } internal static bool HasSymmetricSecurityKey(SecurityToken token) { return GetSecurityKey(token) != null; } internal static void EnsureExpectedSymmetricMatch(SecurityToken t1, SecurityToken t2, Message message) { // nulls are not mismatches if (t1 == null || t2 == null || ReferenceEquals(t1, t2)) { return; } // check for interop flexibility SymmetricSecurityKey c1 = SecurityUtils.GetSecurityKey(t1); SymmetricSecurityKey c2 = SecurityUtils.GetSecurityKey(t2); if (c1 == null || c2 == null || !CryptoHelper.IsEqual(c1.GetSymmetricKey(), c2.GetSymmetricKey())) { throw System.ServiceModel.Diagnostics.TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.TokenNotExpectedInSecurityHeader, t2)), message); } } internal static SymmetricAlgorithm GetSymmetricAlgorithm(string algorithm, SecurityToken token) { SymmetricSecurityKey securityKey = SecurityUtils.GetSecurityKey(token); if (securityKey != null && securityKey.IsSupportedAlgorithm(algorithm)) { return securityKey.GetSymmetricAlgorithm(algorithm); } else { return null; } } internal static KeyedHashAlgorithm GetKeyedHashAlgorithm(string algorithm, SecurityToken token) { SymmetricSecurityKey securityKey = SecurityUtils.GetSecurityKey(token); if (securityKey != null && securityKey.IsSupportedAlgorithm(algorithm)) { return securityKey.GetKeyedHashAlgorithm(algorithm); } else { return null; } } internal static ReadOnlyCollection CreateSymmetricSecurityKeys(byte[] key) { List temp = new List(1); temp.Add(new InMemorySymmetricSecurityKey(key)); return temp.AsReadOnly(); } internal static byte[] DecryptKey(SecurityToken unwrappingToken, string encryptionMethod, byte[] wrappedKey, out SecurityKey unwrappingSecurityKey) { unwrappingSecurityKey = null; if (unwrappingToken.SecurityKeys != null) { for (int i = 0; i < unwrappingToken.SecurityKeys.Count; ++i) { if (unwrappingToken.SecurityKeys[i].IsSupportedAlgorithm(encryptionMethod)) { unwrappingSecurityKey = unwrappingToken.SecurityKeys[i]; break; } } } if (unwrappingSecurityKey == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CannotFindMatchingCrypto, encryptionMethod))); } return unwrappingSecurityKey.DecryptKey(encryptionMethod, wrappedKey); } internal static byte[] EncryptKey(SecurityToken wrappingToken, string encryptionMethod, byte[] keyToWrap) { SecurityKey wrappingSecurityKey = null; if (wrappingToken.SecurityKeys != null) { for (int i = 0; i < wrappingToken.SecurityKeys.Count; ++i) { if (wrappingToken.SecurityKeys[i].IsSupportedAlgorithm(encryptionMethod)) { wrappingSecurityKey = wrappingToken.SecurityKeys[i]; break; } } } if (wrappingSecurityKey == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.CannotFindMatchingCrypto, encryptionMethod)); } return wrappingSecurityKey.EncryptKey(encryptionMethod, keyToWrap); } internal static byte[] ReadContentAsBase64(XmlDictionaryReader reader, long maxBufferSize) { if (reader == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); // Code cloned from System.Xml.XmlDictionaryReder. byte[][] buffers = new byte[32][]; byte[] buffer; // Its best to read in buffers that are a multiple of 3 so we don't break base64 boundaries when converting text int count = 384; int bufferCount = 0; int totalRead = 0; while (true) { buffer = new byte[count]; buffers[bufferCount++] = buffer; int read = 0; while (read < buffer.Length) { int actual = reader.ReadContentAsBase64(buffer, read, buffer.Length - read); if (actual == 0) break; read += actual; } if (totalRead > maxBufferSize - read) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(SR.GetString(SR.BufferQuotaExceededReadingBase64, maxBufferSize))); totalRead += read; if (read < buffer.Length) break; count = count * 2; } buffer = new byte[totalRead]; int offset = 0; for (int i = 0; i < bufferCount - 1; i++) { Buffer.BlockCopy(buffers[i], 0, buffer, offset, buffers[i].Length); offset += buffers[i].Length; } Buffer.BlockCopy(buffers[bufferCount - 1], 0, buffer, offset, totalRead - offset); return buffer; } internal static byte[] GenerateDerivedKey(SecurityToken tokenToDerive, string derivationAlgorithm, byte[] label, byte[] nonce, int keySize, int offset) { SymmetricSecurityKey symmetricSecurityKey = SecurityUtils.GetSecurityKey(tokenToDerive); if (symmetricSecurityKey == null || !symmetricSecurityKey.IsSupportedAlgorithm(derivationAlgorithm)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CannotFindMatchingCrypto, derivationAlgorithm))); } return symmetricSecurityKey.GenerateDerivedKey(derivationAlgorithm, label, nonce, keySize, offset); } internal static string GetSpnFromIdentity(EndpointIdentity identity, EndpointAddress target) { bool foundSpn = false; string spn = null; if (identity != null) { if (ClaimTypes.Spn.Equals(identity.IdentityClaim.ClaimType)) { spn = (string)identity.IdentityClaim.Resource; foundSpn = true; } else if (ClaimTypes.Upn.Equals(identity.IdentityClaim.ClaimType)) { spn = (string)identity.IdentityClaim.Resource; foundSpn = true; } else if (ClaimTypes.Dns.Equals(identity.IdentityClaim.ClaimType)) { spn = String.Format(CultureInfo.InvariantCulture, "host/{0}", (string)identity.IdentityClaim.Resource); foundSpn = true; } } if (!foundSpn) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.CannotDetermineSPNBasedOnAddress, target))); } return spn; } internal static string GetSpnFromTarget(EndpointAddress target) { if (target == null) { throw Fx.AssertAndThrow("target should not be null - expecting an EndpointAddress"); } return string.Format(CultureInfo.InvariantCulture, "host/{0}", target.Uri.DnsSafeHost); } internal static bool IsSupportedAlgorithm(string algorithm, SecurityToken token) { if (token.SecurityKeys == null) { return false; } for (int i = 0; i < token.SecurityKeys.Count; ++i) { if (token.SecurityKeys[i].IsSupportedAlgorithm(algorithm)) { return true; } } return false; } internal static Claim GetPrimaryIdentityClaim(ReadOnlyCollection authorizationPolicies) { return GetPrimaryIdentityClaim(AuthorizationContext.CreateDefaultAuthorizationContext(authorizationPolicies)); } internal static Claim GetPrimaryIdentityClaim(AuthorizationContext authContext) { if (authContext != null) { for (int i = 0; i < authContext.ClaimSets.Count; ++i) { ClaimSet claimSet = authContext.ClaimSets[i]; foreach (Claim claim in claimSet.FindClaims(null, Rights.Identity)) { return claim; } } } return null; } internal static int GetServiceAddressAndViaHash(EndpointAddress sr) { if (sr == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("sr"); } return sr.GetHashCode(); } internal static string GenerateId() { return SecurityUniqueId.Create().Value; } internal static string GenerateIdWithPrefix(string prefix) { return SecurityUniqueId.Create(prefix).Value; } internal static UniqueId GenerateUniqueId() { return new UniqueId(); } internal static string GetPrimaryDomain() { using (WindowsIdentity wid = WindowsIdentity.GetCurrent()) { return GetPrimaryDomain(IsSystemAccount(wid)); } } internal static string GetPrimaryDomain(bool isSystemAccount) { if (computedDomain == false) { try { if (isSystemAccount) { currentDomain = Domain.GetComputerDomain().Name; } else { currentDomain = Domain.GetCurrentDomain().Name; } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning); } finally { computedDomain = true; } } return currentDomain; } internal static void EnsureCertificateCanDoKeyExchange(X509Certificate2 certificate) { if (certificate == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("certificate"); } bool canDoKeyExchange = false; Exception innerException = null; if (certificate.HasPrivateKey) { try { canDoKeyExchange = CanKeyDoKeyExchange(certificate); } // exceptions can be due to ACLs on the key etc catch (System.Security.SecurityException e) { innerException = e; } catch (CryptographicException e) { innerException = e; } } if (!canDoKeyExchange) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SslCertMayNotDoKeyExchange, certificate.SubjectName.Name), innerException)); } } [Fx.Tag.SecurityNote(Critical = "Calls critical method GetKeyContainerInfo.", Safe = "Info is not leaked.")] [SecuritySafeCritical] static bool CanKeyDoKeyExchange(X509Certificate2 certificate) { CspKeyContainerInfo info = GetKeyContainerInfo(certificate); return info != null && info.KeyNumber == KeyNumber.Exchange; } [Fx.Tag.SecurityNote(Critical = "Elevates to call properties: X509Certificate2.PrivateKey and CspKeyContainerInfo. Caller must protect the return value.")] [SecurityCritical] [KeyContainerPermission(SecurityAction.Assert, Flags = KeyContainerPermissionFlags.Open)] static CspKeyContainerInfo GetKeyContainerInfo(X509Certificate2 certificate) { RSACryptoServiceProvider rsa = certificate.PrivateKey as RSACryptoServiceProvider; if (rsa != null) { return rsa.CspKeyContainerInfo; } return null; } internal static string GetCertificateId(X509Certificate2 certificate) { StringBuilder str = new StringBuilder(256); AppendCertificateIdentityName(str, certificate); return str.ToString(); } internal static ReadOnlyCollection CreatePrincipalNameAuthorizationPolicies(string principalName) { if (principalName == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("principalName"); Claim identityClaim; Claim primaryPrincipal; if (principalName.Contains("@") || principalName.Contains(@"\")) { identityClaim = new Claim(ClaimTypes.Upn, principalName, Rights.Identity); primaryPrincipal = Claim.CreateUpnClaim(principalName); } else { identityClaim = new Claim(ClaimTypes.Spn, principalName, Rights.Identity); primaryPrincipal = Claim.CreateSpnClaim(principalName); } List claims = new List(2); claims.Add(identityClaim); claims.Add(primaryPrincipal); List policies = new List(1); policies.Add(new UnconditionalPolicy(SecurityUtils.CreateIdentity(principalName), new DefaultClaimSet(ClaimSet.Anonymous, claims))); return policies.AsReadOnly(); } internal static string GetIdentityNamesFromPolicies(IList authPolicies) { return GetIdentityNamesFromContext(AuthorizationContext.CreateDefaultAuthorizationContext(authPolicies)); } internal static string GetIdentityNamesFromContext(AuthorizationContext authContext) { if (authContext == null) return String.Empty; StringBuilder str = new StringBuilder(256); for (int i = 0; i < authContext.ClaimSets.Count; ++i) { ClaimSet claimSet = authContext.ClaimSets[i]; // Windows WindowsClaimSet windows = claimSet as WindowsClaimSet; if (windows != null) { if (str.Length > 0) str.Append(", "); AppendIdentityName(str, windows.WindowsIdentity); } else { // X509 X509CertificateClaimSet x509 = claimSet as X509CertificateClaimSet; if (x509 != null) { if (str.Length > 0) str.Append(", "); AppendCertificateIdentityName(str, x509.X509Certificate); } } } if (str.Length <= 0) { List identities = null; object obj; if (authContext.Properties.TryGetValue(SecurityUtils.Identities, out obj)) { identities = obj as List; } if (identities != null) { for (int i = 0; i < identities.Count; ++i) { IIdentity identity = identities[i]; if (identity != null) { if (str.Length > 0) str.Append(", "); AppendIdentityName(str, identity); } } } } return str.Length <= 0 ? String.Empty : str.ToString(); } internal static void AppendCertificateIdentityName(StringBuilder str, X509Certificate2 certificate) { string value = certificate.SubjectName.Name; if (String.IsNullOrEmpty(value)) { value = certificate.GetNameInfo(X509NameType.DnsName, false); if (String.IsNullOrEmpty(value)) { value = certificate.GetNameInfo(X509NameType.SimpleName, false); if (String.IsNullOrEmpty(value)) { value = certificate.GetNameInfo(X509NameType.EmailName, false); if (String.IsNullOrEmpty(value)) { value = certificate.GetNameInfo(X509NameType.UpnName, false); } } } } // Same format as X509Identity str.Append(String.IsNullOrEmpty(value) ? "" : value); str.Append("; "); str.Append(certificate.Thumbprint); } internal static void AppendIdentityName(StringBuilder str, IIdentity identity) { string name = null; try { name = identity.Name; } #pragma warning suppress 56500 catch (Exception e) { if (Fx.IsFatal(e)) { throw; } // suppress exception, this is just info. } str.Append(String.IsNullOrEmpty(name) ? "" : name); WindowsIdentity windows = identity as WindowsIdentity; if (windows != null) { if (windows.User != null) { str.Append("; "); str.Append(windows.User.ToString()); } } else { WindowsSidIdentity sid = identity as WindowsSidIdentity; if (sid != null) { str.Append("; "); str.Append(sid.SecurityIdentifier.ToString()); } } } [Fx.Tag.SecurityNote(Critical = "Calls critical methods UnsafeGetDomain, UnsafeGetUserName, UnsafeGetPassword and UnsafeGetCurrentUserSidAsString.")] [SecurityCritical] internal static string AppendWindowsAuthenticationInfo(string inputString, NetworkCredential credential, AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel) { const string delimiter = "\0"; // nonprintable characters are invalid for SSPI Domain/UserName/Password if (IsDefaultNetworkCredential(credential)) { string sid = UnsafeGetCurrentUserSidAsString(); return string.Concat(inputString, delimiter, sid, delimiter, AuthenticationLevelHelper.ToString(authenticationLevel), delimiter, TokenImpersonationLevelHelper.ToString(impersonationLevel)); } else { return string.Concat(inputString, delimiter, NetworkCredentialHelper.UnsafeGetDomain(credential), delimiter, NetworkCredentialHelper.UnsafeGetUsername(credential), delimiter, NetworkCredentialHelper.UnsafeGetPassword(credential), delimiter, AuthenticationLevelHelper.ToString(authenticationLevel), delimiter, TokenImpersonationLevelHelper.ToString(impersonationLevel)); } } internal static string GetIdentityName(IIdentity identity) { StringBuilder str = new StringBuilder(256); AppendIdentityName(str, identity); return str.ToString(); } /// /// Critical - Calls an UnsafeNativeMethod and a Critical method (GetFipsAlgorithmPolicyKeyFromRegistry) /// Safe - processes the return and just returns a bool, which is safe /// internal static bool IsChannelBindingDisabled { [SecuritySafeCritical] get { return ((GetSuppressChannelBindingValue() & 0x1) != 0); } } const string suppressChannelBindingRegistryKey = @"System\CurrentControlSet\Control\Lsa"; /// /// Critical - Asserts to get a value from the registry /// [SecurityCritical] [RegistryPermission(SecurityAction.Assert, Read = @"HKEY_LOCAL_MACHINE\" + suppressChannelBindingRegistryKey)] internal static int GetSuppressChannelBindingValue() { int channelBindingPolicyKeyValue = 0; try { using (RegistryKey channelBindingPolicyKey = Registry.LocalMachine.OpenSubKey(suppressChannelBindingRegistryKey, false)) { if (channelBindingPolicyKey != null) { object data = channelBindingPolicyKey.GetValue("SuppressChannelBindingInfo"); if (data != null) channelBindingPolicyKeyValue = (int)data; } } } #pragma warning suppress 56500 catch (Exception e) { if (Fx.IsFatal(e)) throw; } return channelBindingPolicyKeyValue; } internal static bool IsSecurityBindingSuitableForChannelBinding(TransportSecurityBindingElement securityBindingElement) { if (securityBindingElement == null) { return false; } // channel binding of OperationSupportingTokenParameters, OptionalEndpointSupportingTokenParameters, or OptionalOperationSupportingTokenParameters // is not supported in Win7 if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.Endorsing)) { return true; } if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.Signed)) { return true; } if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted)) { return true; } if (AreSecurityTokenParametersSuitableForChannelBinding(securityBindingElement.EndpointSupportingTokenParameters.SignedEndorsing)) { return true; } return false; } internal static bool AreSecurityTokenParametersSuitableForChannelBinding(Collection tokenParameters) { if (tokenParameters == null) { return false; } foreach (SecurityTokenParameters stp in tokenParameters) { if (stp is SspiSecurityTokenParameters || stp is KerberosSecurityTokenParameters) { return true; } SecureConversationSecurityTokenParameters scstp = stp as SecureConversationSecurityTokenParameters; if (scstp != null) { return IsSecurityBindingSuitableForChannelBinding(scstp.BootstrapSecurityBindingElement as TransportSecurityBindingElement); } } return false; } internal static void ThrowIfNegotiationFault(Message message, EndpointAddress target) { if (message.IsFault) { MessageFault fault = MessageFault.CreateFault(message, TransportDefaults.MaxSecurityFaultSize); Exception faultException = new FaultException(fault, message.Headers.Action); if (fault.Code != null && fault.Code.IsReceiverFault && fault.Code.SubCode != null) { FaultCode subCode = fault.Code.SubCode; if (subCode.Name == DotNetSecurityStrings.SecurityServerTooBusyFault && subCode.Namespace == DotNetSecurityStrings.Namespace) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServerTooBusyException(SR.GetString(SR.SecurityServerTooBusy, target), faultException)); } else if (subCode.Name == AddressingStrings.EndpointUnavailable && subCode.Namespace == message.Version.Addressing.Namespace) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.SecurityEndpointNotFound, target), faultException)); } } throw TraceUtility.ThrowHelperError(faultException, message); } } internal static bool IsSecurityFault(MessageFault fault, SecurityStandardsManager standardsManager) { if (fault.Code.IsSenderFault) { FaultCode subCode = fault.Code.SubCode; if (subCode != null) { return (subCode.Namespace == standardsManager.SecurityVersion.HeaderNamespace.Value || subCode.Namespace == standardsManager.SecureConversationDriver.Namespace.Value || subCode.Namespace == standardsManager.TrustDriver.Namespace.Value || subCode.Namespace == DotNetSecurityStrings.Namespace); } } return false; } internal static Exception CreateSecurityFaultException(Message unverifiedMessage) { MessageFault fault = MessageFault.CreateFault(unverifiedMessage, TransportDefaults.MaxSecurityFaultSize); return CreateSecurityFaultException(fault); } internal static Exception CreateSecurityFaultException(MessageFault fault) { FaultException faultException = FaultException.CreateFault(fault, typeof(string), typeof(object)); return new MessageSecurityException(SR.GetString(SR.UnsecuredMessageFaultReceived), faultException); } internal static MessageFault CreateSecurityContextNotFoundFault(SecurityStandardsManager standardsManager, string action) { SecureConversationDriver scDriver = standardsManager.SecureConversationDriver; FaultCode subCode = new FaultCode(scDriver.BadContextTokenFaultCode.Value, scDriver.Namespace.Value); FaultReason reason; if (action != null) { reason = new FaultReason(SR.GetString(SR.BadContextTokenOrActionFaultReason, action), CultureInfo.CurrentCulture); } else { reason = new FaultReason(SR.GetString(SR.BadContextTokenFaultReason), CultureInfo.CurrentCulture); } FaultCode senderCode = FaultCode.CreateSenderFaultCode(subCode); return MessageFault.CreateFault(senderCode, reason); } internal static MessageFault CreateSecurityMessageFault(Exception e, SecurityStandardsManager standardsManager) { bool isSecurityError = false; bool isTokenValidationError = false; bool isGenericTokenError = false; FaultException faultException = null; while (e != null) { if (e is SecurityTokenValidationException) { if (e is SecurityContextTokenValidationException) { return CreateSecurityContextNotFoundFault(SecurityStandardsManager.DefaultInstance, null); } isSecurityError = true; isTokenValidationError = true; break; } else if (e is SecurityTokenException) { isSecurityError = true; isGenericTokenError = true; break; } else if (e is MessageSecurityException) { MessageSecurityException ms = (MessageSecurityException)e; if (ms.Fault != null) { return ms.Fault; } isSecurityError = true; } else if (e is FaultException) { faultException = (FaultException)e; break; } e = e.InnerException; } if (!isSecurityError && faultException == null) { return null; } FaultCode subCode; FaultReason reason; SecurityVersion wss = standardsManager.SecurityVersion; if (isTokenValidationError) { subCode = new FaultCode(wss.FailedAuthenticationFaultCode.Value, wss.HeaderNamespace.Value); reason = new FaultReason(SR.GetString(SR.FailedAuthenticationFaultReason), CultureInfo.CurrentCulture); } else if (isGenericTokenError) { subCode = new FaultCode(wss.InvalidSecurityTokenFaultCode.Value, wss.HeaderNamespace.Value); reason = new FaultReason(SR.GetString(SR.InvalidSecurityTokenFaultReason), CultureInfo.CurrentCulture); } else if (faultException != null) { // Only support Code and Reason. No detail or action customization. return MessageFault.CreateFault(faultException.Code, faultException.Reason); } else { subCode = new FaultCode(wss.InvalidSecurityFaultCode.Value, wss.HeaderNamespace.Value); reason = new FaultReason(SR.GetString(SR.InvalidSecurityFaultReason), CultureInfo.CurrentCulture); } FaultCode senderCode = FaultCode.CreateSenderFaultCode(subCode); return MessageFault.CreateFault(senderCode, reason); } internal static bool IsCompositeDuplexBinding(BindingContext context) { return ((context.Binding.Elements.Find() != null) || (context.Binding.Elements.Find() != null)); } // The method checks TransportToken, ProtectionToken and all SupportingTokens to find a // UserNameSecurityToken. If found, it sets the password of the UserNameSecurityToken to null. // Custom UserNameSecurityToken are skipped. internal static void ErasePasswordInUsernameTokenIfPresent(SecurityMessageProperty messageProperty) { if (messageProperty == null) { // Nothing to fix. return; } if (messageProperty.TransportToken != null) { UserNameSecurityToken token = messageProperty.TransportToken.SecurityToken as UserNameSecurityToken; if ((token != null) && !messageProperty.TransportToken.SecurityToken.GetType().IsSubclassOf(typeof(UserNameSecurityToken))) { messageProperty.TransportToken = new SecurityTokenSpecification(new UserNameSecurityToken(token.UserName, null, token.Id), messageProperty.TransportToken.SecurityTokenPolicies); } } if (messageProperty.ProtectionToken != null) { UserNameSecurityToken token = messageProperty.ProtectionToken.SecurityToken as UserNameSecurityToken; if ((token != null) && !messageProperty.ProtectionToken.SecurityToken.GetType().IsSubclassOf(typeof(UserNameSecurityToken))) { messageProperty.ProtectionToken = new SecurityTokenSpecification(new UserNameSecurityToken(token.UserName, null, token.Id), messageProperty.ProtectionToken.SecurityTokenPolicies); } } if (messageProperty.HasIncomingSupportingTokens) { for (int i = 0; i < messageProperty.IncomingSupportingTokens.Count; ++i) { SupportingTokenSpecification supportingTokenSpecification = messageProperty.IncomingSupportingTokens[i]; UserNameSecurityToken token = supportingTokenSpecification.SecurityToken as UserNameSecurityToken; if ((token != null) && !supportingTokenSpecification.SecurityToken.GetType().IsSubclassOf(typeof(UserNameSecurityToken))) { messageProperty.IncomingSupportingTokens[i] = new SupportingTokenSpecification(new UserNameSecurityToken(token.UserName, null, token.Id), supportingTokenSpecification.SecurityTokenPolicies, supportingTokenSpecification.SecurityTokenAttachmentMode, supportingTokenSpecification.SecurityTokenParameters); } } } } // work-around to Windows SE Bug 141614 [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method UnsafeGetPassword to access the credential password without a Demand.", Safe = "Only uses the password to construct a cloned NetworkCredential instance, does not leak password value.")] [SecuritySafeCritical] internal static void FixNetworkCredential(ref NetworkCredential credential) { if (credential == null) { return; } string username = NetworkCredentialHelper.UnsafeGetUsername(credential); string domain = NetworkCredentialHelper.UnsafeGetDomain(credential); if (!string.IsNullOrEmpty(username) && string.IsNullOrEmpty(domain)) { // do the splitting only if there is exactly 1 \ or exactly 1 @ string[] partsWithSlashDelimiter = username.Split('\\'); string[] partsWithAtDelimiter = username.Split('@'); if (partsWithSlashDelimiter.Length == 2 && partsWithAtDelimiter.Length == 1) { if (!string.IsNullOrEmpty(partsWithSlashDelimiter[0]) && !string.IsNullOrEmpty(partsWithSlashDelimiter[1])) { credential = new NetworkCredential(partsWithSlashDelimiter[1], NetworkCredentialHelper.UnsafeGetPassword(credential), partsWithSlashDelimiter[0]); } } else if (partsWithSlashDelimiter.Length == 1 && partsWithAtDelimiter.Length == 2) { if (!string.IsNullOrEmpty(partsWithAtDelimiter[0]) && !string.IsNullOrEmpty(partsWithAtDelimiter[1])) { credential = new NetworkCredential(partsWithAtDelimiter[0], NetworkCredentialHelper.UnsafeGetPassword(credential), partsWithAtDelimiter[1]); } } } } // WORKAROUND, [....], VSWhidbey 561276: The first NetworkCredential must be created in a lock. internal static void PrepareNetworkCredential() { if (dummyNetworkCredential == null) { PrepareNetworkCredentialWorker(); } } // Since this takes a lock, it probably won't be inlined, but the typical case will be. static void PrepareNetworkCredentialWorker() { lock (dummyNetworkCredentialLock) { dummyNetworkCredential = new NetworkCredential("dummy", "dummy"); } } // This is the workaround, Since store.Certificates returns a full collection // of certs in store. These are holding native resources. internal static void ResetAllCertificates(X509Certificate2Collection certificates) { if (certificates != null) { for (int i = 0; i < certificates.Count; ++i) { ResetCertificate(certificates[i]); } } } [Fx.Tag.SecurityNote(Critical = "Calls critical method X509Certificate2.Reset.", Safe = "Per review from CLR security team, this method does nothing unsafe.")] [SecuritySafeCritical] internal static void ResetCertificate(X509Certificate2 certificate) { certificate.Reset(); } internal static bool IsDefaultNetworkCredential(NetworkCredential credential) { return NetworkCredentialHelper.IsDefault(credential); } internal static void OpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout) { OpenCommunicationObject(tokenProvider as ICommunicationObject, timeout); } internal static IAsyncResult BeginOpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout, AsyncCallback callback, object state) { return new OpenCommunicationObjectAsyncResult(tokenProvider, timeout, callback, state); } internal static void EndOpenTokenProviderIfRequired(IAsyncResult result) { OpenCommunicationObjectAsyncResult.End(result); } internal static IAsyncResult BeginCloseTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout, AsyncCallback callback, object state) { return new CloseCommunicationObjectAsyncResult(tokenProvider, timeout, callback, state); } internal static void EndCloseTokenProviderIfRequired(IAsyncResult result) { CloseCommunicationObjectAsyncResult.End(result); } internal static void CloseTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout) { CloseCommunicationObject(tokenProvider, false, timeout); } internal static void CloseTokenProviderIfRequired(SecurityTokenProvider tokenProvider, bool aborted, TimeSpan timeout) { CloseCommunicationObject(tokenProvider, aborted, timeout); } internal static void AbortTokenProviderIfRequired(SecurityTokenProvider tokenProvider) { CloseCommunicationObject(tokenProvider, true, TimeSpan.Zero); } internal static void OpenTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout) { OpenCommunicationObject(tokenAuthenticator as ICommunicationObject, timeout); } internal static void CloseTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout) { CloseTokenAuthenticatorIfRequired(tokenAuthenticator, false, timeout); } internal static void CloseTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, bool aborted, TimeSpan timeout) { CloseCommunicationObject(tokenAuthenticator, aborted, timeout); } internal static IAsyncResult BeginOpenTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout, AsyncCallback callback, object state) { return new OpenCommunicationObjectAsyncResult(tokenAuthenticator, timeout, callback, state); } internal static void EndOpenTokenAuthenticatorIfRequired(IAsyncResult result) { OpenCommunicationObjectAsyncResult.End(result); } internal static IAsyncResult BeginCloseTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator, TimeSpan timeout, AsyncCallback callback, object state) { return new CloseCommunicationObjectAsyncResult(tokenAuthenticator, timeout, callback, state); } internal static void EndCloseTokenAuthenticatorIfRequired(IAsyncResult result) { CloseCommunicationObjectAsyncResult.End(result); } internal static void AbortTokenAuthenticatorIfRequired(SecurityTokenAuthenticator tokenAuthenticator) { CloseCommunicationObject(tokenAuthenticator, true, TimeSpan.Zero); } static void OpenCommunicationObject(ICommunicationObject obj, TimeSpan timeout) { if (obj != null) obj.Open(timeout); } static void CloseCommunicationObject(Object obj, bool aborted, TimeSpan timeout) { if (obj != null) { ICommunicationObject co = obj as ICommunicationObject; if (co != null) { if (aborted) { try { co.Abort(); } catch (CommunicationException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); } } else { co.Close(timeout); } } else if (obj is IDisposable) { ((IDisposable)obj).Dispose(); } } } class OpenCommunicationObjectAsyncResult : AsyncResult { ICommunicationObject communicationObject; static AsyncCallback onOpen; public OpenCommunicationObjectAsyncResult(object obj, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.communicationObject = obj as ICommunicationObject; bool completeSelf = false; if (this.communicationObject == null) { completeSelf = true; } else { if (onOpen == null) { onOpen = Fx.ThunkCallback(new AsyncCallback(OnOpen)); } IAsyncResult result = this.communicationObject.BeginOpen(timeout, onOpen, this); if (result.CompletedSynchronously) { this.communicationObject.EndOpen(result); completeSelf = true; } } if (completeSelf) { base.Complete(true); } } public static void End(IAsyncResult result) { AsyncResult.End(result); } static void OnOpen(IAsyncResult result) { if (result.CompletedSynchronously) { return; } OpenCommunicationObjectAsyncResult thisPtr = (OpenCommunicationObjectAsyncResult)result.AsyncState; Exception completionException = null; try { thisPtr.communicationObject.EndOpen(result); } #pragma warning suppress 56500 // [....], transferring exception to another thread catch (Exception e) { if (Fx.IsFatal(e)) { throw; } completionException = e; } thisPtr.Complete(false, completionException); } } class CloseCommunicationObjectAsyncResult : AsyncResult { ICommunicationObject communicationObject; static AsyncCallback onClose; public CloseCommunicationObjectAsyncResult(object obj, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.communicationObject = obj as ICommunicationObject; bool completeSelf = false; if (this.communicationObject == null) { IDisposable disposable = obj as IDisposable; if (disposable != null) { disposable.Dispose(); } completeSelf = true; } else { if (onClose == null) { onClose = Fx.ThunkCallback(new AsyncCallback(OnClose)); } IAsyncResult result = this.communicationObject.BeginClose(timeout, onClose, this); if (result.CompletedSynchronously) { this.communicationObject.EndClose(result); completeSelf = true; } } if (completeSelf) { base.Complete(true); } } public static void End(IAsyncResult result) { AsyncResult.End(result); } static void OnClose(IAsyncResult result) { if (result.CompletedSynchronously) { return; } CloseCommunicationObjectAsyncResult thisPtr = (CloseCommunicationObjectAsyncResult)result.AsyncState; Exception completionException = null; try { thisPtr.communicationObject.EndClose(result); } #pragma warning suppress 56500 // [....], transferring exception to another thread catch (Exception e) { if (Fx.IsFatal(e)) { throw; } completionException = e; } thisPtr.Complete(false, completionException); } } internal static void MatchRstWithEndpointFilter(Message rst, IMessageFilterTable endpointFilterTable, Uri listenUri) { if (endpointFilterTable == null) { return; } Collection result = new Collection(); if (!endpointFilterTable.GetMatchingValues(rst, result)) { throw TraceUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.RequestSecurityTokenDoesNotMatchEndpointFilters, listenUri)), rst); } } // match the RST with the endpoint filters in case there is at least 1 asymmetric signature in the message internal static bool ShouldMatchRstWithEndpointFilter(SecurityBindingElement sbe) { foreach (SecurityTokenParameters parameters in new SecurityTokenParametersEnumerable(sbe, true)) { if (parameters.HasAsymmetricKey) { return true; } } return false; } internal static SecurityStandardsManager CreateSecurityStandardsManager(MessageSecurityVersion securityVersion, SecurityTokenManager tokenManager) { SecurityTokenSerializer tokenSerializer = tokenManager.CreateSecurityTokenSerializer(securityVersion.SecurityTokenVersion); return new SecurityStandardsManager(securityVersion, tokenSerializer); } internal static SecurityStandardsManager CreateSecurityStandardsManager(SecurityTokenRequirement requirement, SecurityTokenManager tokenManager) { MessageSecurityTokenVersion securityVersion = (MessageSecurityTokenVersion)requirement.GetProperty(ServiceModelSecurityTokenRequirement.MessageSecurityVersionProperty); if (securityVersion == MessageSecurityTokenVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005BasicSecurityProfile10) return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, tokenManager); else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005) return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11, tokenManager); else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005BasicSecurityProfile10) return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, tokenManager); else if (securityVersion == MessageSecurityTokenVersion.WSSecurity10WSTrust13WSSecureConversation13BasicSecurityProfile10) return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10, tokenManager); else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrust13WSSecureConversation13) return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12, tokenManager); else if (securityVersion == MessageSecurityTokenVersion.WSSecurity11WSTrust13WSSecureConversation13BasicSecurityProfile10) return CreateSecurityStandardsManager(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10, tokenManager); else throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } internal static SecurityStandardsManager CreateSecurityStandardsManager(MessageSecurityVersion securityVersion, SecurityTokenSerializer securityTokenSerializer) { if (securityVersion == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("securityVersion")); } if (securityTokenSerializer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenSerializer"); } return new SecurityStandardsManager(securityVersion, securityTokenSerializer); } static bool TryCreateIdentity(ClaimSet claimSet, string claimType, out EndpointIdentity identity) { identity = null; foreach (Claim claim in claimSet.FindClaims(claimType, null)) { identity = EndpointIdentity.CreateIdentity(claim); return true; } return false; } internal static EndpointIdentity GetServiceCertificateIdentity(X509Certificate2 certificate) { using (X509CertificateClaimSet claimSet = new X509CertificateClaimSet(certificate)) { EndpointIdentity identity; if (!TryCreateIdentity(claimSet, ClaimTypes.Dns, out identity)) { TryCreateIdentity(claimSet, ClaimTypes.Rsa, out identity); } return identity; } } [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method UnsafeGetPassword to access the credential password without a Demand.", Safe = "Only uses the password to construct a new NetworkCredential which will then protect access, password does not leak from this method.")] [SecuritySafeCritical] internal static NetworkCredential GetNetworkCredentialsCopy(NetworkCredential networkCredential) { NetworkCredential result; if (networkCredential != null && !NetworkCredentialHelper.IsDefault(networkCredential)) { result = new NetworkCredential(NetworkCredentialHelper.UnsafeGetUsername(networkCredential), NetworkCredentialHelper.UnsafeGetPassword(networkCredential), NetworkCredentialHelper.UnsafeGetDomain(networkCredential)); } else { result = networkCredential; } return result; } internal static NetworkCredential GetNetworkCredentialOrDefault(NetworkCredential credential) { // because of VSW 564452, we dont use CredentialCache.DefaultNetworkCredentials in our OM. Instead we // use an empty NetworkCredential to denote the default credentials if (NetworkCredentialHelper.IsNullOrEmpty(credential)) { // FYI: this will fail with SecurityException in PT due to Demand for EnvironmentPermission. // Typically a PT app should not have access to DefaultNetworkCredentials. If there is a valid reason, // see UnsafeGetDefaultNetworkCredentials. return CredentialCache.DefaultNetworkCredentials; } else { return credential; } } static class NetworkCredentialHelper { [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical methods UnsafeGetUsername, UnsafeGetPassword, and UnsafeGetDomain to access the credential details without a Demand.", Safe = "Only uses the protected values to test for null/empty. Does not leak.")] [SecuritySafeCritical] static internal bool IsNullOrEmpty(NetworkCredential credential) { return credential == null || ( String.IsNullOrEmpty(UnsafeGetUsername(credential)) && String.IsNullOrEmpty(UnsafeGetDomain(credential)) && String.IsNullOrEmpty(UnsafeGetPassword(credential)) ); } [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical method UnsafeGetDefaultNetworkCredentials to access the default network credentials without a Demand.", Safe = "Only uses the default credentials to test for equality and uses the system credential's .Equals, not the caller's.")] [SecuritySafeCritical] static internal bool IsDefault(NetworkCredential credential) { return UnsafeGetDefaultNetworkCredentials().Equals(credential); } [Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission(UnmanagedCode) in order to get the NetworkCredential password." + "This is used for example to test for empty/null or to construct a cloned NetworkCredential." + "Callers absolutely must not leak the return value.")] [SecurityCritical] [EnvironmentPermission(SecurityAction.Assert, Read = "USERNAME")] static internal string UnsafeGetUsername(NetworkCredential credential) { return credential.UserName; } [Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission(UnmanagedCode) in order to get the NetworkCredential password." + "This is used for example to test for empty/null or to construct a cloned NetworkCredential." + "Callers absolutely must not leak the return value.")] [SecurityCritical] [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] static internal string UnsafeGetPassword(NetworkCredential credential) { return credential.Password; } [Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission(UnmanagedCode) in order to get the NetworkCredential password." + "This is used for example to test for empty/null or to construct a cloned NetworkCredential." + "Callers absolutely must not leak the return value.")] [SecurityCritical] [EnvironmentPermission(SecurityAction.Assert, Read = "USERDOMAIN")] static internal string UnsafeGetDomain(NetworkCredential credential) { return credential.Domain; } [Fx.Tag.SecurityNote(Critical = "Asserts EnvironmentPermission(Read='USERNAME') in order to get the DefaultNetworkCredentials in PT." + "This is used for example to test for instance equality with a specific NetworkCredential." + "Callers absolutely must not leak the return value.")] [SecurityCritical] [EnvironmentPermission(SecurityAction.Assert, Read = "USERNAME")] static NetworkCredential UnsafeGetDefaultNetworkCredentials() { return CredentialCache.DefaultNetworkCredentials; } } internal static SafeFreeCredentials GetCredentialsHandle(string package, NetworkCredential credential, bool isServer, params string[] additionalPackages) { SafeFreeCredentials credentialsHandle; CredentialUse credentialUse = isServer ? CredentialUse.Inbound : CredentialUse.Outbound; if (credential == null || NetworkCredentialHelper.IsDefault(credential)) { AuthIdentityEx authIdentity = new AuthIdentityEx(null, null, null, additionalPackages); credentialsHandle = SspiWrapper.AcquireCredentialsHandle(package, credentialUse, ref authIdentity); } else { SecurityUtils.FixNetworkCredential(ref credential); // we're not using DefaultCredentials, we need a // AuthIdentity struct to contain credentials AuthIdentityEx authIdentity = new AuthIdentityEx(credential.UserName, credential.Password, credential.Domain); credentialsHandle = SspiWrapper.AcquireCredentialsHandle(package, credentialUse, ref authIdentity); } return credentialsHandle; } internal static SafeFreeCredentials GetCredentialsHandle(Binding binding, KeyedByTypeCollection behaviors) { ClientCredentials clientCredentials = (behaviors == null) ? null : behaviors.Find(); return GetCredentialsHandle(binding, clientCredentials); } internal static SafeFreeCredentials GetCredentialsHandle(Binding binding, ClientCredentials clientCredentials) { SecurityBindingElement sbe = (binding == null) ? null : binding.CreateBindingElements().Find(); return GetCredentialsHandle(sbe, clientCredentials); } internal static SafeFreeCredentials GetCredentialsHandle(SecurityBindingElement sbe, BindingContext context) { ClientCredentials clientCredentials = (context == null) ? null : context.BindingParameters.Find(); return GetCredentialsHandle(sbe, clientCredentials); } internal static SafeFreeCredentials GetCredentialsHandle(SecurityBindingElement sbe, ClientCredentials clientCredentials) { if (sbe == null) { return null; } bool isSspi = false; bool isKerberos = false; foreach (SecurityTokenParameters stp in new SecurityTokenParametersEnumerable(sbe, true)) { if (stp is SecureConversationSecurityTokenParameters) { SafeFreeCredentials result = GetCredentialsHandle(((SecureConversationSecurityTokenParameters)stp).BootstrapSecurityBindingElement, clientCredentials); if (result != null) { return result; } continue; } else if (stp is IssuedSecurityTokenParameters) { SafeFreeCredentials result = GetCredentialsHandle(((IssuedSecurityTokenParameters)stp).IssuerBinding, clientCredentials); if (result != null) { return result; } continue; } else if (stp is SspiSecurityTokenParameters) { isSspi = true; break; } else if (stp is KerberosSecurityTokenParameters) { isKerberos = true; break; } } if (!isSspi && !isKerberos) { return null; } NetworkCredential credential = null; if (clientCredentials != null) { credential = SecurityUtils.GetNetworkCredentialOrDefault(clientCredentials.Windows.ClientCredential); } if (isKerberos) { return SecurityUtils.GetCredentialsHandle("Kerberos", credential, false); } // if OS is less that Vista cannot use !NTLM, Windows SE 142400 // To disable AllowNtlm warning. #pragma warning disable 618 else if (clientCredentials != null && !clientCredentials.Windows.AllowNtlm) { if (SecurityUtils.IsOsGreaterThanXP()) { return SecurityUtils.GetCredentialsHandle("Negotiate", credential, false, "!NTLM"); } else { return SecurityUtils.GetCredentialsHandle("Kerberos", credential, false); } } #pragma warning restore 618 return SecurityUtils.GetCredentialsHandle("Negotiate", credential, false); } internal static byte[] CloneBuffer(byte[] buffer) { byte[] copy = DiagnosticUtility.Utility.AllocateByteArray(buffer.Length); Buffer.BlockCopy(buffer, 0, copy, 0, buffer.Length); return copy; } internal static X509Certificate2 GetCertificateFromStore(StoreName storeName, StoreLocation storeLocation, X509FindType findType, object findValue, EndpointAddress target) { X509Certificate2 certificate = GetCertificateFromStoreCore(storeName, storeLocation, findType, findValue, target, true); if (certificate == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotFindCert, storeName, storeLocation, findType, findValue))); return certificate; } internal static bool TryGetCertificateFromStore(StoreName storeName, StoreLocation storeLocation, X509FindType findType, object findValue, EndpointAddress target, out X509Certificate2 certificate) { certificate = GetCertificateFromStoreCore(storeName, storeLocation, findType, findValue, target, false); return (certificate != null); } static X509Certificate2 GetCertificateFromStoreCore(StoreName storeName, StoreLocation storeLocation, X509FindType findType, object findValue, EndpointAddress target, bool throwIfMultipleOrNoMatch) { if (findValue == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("findValue"); } X509CertificateStore store = new X509CertificateStore(storeName, storeLocation); X509Certificate2Collection certs = null; try { store.Open(OpenFlags.ReadOnly); certs = store.Find(findType, findValue, false); if (certs.Count == 1) { return new X509Certificate2(certs[0]); } if (throwIfMultipleOrNoMatch) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateCertificateLoadException( storeName, storeLocation, findType, findValue, target, certs.Count)); } else { return null; } } finally { SecurityUtils.ResetAllCertificates(certs); store.Close(); } } static Exception CreateCertificateLoadException(StoreName storeName, StoreLocation storeLocation, X509FindType findType, object findValue, EndpointAddress target, int certCount) { if (certCount == 0) { if (target == null) { return new InvalidOperationException(SR.GetString(SR.CannotFindCert, storeName, storeLocation, findType, findValue)); } else { return new InvalidOperationException(SR.GetString(SR.CannotFindCertForTarget, storeName, storeLocation, findType, findValue, target)); } } else { if (target == null) { return new InvalidOperationException(SR.GetString(SR.FoundMultipleCerts, storeName, storeLocation, findType, findValue)); } else { return new InvalidOperationException(SR.GetString(SR.FoundMultipleCertsForTarget, storeName, storeLocation, findType, findValue, target)); } } } public static SecurityBindingElement GetIssuerSecurityBindingElement(ServiceModelSecurityTokenRequirement requirement) { SecurityBindingElement bindingElement = requirement.SecureConversationSecurityBindingElement; if (bindingElement != null) { return bindingElement; } Binding binding = requirement.IssuerBinding; if (binding == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.IssuerBindingNotPresentInTokenRequirement, requirement)); } BindingElementCollection bindingElements = binding.CreateBindingElements(); return bindingElements.Find(); } public static int GetMaxNegotiationBufferSize(BindingContext bindingContext) { TransportBindingElement transport = bindingContext.RemainingBindingElements.Find(); Fx.Assert(transport != null, "TransportBindingElement is null!"); int maxNegoMessageSize; if (transport is ConnectionOrientedTransportBindingElement) { maxNegoMessageSize = ((ConnectionOrientedTransportBindingElement)transport).MaxBufferSize; } else if (transport is HttpTransportBindingElement) { maxNegoMessageSize = ((HttpTransportBindingElement)transport).MaxBufferSize; } else { maxNegoMessageSize = TransportDefaults.MaxBufferSize; } return maxNegoMessageSize; } public static bool TryCreateKeyFromIntrinsicKeyClause(SecurityKeyIdentifierClause keyIdentifierClause, SecurityTokenResolver resolver, out SecurityKey key) { key = null; if (keyIdentifierClause.CanCreateKey) { key = keyIdentifierClause.CreateKey(); return true; } if (keyIdentifierClause is EncryptedKeyIdentifierClause) { EncryptedKeyIdentifierClause keyClause = (EncryptedKeyIdentifierClause)keyIdentifierClause; // PreSharp Bug: Parameter 'keyClause' to this public method must be validated: A null-dereference can occur here. #pragma warning suppress 56506 // keyClause will not be null due to the if condition above. for (int i = 0; i < keyClause.EncryptingKeyIdentifier.Count; i++) { SecurityKey unwrappingSecurityKey = null; if (resolver.TryResolveSecurityKey(keyClause.EncryptingKeyIdentifier[i], out unwrappingSecurityKey)) { byte[] wrappedKey = keyClause.GetEncryptedKey(); string wrappingAlgorithm = keyClause.EncryptionMethod; byte[] unwrappedKey = unwrappingSecurityKey.DecryptKey(wrappingAlgorithm, wrappedKey); key = new InMemorySymmetricSecurityKey(unwrappedKey, false); return true; } } } return false; } public static WrappedKeySecurityToken CreateTokenFromEncryptedKeyClause(EncryptedKeyIdentifierClause keyClause, SecurityToken unwrappingToken) { SecurityKeyIdentifier wrappingTokenReference = keyClause.EncryptingKeyIdentifier; byte[] wrappedKey = keyClause.GetEncryptedKey(); SecurityKey unwrappingSecurityKey = unwrappingToken.SecurityKeys[0]; string wrappingAlgorithm = keyClause.EncryptionMethod; byte[] unwrappedKey = unwrappingSecurityKey.DecryptKey(wrappingAlgorithm, wrappedKey); return new WrappedKeySecurityToken(SecurityUtils.GenerateId(), unwrappedKey, wrappingAlgorithm, unwrappingToken, wrappingTokenReference, wrappedKey, unwrappingSecurityKey ); } public static void ValidateAnonymityConstraint(WindowsIdentity identity, bool allowUnauthenticatedCallers) { if (!allowUnauthenticatedCallers && identity.User.IsWellKnown(WellKnownSidType.AnonymousSid)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning( new SecurityTokenValidationException(SR.GetString(SR.AnonymousLogonsAreNotAllowed))); } } static bool ComputeSslCipherStrengthRequirementFlag() { // validate only for XP versions < XP SP3 and windows server versions < Win2K3 SP2 if ((Environment.OSVersion.Version.Major > WindowsServerMajorNumber) || (Environment.OSVersion.Version.Major == WindowsServerMajorNumber && Environment.OSVersion.Version.Minor > WindowsServerMinorNumber)) { return false; } // version <= Win2K3 if (Environment.OSVersion.Version.Major == XPMajorNumber && Environment.OSVersion.Version.Minor == XPMinorNumber) { if ((Environment.OSVersion.ServicePack == string.Empty) || String.Equals(Environment.OSVersion.ServicePack, ServicePack1, StringComparison.OrdinalIgnoreCase) || String.Equals(Environment.OSVersion.ServicePack, ServicePack2, StringComparison.OrdinalIgnoreCase)) { return true; } else { // the OS is XP SP3 or higher return false; } } else if (Environment.OSVersion.Version.Major == WindowsServerMajorNumber && Environment.OSVersion.Version.Minor == WindowsServerMinorNumber) { if (Environment.OSVersion.ServicePack == string.Empty || String.Equals(Environment.OSVersion.ServicePack, ServicePack1, StringComparison.OrdinalIgnoreCase)) { return true; } else { // the OS is Win2K3 SP2 or higher return false; } } else { // this is <= XP. We should never get here but if we do validate SSL strength return true; } } public static bool ShouldValidateSslCipherStrength() { if (!isSslValidationRequirementDetermined) { shouldValidateSslCipherStrength = ComputeSslCipherStrengthRequirementFlag(); Thread.MemoryBarrier(); isSslValidationRequirementDetermined = true; } return shouldValidateSslCipherStrength; } public static void ValidateSslCipherStrength(int keySizeInBits) { if (ShouldValidateSslCipherStrength() && keySizeInBits < MinimumSslCipherStrength) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.SslCipherKeyTooSmall, keySizeInBits, MinimumSslCipherStrength))); } } public static bool TryCreateX509CertificateFromRawData(byte[] rawData, out X509Certificate2 certificate) { certificate = (rawData == null || rawData.Length == 0) ? null : new X509Certificate2(rawData); return certificate != null && certificate.Handle != IntPtr.Zero; } internal static string GetKeyDerivationAlgorithm(SecureConversationVersion version) { string derivationAlgorithm = null; if (version == SecureConversationVersion.WSSecureConversationFeb2005) { derivationAlgorithm = SecurityAlgorithms.Psha1KeyDerivation; } else if (version == SecureConversationVersion.WSSecureConversation13) { derivationAlgorithm = SecurityAlgorithms.Psha1KeyDerivationDec2005; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); } return derivationAlgorithm; } } struct SecurityUniqueId { static long nextId = 0; static string commonPrefix = "uuid-" + Guid.NewGuid().ToString() + "-"; long id; string prefix; string val; SecurityUniqueId(string prefix, long id) { this.id = id; this.prefix = prefix; this.val = null; } public static SecurityUniqueId Create() { return SecurityUniqueId.Create(commonPrefix); } public static SecurityUniqueId Create(string prefix) { return new SecurityUniqueId(prefix, Interlocked.Increment(ref nextId)); } public string Value { get { if (this.val == null) this.val = this.prefix + this.id.ToString(CultureInfo.InvariantCulture); return this.val; } } } static class EmptyReadOnlyCollection { public static ReadOnlyCollection Instance = new ReadOnlyCollection(new List()); } class OperationWithTimeoutAsyncResult : TraceAsyncResult { static readonly Action scheduledCallback = new Action(OnScheduled); TimeoutHelper timeoutHelper; OperationWithTimeoutCallback operationWithTimeout; public OperationWithTimeoutAsyncResult(OperationWithTimeoutCallback operationWithTimeout, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.operationWithTimeout = operationWithTimeout; this.timeoutHelper = new TimeoutHelper(timeout); ActionItem.Schedule(scheduledCallback, this); } static void OnScheduled(object state) { OperationWithTimeoutAsyncResult thisResult = (OperationWithTimeoutAsyncResult)state; Exception completionException = null; try { using (thisResult.CallbackActivity == null ? null : ServiceModelActivity.BoundOperation(thisResult.CallbackActivity)) { thisResult.operationWithTimeout(thisResult.timeoutHelper.RemainingTime()); } } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } completionException = e; } thisResult.Complete(false, completionException); } public static void End(IAsyncResult result) { AsyncResult.End(result); } } }