Improved GSS implementation

This commit is contained in:
Tal Aloni 2017-06-05 21:48:32 +03:00
parent cd11c57cc4
commit d16092ed38
3 changed files with 48 additions and 40 deletions

View file

@ -11,12 +11,23 @@ using Utilities;
namespace SMBLibrary.Authentication.GSSAPI namespace SMBLibrary.Authentication.GSSAPI
{ {
public class GSSContext
{
internal IGSSMechanism Mechanism;
internal object MechanismContext;
internal GSSContext(IGSSMechanism mechanism, object mechanismContext)
{
Mechanism = mechanism;
MechanismContext = mechanismContext;
}
}
public class GSSProvider public class GSSProvider
{ {
public static readonly byte[] NTLMSSPIdentifier = new byte[] { 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a }; public static readonly byte[] NTLMSSPIdentifier = new byte[] { 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a };
private List<IGSSMechanism> m_mechanisms; private List<IGSSMechanism> m_mechanisms;
private Dictionary<object, IGSSMechanism> m_contextToMechanism = new Dictionary<object, IGSSMechanism>();
public GSSProvider(IGSSMechanism mechanism) public GSSProvider(IGSSMechanism mechanism)
{ {
@ -40,7 +51,7 @@ namespace SMBLibrary.Authentication.GSSAPI
return SimpleProtectedNegotiationToken.GetTokenBytes(token); return SimpleProtectedNegotiationToken.GetTokenBytes(token);
} }
public NTStatus AcceptSecurityContext(ref object context, byte[] inputToken, out byte[] outputToken) public NTStatus AcceptSecurityContext(ref GSSContext context, byte[] inputToken, out byte[] outputToken)
{ {
outputToken = null; outputToken = null;
SimpleProtectedNegotiationToken spnegoToken = SimpleProtectedNegotiationToken.ReadToken(inputToken, 0); SimpleProtectedNegotiationToken spnegoToken = SimpleProtectedNegotiationToken.ReadToken(inputToken, 0);
@ -67,10 +78,11 @@ namespace SMBLibrary.Authentication.GSSAPI
if (mechanism != null) if (mechanism != null)
{ {
NTStatus status; NTStatus status;
context = new GSSContext(mechanism, null);
if (isPreferredMechanism) if (isPreferredMechanism)
{ {
byte[] mechanismOutput; byte[] mechanismOutput;
status = mechanism.AcceptSecurityContext(ref context, tokenInit.MechanismToken, out mechanismOutput); status = mechanism.AcceptSecurityContext(ref context.MechanismContext, tokenInit.MechanismToken, out mechanismOutput);
outputToken = GetSPNEGOTokenResponseBytes(mechanismOutput, status, mechanism.Identifier); outputToken = GetSPNEGOTokenResponseBytes(mechanismOutput, status, mechanism.Identifier);
} }
else else
@ -78,23 +90,20 @@ namespace SMBLibrary.Authentication.GSSAPI
status = NTStatus.SEC_I_CONTINUE_NEEDED; status = NTStatus.SEC_I_CONTINUE_NEEDED;
outputToken = GetSPNEGOTokenResponseBytes(null, status, mechanism.Identifier); outputToken = GetSPNEGOTokenResponseBytes(null, status, mechanism.Identifier);
} }
m_contextToMechanism[context] = mechanism;
return status; return status;
} }
return NTStatus.SEC_E_SECPKG_NOT_FOUND; return NTStatus.SEC_E_SECPKG_NOT_FOUND;
} }
else // SimpleProtectedNegotiationTokenResponse else // SimpleProtectedNegotiationTokenResponse
{ {
IGSSMechanism mechanism; if (context == null)
if (!m_contextToMechanism.TryGetValue(context, out mechanism))
{ {
// We assume that the problem is not with our implementation and that the client has sent
// SimpleProtectedNegotiationTokenResponse without first sending SimpleProtectedNegotiationTokenInit.
return NTStatus.SEC_E_INVALID_TOKEN; return NTStatus.SEC_E_INVALID_TOKEN;
} }
IGSSMechanism mechanism = context.Mechanism;
SimpleProtectedNegotiationTokenResponse tokenResponse = (SimpleProtectedNegotiationTokenResponse)spnegoToken; SimpleProtectedNegotiationTokenResponse tokenResponse = (SimpleProtectedNegotiationTokenResponse)spnegoToken;
byte[] mechanismOutput; byte[] mechanismOutput;
NTStatus status = mechanism.AcceptSecurityContext(ref context, tokenResponse.ResponseToken, out mechanismOutput); NTStatus status = mechanism.AcceptSecurityContext(ref context.MechanismContext, tokenResponse.ResponseToken, out mechanismOutput);
outputToken = GetSPNEGOTokenResponseBytes(mechanismOutput, status, null); outputToken = GetSPNEGOTokenResponseBytes(mechanismOutput, status, null);
return status; return status;
} }
@ -109,11 +118,17 @@ namespace SMBLibrary.Authentication.GSSAPI
IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier); IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier);
if (ntlmAuthenticationProvider != null) if (ntlmAuthenticationProvider != null)
{ {
NTStatus status = ntlmAuthenticationProvider.AcceptSecurityContext(ref context, inputToken, out outputToken);
if (messageType == MessageTypeName.Negotiate) if (messageType == MessageTypeName.Negotiate)
{ {
m_contextToMechanism[context] = ntlmAuthenticationProvider; context = new GSSContext(ntlmAuthenticationProvider, null);
} }
if (context == null)
{
return NTStatus.SEC_E_INVALID_TOKEN;
}
NTStatus status = ntlmAuthenticationProvider.AcceptSecurityContext(ref context.MechanismContext, inputToken, out outputToken);
return status; return status;
} }
else else
@ -125,53 +140,44 @@ namespace SMBLibrary.Authentication.GSSAPI
return NTStatus.SEC_E_INVALID_TOKEN; return NTStatus.SEC_E_INVALID_TOKEN;
} }
public object GetContextAttribute(object context, GSSAttributeName attributeName) public object GetContextAttribute(GSSContext context, GSSAttributeName attributeName)
{ {
IGSSMechanism mechanism; if (context == null)
if (!m_contextToMechanism.TryGetValue(context, out mechanism))
{ {
return null; return null;
} }
return mechanism.GetContextAttribute(context, attributeName); IGSSMechanism mechanism = context.Mechanism;
return mechanism.GetContextAttribute(context.MechanismContext, attributeName);
} }
public bool DeleteSecurityContext(ref object context) public bool DeleteSecurityContext(ref GSSContext context)
{ {
bool result = false;
if (context != null) if (context != null)
{ {
IGSSMechanism mechanism; IGSSMechanism mechanism = context.Mechanism;
if (m_contextToMechanism.TryGetValue(context, out mechanism)) return mechanism.DeleteSecurityContext(ref context.MechanismContext);
{
object contextReference = context;
result = mechanism.DeleteSecurityContext(ref context);
if (result)
{
m_contextToMechanism.Remove(contextReference);
} }
} return false;
}
return result;
} }
/// <summary> /// <summary>
/// Helper method for legacy implementation. /// Helper method for legacy implementation.
/// </summary> /// </summary>
public NTStatus GetNTLMChallengeMessage(out object context, NegotiateMessage negotiateMessage, out ChallengeMessage challengeMessage) public NTStatus GetNTLMChallengeMessage(out GSSContext context, NegotiateMessage negotiateMessage, out ChallengeMessage challengeMessage)
{ {
context = null;
challengeMessage = null;
IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier); IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier);
if (ntlmAuthenticationProvider != null) if (ntlmAuthenticationProvider != null)
{ {
context = new GSSContext(ntlmAuthenticationProvider, null);
byte[] outputToken; byte[] outputToken;
NTStatus result = ntlmAuthenticationProvider.AcceptSecurityContext(ref context, negotiateMessage.GetBytes(), out outputToken); NTStatus result = ntlmAuthenticationProvider.AcceptSecurityContext(ref context.MechanismContext, negotiateMessage.GetBytes(), out outputToken);
challengeMessage = new ChallengeMessage(outputToken); challengeMessage = new ChallengeMessage(outputToken);
m_contextToMechanism.Add(context, ntlmAuthenticationProvider);
return result; return result;
} }
else else
{ {
context = null;
challengeMessage = null;
return NTStatus.SEC_E_SECPKG_NOT_FOUND; return NTStatus.SEC_E_SECPKG_NOT_FOUND;
} }
} }
@ -179,13 +185,13 @@ namespace SMBLibrary.Authentication.GSSAPI
/// <summary> /// <summary>
/// Helper method for legacy implementation. /// Helper method for legacy implementation.
/// </summary> /// </summary>
public NTStatus NTLMAuthenticate(object context, AuthenticateMessage authenticateMessage) public NTStatus NTLMAuthenticate(GSSContext context, AuthenticateMessage authenticateMessage)
{ {
IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier); if (context != null && ByteUtils.AreByteArraysEqual(context.Mechanism.Identifier, NTLMSSPIdentifier))
if (ntlmAuthenticationProvider != null)
{ {
IGSSMechanism mechanism = context.Mechanism;
byte[] outputToken; byte[] outputToken;
NTStatus result = ntlmAuthenticationProvider.AcceptSecurityContext(ref context, authenticateMessage.GetBytes(), out outputToken); NTStatus result = mechanism.AcceptSecurityContext(ref context.MechanismContext, authenticateMessage.GetBytes(), out outputToken);
return result; return result;
} }
else else

View file

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using SMBLibrary.Authentication.GSSAPI;
using SMBLibrary.NetBios; using SMBLibrary.NetBios;
using Utilities; using Utilities;
@ -23,7 +24,7 @@ namespace SMBLibrary.Server
public BlockingQueue<SessionPacket> SendQueue; public BlockingQueue<SessionPacket> SendQueue;
protected LogDelegate LogToServerHandler; protected LogDelegate LogToServerHandler;
public SMBDialect Dialect; public SMBDialect Dialect;
public object AuthenticationContext; public GSSContext AuthenticationContext;
public ConnectionState(LogDelegate logToServerHandler) public ConnectionState(LogDelegate logToServerHandler)
{ {

View file

@ -7,6 +7,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using SMBLibrary.Authentication.GSSAPI;
namespace SMBLibrary namespace SMBLibrary
{ {
@ -15,10 +16,10 @@ namespace SMBLibrary
private string m_userName; private string m_userName;
private string m_machineName; private string m_machineName;
private IPEndPoint m_clientEndPoint; private IPEndPoint m_clientEndPoint;
public object AuthenticationContext; public GSSContext AuthenticationContext;
public object AccessToken; public object AccessToken;
public SecurityContext(string userName, string machineName, IPEndPoint clientEndPoint, object authenticationContext, object accessToken) public SecurityContext(string userName, string machineName, IPEndPoint clientEndPoint, GSSContext authenticationContext, object accessToken)
{ {
m_userName = userName; m_userName = userName;
m_machineName = machineName; m_machineName = machineName;