mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-08-16 04:03:47 +02:00
Added signature verification support for SMB2 client
This commit is contained in:
parent
ef4508271c
commit
fe40563d65
2 changed files with 358 additions and 9 deletions
264
SMBLibrary.Tests/Client/SMB2SigningTests.cs
Normal file
264
SMBLibrary.Tests/Client/SMB2SigningTests.cs
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using SMBLibrary.Client;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using SMBLibrary.Server;
|
||||||
|
using SMBLibrary.Authentication.GSSAPI;
|
||||||
|
using SMBLibrary.Client.Authentication;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SMBLibrary.Tests.Client
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class SMB2SigningTests
|
||||||
|
{
|
||||||
|
private TcpRelay m_tcpRelay;
|
||||||
|
private SMBServer m_smbServer;
|
||||||
|
private SMB2Client client;
|
||||||
|
private static readonly byte[] m_sessionKey = new byte[16];
|
||||||
|
private static readonly byte[] m_fakeIdentifier = new byte[] { 1, 2, 3, 4, 5, 6 };
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
new Random().NextBytes(m_sessionKey);
|
||||||
|
|
||||||
|
SMBShareCollection shares = new SMBShareCollection();
|
||||||
|
GSSProvider securityProvider = new GSSProvider(new FakeAuthenticationProvider());
|
||||||
|
m_smbServer = new SMBServer(shares, securityProvider);
|
||||||
|
m_smbServer.Start(IPAddress.Any, SMBTransportType.NetBiosOverTCP, 30002, false, true, true, null);
|
||||||
|
|
||||||
|
m_tcpRelay = new TcpRelay();
|
||||||
|
Task.Run(m_tcpRelay.Start);
|
||||||
|
|
||||||
|
client = new SMB2Client();
|
||||||
|
client.SigningRequired = true;
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = true;
|
||||||
|
Assert.IsTrue(client.Connect(IPAddress.Loopback, SMBTransportType.DirectTCPTransport, 30001, 3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCleanup]
|
||||||
|
public void CleanUp()
|
||||||
|
{
|
||||||
|
client?.Disconnect();
|
||||||
|
m_tcpRelay.Stop();
|
||||||
|
m_smbServer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void When_SignatureIsValid_ShouldNotBeInvalid()
|
||||||
|
{
|
||||||
|
client.DisconnectOnInvalidSignature = false;
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = false;
|
||||||
|
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_SUCCESS, client.Login(new FakeAuthenticationClient()));
|
||||||
|
|
||||||
|
client.TreeConnect("test", out NTStatus status);
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_OBJECT_PATH_NOT_FOUND, status);
|
||||||
|
Assert.IsTrue(client.IsConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void When_SigningEnabledAndSignatureIsInvalid_LoginShouldFail()
|
||||||
|
{
|
||||||
|
client.DisconnectOnInvalidSignature = false;
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = true;
|
||||||
|
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_INVALID_SMB, client.Login(new FakeAuthenticationClient()));
|
||||||
|
Assert.IsTrue(client.IsConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void When_SigningEnabledAndSignatureIsInvalid_LoginShouldDisconnect()
|
||||||
|
{
|
||||||
|
client.DisconnectOnInvalidSignature = true;
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = true;
|
||||||
|
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_INVALID_SMB, client.Login(new FakeAuthenticationClient()));
|
||||||
|
Assert.IsFalse(client.IsConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void When_SigningEnabledAndSignatureIsInvalid_CommandShouldFail()
|
||||||
|
{
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = false;
|
||||||
|
client.DisconnectOnInvalidSignature = false;
|
||||||
|
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_SUCCESS, client.Login(new FakeAuthenticationClient()));
|
||||||
|
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = true;
|
||||||
|
|
||||||
|
client.TreeConnect("test", out NTStatus status);
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_INVALID_SMB, status);
|
||||||
|
Assert.IsTrue(client.IsConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void When_SigningEnabledAndSignatureIsInvalid_CommandShouldDisconnect()
|
||||||
|
{
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = false;
|
||||||
|
client.DisconnectOnInvalidSignature = true;
|
||||||
|
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_SUCCESS, client.Login(new FakeAuthenticationClient()));
|
||||||
|
|
||||||
|
m_tcpRelay.SignatureManipulationEnabled = true;
|
||||||
|
|
||||||
|
client.TreeConnect("test", out NTStatus status);
|
||||||
|
Assert.AreEqual(NTStatus.STATUS_INVALID_SMB, status);
|
||||||
|
Assert.IsFalse(client.IsConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeAuthenticationClient : IAuthenticationClient
|
||||||
|
{
|
||||||
|
public byte[] GetSessionKey()
|
||||||
|
{
|
||||||
|
return m_sessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] InitializeSecurityContext(byte[] securityBlob)
|
||||||
|
{
|
||||||
|
SimpleProtectedNegotiationTokenInit initToken = new SimpleProtectedNegotiationTokenInit();
|
||||||
|
initToken.MechanismTypeList = new List<byte[]>() { m_fakeIdentifier };
|
||||||
|
return initToken.GetBytes(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeAuthenticationProvider : IGSSMechanism
|
||||||
|
{
|
||||||
|
public byte[] Identifier => m_fakeIdentifier;
|
||||||
|
|
||||||
|
public NTStatus AcceptSecurityContext(ref object context, byte[] inputToken, out byte[] outputToken)
|
||||||
|
{
|
||||||
|
outputToken = null;
|
||||||
|
return NTStatus.STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteSecurityContext(ref object context)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetContextAttribute(object context, GSSAttributeName attributeName)
|
||||||
|
{
|
||||||
|
switch (attributeName)
|
||||||
|
{
|
||||||
|
case GSSAttributeName.SessionKey:
|
||||||
|
return m_sessionKey;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TcpRelay
|
||||||
|
{
|
||||||
|
private TcpListener m_relay;
|
||||||
|
private TcpClient m_localClient;
|
||||||
|
private TcpClient m_remoteClient;
|
||||||
|
private Thread m_clientToServer;
|
||||||
|
private Thread m_serverToClient;
|
||||||
|
|
||||||
|
public bool SignatureManipulationEnabled { get; set; } = false;
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
m_remoteClient = new TcpClient();
|
||||||
|
m_remoteClient.Connect(IPAddress.Loopback, 30002);
|
||||||
|
|
||||||
|
m_relay = new TcpListener(IPAddress.Any, 30001);
|
||||||
|
m_relay.Start();
|
||||||
|
|
||||||
|
m_localClient = m_relay.AcceptTcpClient();
|
||||||
|
|
||||||
|
NetworkStream localStream = m_localClient.GetStream();
|
||||||
|
NetworkStream remoteStream = m_remoteClient.GetStream();
|
||||||
|
|
||||||
|
m_clientToServer = new Thread(() => ForwardData(localStream, remoteStream));
|
||||||
|
m_serverToClient = new Thread(() => ForwardData(remoteStream, localStream));
|
||||||
|
|
||||||
|
m_clientToServer.Start();
|
||||||
|
m_serverToClient.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
m_localClient?.Dispose();
|
||||||
|
m_remoteClient?.Dispose();
|
||||||
|
m_relay?.Stop();
|
||||||
|
m_clientToServer.Join();
|
||||||
|
m_serverToClient.Join();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ForwardData(NetworkStream input, NetworkStream output)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||||
|
{
|
||||||
|
if (TryGetSmb2HeaderOffset(buffer, bytesRead, out int smbOffset) && IsSigned(buffer, smbOffset) && SignatureManipulationEnabled)
|
||||||
|
{
|
||||||
|
ManipulateSignature(buffer, smbOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Likely disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetSmb2HeaderOffset(byte[] data, int length, out int offset)
|
||||||
|
{
|
||||||
|
offset = -1;
|
||||||
|
|
||||||
|
// NetBIOS Session Header?
|
||||||
|
if (length >= 68 && data[0] == 0x00)
|
||||||
|
{
|
||||||
|
if (data[4] == 0xFE && data[5] == (byte)'S' && data[6] == (byte)'M' && data[7] == (byte)'B')
|
||||||
|
{
|
||||||
|
offset = 4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (length >= 64 && data[0] == 0xFE && data[1] == (byte)'S' && data[2] == (byte)'M' && data[3] == (byte)'B')
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsSigned(byte[] data, int offset)
|
||||||
|
{
|
||||||
|
uint flags = BitConverter.ToUInt32(data, offset + 16);
|
||||||
|
return (flags & 0x00000008) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ManipulateSignature(byte[] data, int offset)
|
||||||
|
{
|
||||||
|
Random rand = new Random();
|
||||||
|
|
||||||
|
// Change a random signature byte
|
||||||
|
int idx = rand.Next(48, 48 + 16);
|
||||||
|
|
||||||
|
// Generate a new random byte and make sure it is different from the current value
|
||||||
|
int byteValue;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byteValue = rand.Next(0, 256);
|
||||||
|
}
|
||||||
|
while (data[offset + idx] == byteValue);
|
||||||
|
|
||||||
|
data[offset + idx] = (byte) byteValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,10 +59,15 @@ namespace SMBLibrary.Client
|
||||||
private byte[] m_preauthIntegrityHashValue; // SMB 3.1.1
|
private byte[] m_preauthIntegrityHashValue; // SMB 3.1.1
|
||||||
private ushort m_availableCredits = 1;
|
private ushort m_availableCredits = 1;
|
||||||
|
|
||||||
|
private byte[] m_sessionSetupResponseMessage;
|
||||||
|
|
||||||
public SMB2Client()
|
public SMB2Client()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool SigningRequired { get; set; } = false;
|
||||||
|
public bool DisconnectOnInvalidSignature { get; set; } = false;
|
||||||
|
|
||||||
/// <param name="serverName">
|
/// <param name="serverName">
|
||||||
/// When a Windows Server host is using Failover Cluster and Cluster Shared Volumes, each of those CSV file shares is associated
|
/// When a Windows Server host is using Failover Cluster and Cluster Shared Volumes, each of those CSV file shares is associated
|
||||||
/// with a specific host name associated with the cluster and is not accessible using the node IP address or node host name.
|
/// with a specific host name associated with the cluster and is not accessible using the node IP address or node host name.
|
||||||
|
@ -197,7 +202,7 @@ namespace SMBLibrary.Client
|
||||||
private bool NegotiateDialect()
|
private bool NegotiateDialect()
|
||||||
{
|
{
|
||||||
NegotiateRequest request = new NegotiateRequest();
|
NegotiateRequest request = new NegotiateRequest();
|
||||||
request.SecurityMode = SecurityMode.SigningEnabled;
|
request.SecurityMode = SigningRequired ? SecurityMode.SigningRequired | SecurityMode.SigningEnabled : SecurityMode.SigningEnabled;
|
||||||
request.Capabilities = Capabilities.Encryption;
|
request.Capabilities = Capabilities.Encryption;
|
||||||
request.ClientGuid = Guid.NewGuid();
|
request.ClientGuid = Guid.NewGuid();
|
||||||
request.ClientStartTime = DateTime.Now;
|
request.ClientStartTime = DateTime.Now;
|
||||||
|
@ -219,7 +224,7 @@ namespace SMBLibrary.Client
|
||||||
m_dialect = response.DialectRevision;
|
m_dialect = response.DialectRevision;
|
||||||
// [MS-SMB2] 3.3.5.7 If Connection.Dialect is "3.1.1" and Session.IsAnonymous and Session.IsGuest
|
// [MS-SMB2] 3.3.5.7 If Connection.Dialect is "3.1.1" and Session.IsAnonymous and Session.IsGuest
|
||||||
// are set to FALSE and the request is not signed or not encrypted, then the server MUST disconnect the connection.
|
// are set to FALSE and the request is not signed or not encrypted, then the server MUST disconnect the connection.
|
||||||
m_signingRequired = (response.SecurityMode & SecurityMode.SigningRequired) > 0 ||
|
m_signingRequired = SigningRequired || (response.SecurityMode & SecurityMode.SigningRequired) > 0 ||
|
||||||
response.DialectRevision == SMB2Dialect.SMB311;
|
response.DialectRevision == SMB2Dialect.SMB311;
|
||||||
m_maxTransactSize = Math.Min(response.MaxTransactSize, ClientMaxTransactSize);
|
m_maxTransactSize = Math.Min(response.MaxTransactSize, ClientMaxTransactSize);
|
||||||
m_maxReadSize = Math.Min(response.MaxReadSize, ClientMaxReadSize);
|
m_maxReadSize = Math.Min(response.MaxReadSize, ClientMaxReadSize);
|
||||||
|
@ -256,7 +261,7 @@ namespace SMBLibrary.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionSetupRequest request = new SessionSetupRequest();
|
SessionSetupRequest request = new SessionSetupRequest();
|
||||||
request.SecurityMode = SecurityMode.SigningEnabled;
|
request.SecurityMode = SigningRequired ? SecurityMode.SigningRequired | SecurityMode.SigningEnabled : SecurityMode.SigningEnabled;
|
||||||
request.SecurityBuffer = negotiateMessage;
|
request.SecurityBuffer = negotiateMessage;
|
||||||
TrySendCommand(request);
|
TrySendCommand(request);
|
||||||
SMB2Command response = WaitForCommand(request.MessageID);
|
SMB2Command response = WaitForCommand(request.MessageID);
|
||||||
|
@ -270,7 +275,7 @@ namespace SMBLibrary.Client
|
||||||
|
|
||||||
m_sessionID = response.Header.SessionID;
|
m_sessionID = response.Header.SessionID;
|
||||||
request = new SessionSetupRequest();
|
request = new SessionSetupRequest();
|
||||||
request.SecurityMode = SecurityMode.SigningEnabled;
|
request.SecurityMode = SigningRequired ? SecurityMode.SigningRequired | SecurityMode.SigningEnabled : SecurityMode.SigningEnabled;
|
||||||
request.SecurityBuffer = authenticateMessage;
|
request.SecurityBuffer = authenticateMessage;
|
||||||
TrySendCommand(request);
|
TrySendCommand(request);
|
||||||
response = WaitForCommand(request.MessageID);
|
response = WaitForCommand(request.MessageID);
|
||||||
|
@ -301,6 +306,26 @@ namespace SMBLibrary.Client
|
||||||
m_encryptionKey = SMB2Cryptography.GenerateClientEncryptionKey(m_sessionKey, m_dialect, m_preauthIntegrityHashValue);
|
m_encryptionKey = SMB2Cryptography.GenerateClientEncryptionKey(m_sessionKey, m_dialect, m_preauthIntegrityHashValue);
|
||||||
m_decryptionKey = SMB2Cryptography.GenerateClientDecryptionKey(m_sessionKey, m_dialect, m_preauthIntegrityHashValue);
|
m_decryptionKey = SMB2Cryptography.GenerateClientDecryptionKey(m_sessionKey, m_dialect, m_preauthIntegrityHashValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [MS-SMB2] 3.2.5.1.3 Verifying the Signature
|
||||||
|
// If signature verification fails, the client MUST discard the received message.
|
||||||
|
// The client MAY also choose to disconnect the connection.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!VerifySignature(m_sessionSetupResponseMessage, response))
|
||||||
|
{
|
||||||
|
m_isLoggedIn = false;
|
||||||
|
if (DisconnectOnInvalidSignature)
|
||||||
|
{
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
return NTStatus.STATUS_INVALID_SMB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
m_sessionSetupResponseMessage = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return response.Header.Status;
|
return response.Header.Status;
|
||||||
}
|
}
|
||||||
|
@ -526,15 +551,43 @@ namespace SMBLibrary.Client
|
||||||
// and the client MUST NOT attempt to locate the request, but instead process it as follows:
|
// and the client MUST NOT attempt to locate the request, but instead process it as follows:
|
||||||
// If the command field in the SMB2 header is SMB2 OPLOCK_BREAK, it MUST be processed as specified in 3.2.5.19.
|
// If the command field in the SMB2 header is SMB2 OPLOCK_BREAK, it MUST be processed as specified in 3.2.5.19.
|
||||||
// Otherwise, the response MUST be discarded as invalid.
|
// Otherwise, the response MUST be discarded as invalid.
|
||||||
if (command.Header.MessageID != 0xFFFFFFFFFFFFFFFF || command.Header.Command == SMB2CommandName.OplockBreak)
|
if (command.Header.MessageID == 0xFFFFFFFFFFFFFFFF && command.Header.Command != SMB2CommandName.OplockBreak)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [MS-SMB2] 3.2.5.1.3 Verifying the Signature
|
||||||
|
// If signature verification fails, the client MUST discard the received message.
|
||||||
|
// The client MAY also choose to disconnect the connection.
|
||||||
|
if (m_isLoggedIn)
|
||||||
|
{
|
||||||
|
// This check covers all messages except the final session setup message which is treated seperately
|
||||||
|
if (!VerifySignature(messageBytes, command))
|
||||||
|
{
|
||||||
|
if (DisconnectOnInvalidSignature)
|
||||||
|
{
|
||||||
|
m_isLoggedIn = false;
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((command.Header.Command == SMB2CommandName.SessionSetup) &&
|
||||||
|
(command.Header.Status == NTStatus.STATUS_SUCCESS))
|
||||||
|
{
|
||||||
|
// The final session setup message already has a valid signature, but the session/signing key have not been set yet (m_isLoggedIn is false).
|
||||||
|
// The message is evaluated within the Login() method, which will then determine the keys and set m_isLoggedIn to true.
|
||||||
|
// Nevertheless, the signature must be verified. So the raw message is preserved here and the signature is verified later in the
|
||||||
|
// Login() method, after the keys have been set.
|
||||||
|
m_sessionSetupResponseMessage = messageBytes;
|
||||||
|
}
|
||||||
|
|
||||||
lock (m_incomingQueueLock)
|
lock (m_incomingQueueLock)
|
||||||
{
|
{
|
||||||
m_incomingQueue.Add(command);
|
m_incomingQueue.Add(command);
|
||||||
m_incomingQueueEventHandle.Set();
|
m_incomingQueueEventHandle.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP)
|
else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP)
|
||||||
{
|
{
|
||||||
m_sessionResponsePacket = packet;
|
m_sessionResponsePacket = packet;
|
||||||
|
@ -552,6 +605,38 @@ namespace SMBLibrary.Client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [MS-SMB2] 3.2.5.1.3 Verifying the Signature
|
||||||
|
private bool VerifySignature(byte[] messageBytes, SMB2Command command)
|
||||||
|
{
|
||||||
|
if (!m_signingRequired)
|
||||||
|
{
|
||||||
|
// Client and server require no signing at all
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageBytes == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("messageBytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUnspecifiedMessageId = command.Header.MessageID == 0xFFFFFFFFFFFFFFFF;
|
||||||
|
bool isPendingMessage = command.Header.Status == NTStatus.STATUS_PENDING;
|
||||||
|
|
||||||
|
if (m_encryptSessionData || isUnspecifiedMessageId || isPendingMessage)
|
||||||
|
{
|
||||||
|
// Signing is not required
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] key = (m_dialect >= SMB2Dialect.SMB300) ? m_signingKey : m_sessionKey;
|
||||||
|
|
||||||
|
Array.Clear(messageBytes, SMB2Header.SignatureOffset, command.Header.Signature.Length);
|
||||||
|
byte[] signature = SMB2Cryptography.CalculateSignature(key, m_dialect, messageBytes, 0, messageBytes.Length);
|
||||||
|
signature = ByteReader.ReadBytes(signature, 0, command.Header.Signature.Length);
|
||||||
|
|
||||||
|
return ByteUtils.AreByteArraysEqual(signature, command.Header.Signature);
|
||||||
|
}
|
||||||
|
|
||||||
internal SMB2Command WaitForCommand(ulong messageID)
|
internal SMB2Command WaitForCommand(ulong messageID)
|
||||||
{
|
{
|
||||||
return WaitForCommand(messageID, out bool _);
|
return WaitForCommand(messageID, out bool _);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue