e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
2394 lines
99 KiB
C#
2394 lines
99 KiB
C#
//------------------------------------------------------------
|
|
// 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<ProtectionLevel> 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<T>(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<SymmetricSecurityKey>(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<SymmetricSecurityKey>(t1);
|
|
SymmetricSecurityKey c2 = SecurityUtils.GetSecurityKey<SymmetricSecurityKey>(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<SymmetricSecurityKey>(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<SymmetricSecurityKey>(token);
|
|
if (securityKey != null && securityKey.IsSupportedAlgorithm(algorithm))
|
|
{
|
|
return securityKey.GetKeyedHashAlgorithm(algorithm);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal static ReadOnlyCollection<SecurityKey> CreateSymmetricSecurityKeys(byte[] key)
|
|
{
|
|
List<SecurityKey> temp = new List<SecurityKey>(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<SymmetricSecurityKey>(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<IAuthorizationPolicy> 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<IAuthorizationPolicy> 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<Claim> claims = new List<Claim>(2);
|
|
claims.Add(identityClaim);
|
|
claims.Add(primaryPrincipal);
|
|
|
|
List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
|
|
policies.Add(new UnconditionalPolicy(SecurityUtils.CreateIdentity(principalName), new DefaultClaimSet(ClaimSet.Anonymous, claims)));
|
|
return policies.AsReadOnly();
|
|
}
|
|
|
|
internal static string GetIdentityNamesFromPolicies(IList<IAuthorizationPolicy> 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<IIdentity> identities = null;
|
|
object obj;
|
|
if (authContext.Properties.TryGetValue(SecurityUtils.Identities, out obj))
|
|
{
|
|
identities = obj as List<IIdentity>;
|
|
}
|
|
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) ? "<x509>" : 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) ? "<null>" : 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();
|
|
}
|
|
|
|
/// <SecurityNote>
|
|
/// Critical - Calls an UnsafeNativeMethod and a Critical method (GetFipsAlgorithmPolicyKeyFromRegistry)
|
|
/// Safe - processes the return and just returns a bool, which is safe
|
|
/// </SecurityNote>
|
|
internal static bool IsChannelBindingDisabled
|
|
{
|
|
[SecuritySafeCritical]
|
|
get
|
|
{
|
|
return ((GetSuppressChannelBindingValue() & 0x1) != 0);
|
|
}
|
|
}
|
|
|
|
const string suppressChannelBindingRegistryKey = @"System\CurrentControlSet\Control\Lsa";
|
|
|
|
/// <SecurityNote>
|
|
/// Critical - Asserts to get a value from the registry
|
|
/// </SecurityNote>
|
|
[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<SecurityTokenParameters> 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<CompositeDuplexBindingElement>() != null)
|
|
|| (context.Binding.Elements.Find<InternalDuplexBindingElement>() != 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<OpenCommunicationObjectAsyncResult>(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<CloseCommunicationObjectAsyncResult>(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<EndpointAddress> endpointFilterTable, Uri listenUri)
|
|
{
|
|
if (endpointFilterTable == null)
|
|
{
|
|
return;
|
|
}
|
|
Collection<EndpointAddress> result = new Collection<EndpointAddress>();
|
|
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<MessageSecurityTokenVersion>(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<IEndpointBehavior> behaviors)
|
|
{
|
|
ClientCredentials clientCredentials = (behaviors == null) ? null : behaviors.Find<ClientCredentials>();
|
|
return GetCredentialsHandle(binding, clientCredentials);
|
|
}
|
|
|
|
internal static SafeFreeCredentials GetCredentialsHandle(Binding binding, ClientCredentials clientCredentials)
|
|
{
|
|
SecurityBindingElement sbe = (binding == null) ? null : binding.CreateBindingElements().Find<SecurityBindingElement>();
|
|
return GetCredentialsHandle(sbe, clientCredentials);
|
|
}
|
|
|
|
internal static SafeFreeCredentials GetCredentialsHandle(SecurityBindingElement sbe, BindingContext context)
|
|
{
|
|
ClientCredentials clientCredentials = (context == null) ? null : context.BindingParameters.Find<ClientCredentials>();
|
|
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<SecurityBindingElement>();
|
|
}
|
|
|
|
public static int GetMaxNegotiationBufferSize(BindingContext bindingContext)
|
|
{
|
|
TransportBindingElement transport = bindingContext.RemainingBindingElements.Find<TransportBindingElement>();
|
|
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<T>
|
|
{
|
|
public static ReadOnlyCollection<T> Instance = new ReadOnlyCollection<T>(new List<T>());
|
|
}
|
|
|
|
class OperationWithTimeoutAsyncResult : TraceAsyncResult
|
|
{
|
|
static readonly Action<object> scheduledCallback = new Action<object>(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<OperationWithTimeoutAsyncResult>(result);
|
|
}
|
|
}
|
|
}
|