e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
648 lines
25 KiB
C#
648 lines
25 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Security
|
|
{
|
|
using System.Runtime.InteropServices;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.Diagnostics;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Globalization;
|
|
using System.ComponentModel;
|
|
using System.Security.Principal;
|
|
using System.IdentityModel.Tokens;
|
|
using System.Net;
|
|
using System.IdentityModel;
|
|
using System.IdentityModel.Selectors;
|
|
using System.Security.Authentication.ExtendedProtection;
|
|
using IMD = System.IdentityModel.Diagnostics;
|
|
|
|
using DiagnosticUtility = System.ServiceModel.DiagnosticUtility;
|
|
using SR = System.ServiceModel.SR;
|
|
|
|
internal sealed class WindowsSspiNegotiation : ISspiNegotiation
|
|
{
|
|
const int DefaultMaxPromptAttempts = 1;
|
|
SspiContextFlags contextFlags;
|
|
SafeFreeCredentials credentialsHandle;
|
|
bool disposed = false;
|
|
bool doMutualAuth;
|
|
TokenImpersonationLevel impersonationLevel;
|
|
bool isCompleted;
|
|
bool isServer;
|
|
LifeSpan lifespan;
|
|
string protocolName;
|
|
SafeDeleteContext securityContext;
|
|
string servicePrincipalName;
|
|
SecSizes sizes;
|
|
Object syncObject = new Object();
|
|
int tokenSize;
|
|
bool interactiveNegoLogonEnabled = true;
|
|
string clientPackageName;
|
|
bool saveClientCredentialsOnSspiUi = true;
|
|
bool allowNtlm;
|
|
int MaxPromptAttempts = 0;
|
|
|
|
/// <summary>
|
|
/// Client side ctor
|
|
/// </summary>
|
|
internal WindowsSspiNegotiation(string package, SafeFreeCredentials credentialsHandle, TokenImpersonationLevel impersonationLevel, string servicePrincipalName, bool doMutualAuth, bool interactiveLogonEnabled, bool ntlmEnabled)
|
|
: this(false, package, credentialsHandle, impersonationLevel, servicePrincipalName, doMutualAuth, interactiveLogonEnabled, ntlmEnabled)
|
|
{ }
|
|
|
|
/// <summary>
|
|
/// Server side ctor
|
|
/// </summary>
|
|
internal WindowsSspiNegotiation(string package, SafeFreeCredentials credentialsHandle, string defaultServiceBinding)
|
|
: this(true, package, credentialsHandle, TokenImpersonationLevel.Delegation, defaultServiceBinding, false, false, true)
|
|
{ }
|
|
|
|
WindowsSspiNegotiation(bool isServer, string package, SafeFreeCredentials credentialsHandle, TokenImpersonationLevel impersonationLevel, string servicePrincipalName, bool doMutualAuth, bool interactiveLogonEnabled, bool ntlmEnabled)
|
|
{
|
|
this.tokenSize = SspiWrapper.GetVerifyPackageInfo(package).MaxToken;
|
|
this.isServer = isServer;
|
|
this.servicePrincipalName = servicePrincipalName;
|
|
this.securityContext = null;
|
|
if (isServer)
|
|
{
|
|
this.impersonationLevel = TokenImpersonationLevel.Delegation;
|
|
this.doMutualAuth = false;
|
|
}
|
|
else
|
|
{
|
|
this.impersonationLevel = impersonationLevel;
|
|
this.doMutualAuth = doMutualAuth;
|
|
this.interactiveNegoLogonEnabled = interactiveLogonEnabled;
|
|
this.clientPackageName = package;
|
|
this.allowNtlm = ntlmEnabled;
|
|
}
|
|
this.credentialsHandle = credentialsHandle;
|
|
}
|
|
|
|
public DateTime ExpirationTimeUtc
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
if (this.LifeSpan == null)
|
|
{
|
|
return SecurityUtils.MaxUtcDateTime;
|
|
}
|
|
else
|
|
{
|
|
return this.LifeSpan.ExpiryTimeUtc;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsCompleted
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
return this.isCompleted;
|
|
}
|
|
}
|
|
|
|
public bool IsDelegationFlag
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
return (this.contextFlags & SspiContextFlags.Delegate) != 0;
|
|
}
|
|
}
|
|
|
|
public bool IsIdentifyFlag
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
return (this.contextFlags & (this.isServer ? SspiContextFlags.AcceptIdentify : SspiContextFlags.InitIdentify)) != 0;
|
|
}
|
|
}
|
|
|
|
public bool IsMutualAuthFlag
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
return (this.contextFlags & SspiContextFlags.MutualAuth) != 0;
|
|
}
|
|
}
|
|
|
|
public bool IsValidContext
|
|
{
|
|
get
|
|
{
|
|
return (this.securityContext != null && this.securityContext.IsInvalid == false);
|
|
}
|
|
}
|
|
|
|
public string KeyEncryptionAlgorithm
|
|
{
|
|
get
|
|
{
|
|
return SecurityAlgorithms.WindowsSspiKeyWrap;
|
|
}
|
|
}
|
|
|
|
public LifeSpan LifeSpan
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
if (this.lifespan == null)
|
|
{
|
|
LifeSpan tmpLifeSpan = (LifeSpan)SspiWrapper.QueryContextAttributes(this.securityContext, ContextAttribute.Lifespan);
|
|
|
|
if (IsCompleted)
|
|
{
|
|
// cache it only when it's completed
|
|
this.lifespan = tmpLifeSpan;
|
|
}
|
|
|
|
return tmpLifeSpan;
|
|
}
|
|
|
|
return this.lifespan;
|
|
}
|
|
}
|
|
|
|
public string ProtocolName
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
if (this.protocolName == null)
|
|
{
|
|
NegotiationInfoClass negotiationInfo = SspiWrapper.QueryContextAttributes(this.securityContext, ContextAttribute.NegotiationInfo) as NegotiationInfoClass;
|
|
|
|
if (IsCompleted)
|
|
{
|
|
// cache it only when it's completed
|
|
this.protocolName = negotiationInfo.AuthenticationPackage;
|
|
}
|
|
|
|
return negotiationInfo.AuthenticationPackage;
|
|
}
|
|
|
|
return this.protocolName;
|
|
}
|
|
}
|
|
|
|
public string ServicePrincipalName
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
return this.servicePrincipalName;
|
|
}
|
|
}
|
|
|
|
SecSizes SecuritySizes
|
|
{
|
|
get
|
|
{
|
|
ThrowIfDisposed();
|
|
if (this.sizes == null)
|
|
{
|
|
SecSizes tmpSizes = (SecSizes)SspiWrapper.QueryContextAttributes(this.securityContext, ContextAttribute.Sizes);
|
|
|
|
if (IsCompleted)
|
|
{
|
|
// cache it only when it's completed
|
|
this.sizes = tmpSizes;
|
|
}
|
|
|
|
return tmpSizes;
|
|
}
|
|
|
|
return this.sizes;
|
|
}
|
|
}
|
|
|
|
public string GetRemoteIdentityName()
|
|
{
|
|
if (!this.isServer)
|
|
{
|
|
return this.servicePrincipalName;
|
|
}
|
|
|
|
if (IsValidContext)
|
|
{
|
|
using (SafeCloseHandle contextToken = GetContextToken())
|
|
{
|
|
using (WindowsIdentity windowsIdentity = new WindowsIdentity(contextToken.DangerousGetHandle(), this.ProtocolName))
|
|
{
|
|
return windowsIdentity.Name;
|
|
}
|
|
}
|
|
}
|
|
return String.Empty;
|
|
}
|
|
|
|
public byte[] Decrypt(byte[] encryptedContent)
|
|
{
|
|
if (encryptedContent == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encryptedContent");
|
|
ThrowIfDisposed();
|
|
|
|
SecurityBuffer[] securityBuffer = new SecurityBuffer[2];
|
|
securityBuffer[0] = new SecurityBuffer(encryptedContent, 0, encryptedContent.Length, BufferType.Stream);
|
|
securityBuffer[1] = new SecurityBuffer(0, BufferType.Data);
|
|
int errorCode = SspiWrapper.DecryptMessage(this.securityContext, securityBuffer, 0, true);
|
|
if (errorCode != 0)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
|
|
}
|
|
|
|
for (int i = 0; i < securityBuffer.Length; ++i)
|
|
{
|
|
if (securityBuffer[i].type == BufferType.Data)
|
|
{
|
|
return securityBuffer[i].token;
|
|
}
|
|
}
|
|
OnBadData();
|
|
return null;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public byte[] Encrypt(byte[] input)
|
|
{
|
|
if (input == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("input");
|
|
ThrowIfDisposed();
|
|
SecurityBuffer[] securityBuffer = new SecurityBuffer[3];
|
|
|
|
byte[] tokenBuffer = DiagnosticUtility.Utility.AllocateByteArray(SecuritySizes.SecurityTrailer);
|
|
securityBuffer[0] = new SecurityBuffer(tokenBuffer, 0, tokenBuffer.Length, BufferType.Token);
|
|
byte[] dataBuffer = DiagnosticUtility.Utility.AllocateByteArray(input.Length);
|
|
Buffer.BlockCopy(input, 0, dataBuffer, 0, input.Length);
|
|
securityBuffer[1] = new SecurityBuffer(dataBuffer, 0, dataBuffer.Length, BufferType.Data);
|
|
byte[] paddingBuffer = DiagnosticUtility.Utility.AllocateByteArray(SecuritySizes.BlockSize);
|
|
securityBuffer[2] = new SecurityBuffer(paddingBuffer, 0, paddingBuffer.Length, BufferType.Padding);
|
|
|
|
int errorCode = SspiWrapper.EncryptMessage(this.securityContext, securityBuffer, 0);
|
|
if (errorCode != 0)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
|
|
}
|
|
|
|
int tokenLen = 0;
|
|
int paddingLen = 0;
|
|
for (int i = 0; i < securityBuffer.Length; ++i)
|
|
{
|
|
if (securityBuffer[i].type == BufferType.Token)
|
|
tokenLen = securityBuffer[i].size;
|
|
else if (securityBuffer[i].type == BufferType.Padding)
|
|
paddingLen = securityBuffer[i].size;
|
|
}
|
|
byte[] encryptedData = DiagnosticUtility.Utility.AllocateByteArray(checked(tokenLen + dataBuffer.Length + paddingLen));
|
|
|
|
Buffer.BlockCopy(tokenBuffer, 0, encryptedData, 0, tokenLen);
|
|
Buffer.BlockCopy(dataBuffer, 0, encryptedData, tokenLen, dataBuffer.Length);
|
|
Buffer.BlockCopy(paddingBuffer, 0, encryptedData, tokenLen + dataBuffer.Length, paddingLen);
|
|
|
|
return encryptedData;
|
|
}
|
|
|
|
public byte[] GetOutgoingBlob(byte[] incomingBlob, ChannelBinding channelbinding, ExtendedProtectionPolicy protectionPolicy)
|
|
{
|
|
ThrowIfDisposed();
|
|
int statusCode = 0;
|
|
|
|
// use the confidentiality option to ensure we can encrypt messages
|
|
SspiContextFlags requestedFlags = SspiContextFlags.Confidentiality
|
|
| SspiContextFlags.ReplayDetect
|
|
| SspiContextFlags.SequenceDetect;
|
|
|
|
if (this.doMutualAuth)
|
|
{
|
|
requestedFlags |= SspiContextFlags.MutualAuth;
|
|
}
|
|
|
|
if (this.impersonationLevel == TokenImpersonationLevel.Delegation)
|
|
{
|
|
requestedFlags |= SspiContextFlags.Delegate;
|
|
}
|
|
else if (this.isServer == false && this.impersonationLevel == TokenImpersonationLevel.Identification)
|
|
{
|
|
requestedFlags |= SspiContextFlags.InitIdentify;
|
|
}
|
|
else if (this.isServer == false && this.impersonationLevel == TokenImpersonationLevel.Anonymous)
|
|
{
|
|
requestedFlags |= SspiContextFlags.InitAnonymous;
|
|
}
|
|
|
|
ExtendedProtectionPolicyHelper policyHelper = new ExtendedProtectionPolicyHelper(channelbinding, protectionPolicy);
|
|
|
|
if (isServer)
|
|
{
|
|
if (policyHelper.PolicyEnforcement == PolicyEnforcement.Always && policyHelper.ChannelBinding == null && policyHelper.ProtectionScenario != ProtectionScenario.TrustedProxy)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenException(SR.GetString(SR.SecurityChannelBindingMissing)));
|
|
}
|
|
|
|
if (policyHelper.PolicyEnforcement == PolicyEnforcement.WhenSupported)
|
|
{
|
|
requestedFlags |= SspiContextFlags.ChannelBindingAllowMissingBindings;
|
|
}
|
|
|
|
if (policyHelper.ProtectionScenario == ProtectionScenario.TrustedProxy)
|
|
{
|
|
requestedFlags |= SspiContextFlags.ChannelBindingProxyBindings;
|
|
}
|
|
}
|
|
|
|
List<SecurityBuffer> list = new List<SecurityBuffer>(2);
|
|
|
|
if (incomingBlob != null)
|
|
{
|
|
list.Add(new SecurityBuffer(incomingBlob, BufferType.Token));
|
|
}
|
|
|
|
// when deciding if the channel binding should be added to the security buffer
|
|
// it is necessary to differentiate between client and server.
|
|
// Server rules were added to policyHelper as they are shared with Kerb and I want them consistent
|
|
// Client adds if not null.
|
|
if (this.isServer)
|
|
{
|
|
if (policyHelper.ShouldAddChannelBindingToASC())
|
|
{
|
|
list.Add(new SecurityBuffer(policyHelper.ChannelBinding));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (policyHelper.ChannelBinding != null)
|
|
{
|
|
list.Add(new SecurityBuffer(policyHelper.ChannelBinding));
|
|
}
|
|
}
|
|
|
|
SecurityBuffer[] inSecurityBuffer = null;
|
|
if (list.Count > 0)
|
|
{
|
|
inSecurityBuffer = list.ToArray();
|
|
}
|
|
|
|
SecurityBuffer outSecurityBuffer = new SecurityBuffer(this.tokenSize, BufferType.Token);
|
|
|
|
if (!this.isServer)
|
|
{
|
|
//client session
|
|
statusCode = SspiWrapper.InitializeSecurityContext(this.credentialsHandle,
|
|
ref this.securityContext,
|
|
this.servicePrincipalName,
|
|
requestedFlags,
|
|
Endianness.Network,
|
|
inSecurityBuffer,
|
|
outSecurityBuffer,
|
|
ref this.contextFlags);
|
|
}
|
|
else
|
|
{
|
|
// server session
|
|
//This check is to save an unnecessary ASC call.
|
|
bool isServerSecurityContextNull = this.securityContext == null;
|
|
SspiContextFlags serverContextFlags = this.contextFlags;
|
|
|
|
statusCode = SspiWrapper.AcceptSecurityContext(this.credentialsHandle,
|
|
ref this.securityContext,
|
|
requestedFlags,
|
|
Endianness.Network,
|
|
inSecurityBuffer,
|
|
outSecurityBuffer,
|
|
ref this.contextFlags);
|
|
|
|
if (statusCode == (int)SecurityStatus.InvalidToken && !isServerSecurityContextNull)
|
|
{
|
|
// Call again into ASC after deleting the Securitycontext. If this securitycontext is not deleted
|
|
// then when the client sends NTLM blob the service will treat it as Nego2blob and will fail to authenticate the client.
|
|
this.contextFlags = serverContextFlags;
|
|
CloseContext();
|
|
statusCode = SspiWrapper.AcceptSecurityContext(this.credentialsHandle,
|
|
ref this.securityContext,
|
|
requestedFlags,
|
|
Endianness.Network,
|
|
inSecurityBuffer,
|
|
outSecurityBuffer,
|
|
ref this.contextFlags);
|
|
}
|
|
}
|
|
|
|
if (DiagnosticUtility.ShouldTraceInformation)
|
|
{
|
|
IMD.SecurityTraceRecordHelper.TraceChannelBindingInformation(policyHelper, this.isServer, channelbinding);
|
|
}
|
|
|
|
if ((statusCode & unchecked((int)0x80000000)) != 0)
|
|
{
|
|
if (!this.isServer
|
|
&& this.interactiveNegoLogonEnabled
|
|
&& SecurityUtils.IsOSGreaterThanOrEqualToWin7()
|
|
&& SspiWrapper.IsSspiPromptingNeeded((uint)statusCode)
|
|
&& SspiWrapper.IsNegotiateExPackagePresent())
|
|
{
|
|
// If we have prompted enough number of times (DefaultMaxPromptAttempts) with wrong credentials, then we do not prompt again and throw.
|
|
if (MaxPromptAttempts >= DefaultMaxPromptAttempts)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(statusCode, SR.GetString(SR.InvalidClientCredentials)));
|
|
}
|
|
|
|
IntPtr ppAuthIdentity = IntPtr.Zero;
|
|
uint errorCode = SspiWrapper.SspiPromptForCredential(this.servicePrincipalName, this.clientPackageName, out ppAuthIdentity, ref this.saveClientCredentialsOnSspiUi);
|
|
if (errorCode == (uint)CredentialStatus.Success)
|
|
{
|
|
IntPtr ppNewAuthIdentity = IntPtr.Zero;
|
|
|
|
if (!this.allowNtlm)
|
|
{
|
|
// When Ntlm is explicitly disabled we don't want the collected
|
|
//creds from the Kerb/NTLM tile to be used for NTLM auth.
|
|
|
|
uint status = UnsafeNativeMethods.SspiExcludePackage(ppAuthIdentity, "NTLM", out ppNewAuthIdentity);
|
|
}
|
|
else
|
|
{
|
|
ppNewAuthIdentity = ppAuthIdentity;
|
|
}
|
|
|
|
this.credentialsHandle = SspiWrapper.AcquireCredentialsHandle(this.clientPackageName, CredentialUse.Outbound, ref ppNewAuthIdentity);
|
|
|
|
if (IntPtr.Zero != ppNewAuthIdentity)
|
|
{
|
|
UnsafeNativeMethods.SspiFreeAuthIdentity(ppNewAuthIdentity);
|
|
}
|
|
|
|
CloseContext();
|
|
|
|
MaxPromptAttempts++;
|
|
return this.GetOutgoingBlob(null, channelbinding, protectionPolicy);
|
|
}
|
|
else
|
|
{
|
|
// Call into SspiPromptForCredential had an error. Time to throw.
|
|
if (IntPtr.Zero != ppAuthIdentity)
|
|
{
|
|
UnsafeNativeMethods.SspiFreeAuthIdentity(ppAuthIdentity);
|
|
}
|
|
|
|
CloseContext();
|
|
this.isCompleted = true;
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception((int)errorCode, SR.GetString(SR.SspiErrorOrInvalidClientCredentials)));
|
|
}
|
|
}
|
|
|
|
CloseContext();
|
|
this.isCompleted = true;
|
|
if (!this.isServer && (statusCode == (int)SecurityStatus.TargetUnknown
|
|
|| statusCode == (int)SecurityStatus.WrongPrincipal))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(statusCode, SR.GetString(SR.IncorrectSpnOrUpnSpecified, this.servicePrincipalName)));
|
|
}
|
|
else
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(statusCode, SR.GetString(SR.InvalidSspiNegotiation)));
|
|
}
|
|
}
|
|
|
|
if (DiagnosticUtility.ShouldTraceInformation)
|
|
{
|
|
if (this.isServer)
|
|
{
|
|
SecurityTraceRecordHelper.TraceServiceOutgoingSpnego(this);
|
|
}
|
|
else
|
|
{
|
|
SecurityTraceRecordHelper.TraceClientOutgoingSpnego(this);
|
|
}
|
|
}
|
|
|
|
if (statusCode == (int)SecurityStatus.OK)
|
|
{
|
|
// we're done
|
|
this.isCompleted = true;
|
|
|
|
// These must all be true to check service binding
|
|
// 1. we are the service (listener)
|
|
// 2. caller is not anonymous
|
|
// 3. protocol is not Kerberos
|
|
// 4. policy is set to check service binding
|
|
//
|
|
if (isServer && ((this.contextFlags & SspiContextFlags.AcceptAnonymous) == 0) && (string.Compare(this.ProtocolName, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnoreCase) != 0) && policyHelper.ShouldCheckServiceBinding)
|
|
{
|
|
// in the server case the servicePrincipalName is the defaultServiceBinding
|
|
|
|
if (DiagnosticUtility.ShouldTraceInformation)
|
|
{
|
|
string serviceBindingNameSentByClient;
|
|
SspiWrapper.QuerySpecifiedTarget(securityContext, out serviceBindingNameSentByClient);
|
|
IMD.SecurityTraceRecordHelper.TraceServiceNameBindingOnServer( serviceBindingNameSentByClient, this.servicePrincipalName, policyHelper.ServiceNameCollection);
|
|
}
|
|
|
|
policyHelper.CheckServiceBinding(this.securityContext, this.servicePrincipalName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we need to continue
|
|
}
|
|
|
|
return outSecurityBuffer.token;
|
|
}
|
|
|
|
public void ImpersonateContext()
|
|
{
|
|
ThrowIfDisposed();
|
|
if (!IsValidContext)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception((int)SecurityStatus.InvalidHandle));
|
|
}
|
|
|
|
SspiWrapper.ImpersonateSecurityContext(this.securityContext);
|
|
}
|
|
|
|
internal void CloseContext()
|
|
{
|
|
ThrowIfDisposed();
|
|
try
|
|
{
|
|
if (this.securityContext != null)
|
|
{
|
|
this.securityContext.Close();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
this.securityContext = null;
|
|
}
|
|
}
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
lock (this.syncObject)
|
|
{
|
|
if (this.disposed == false)
|
|
{
|
|
if (disposing)
|
|
{
|
|
this.CloseContext();
|
|
}
|
|
|
|
// set to null any references that aren't finalizable
|
|
this.protocolName = null;
|
|
this.servicePrincipalName = null;
|
|
this.sizes = null;
|
|
this.disposed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal SafeCloseHandle GetContextToken()
|
|
{
|
|
if (!IsValidContext)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception((int)SecurityStatus.InvalidHandle));
|
|
}
|
|
|
|
SafeCloseHandle token;
|
|
SecurityStatus status = (SecurityStatus)SspiWrapper.QuerySecurityContextToken(this.securityContext, out token);
|
|
if (status != SecurityStatus.OK)
|
|
{
|
|
Utility.CloseInvalidOutSafeHandle(token);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception((int)status));
|
|
}
|
|
return token;
|
|
}
|
|
|
|
void OnBadData()
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.BadData)));
|
|
}
|
|
|
|
void ThrowIfDisposed()
|
|
{
|
|
lock (this.syncObject)
|
|
{
|
|
if (this.disposed)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(null));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|