private static bool VerifySession(ModelSmb2Status status, ModelRequestType modelRequestType, EncryptionConfig c) { ModelHelper.Log(LogType.Requirement, "3.3.5.2.9 Verifying the Session"); if (Smb2Utility.IsSmb3xFamily(negotiateDialect) && Session_EncryptData == SessionEncryptDataType.SessionEncryptDataSet && (modelRequestType == ModelRequestType.UnEncryptedRequest) && (config.MaxSmbVersionSupported == ModelDialectRevision.Smb311 || ((config.MaxSmbVersionSupported == ModelDialectRevision.Smb30 || config.MaxSmbVersionSupported == ModelDialectRevision.Smb302) && config.IsGlobalRejectUnencryptedAccessEnabled))) { ModelHelper.Log(LogType.Requirement, "If Connection.Dialect belongs to the SMB 3.x dialect family, and Session.EncryptData is TRUE, " + "the server MUST do the following: \n" + "\tIf the server supports the 3.1.1 dialect, locate the Request in Connection.RequestList for which " + "Request.MessageId matches the MessageId value in the SMB2 header of the request." + "\tOtherwise, if the server supports 3.0 or 3.0.2 dialect, and RejectUnencryptedAccess is TRUE, " + "locate the Request in Connection.RequestList for which Request.MessageId matches the MessageId " + "value in the SMB2 header of the request.\n" + "If Request.IsEncrypted is FALSE, the server MUST fail the request with STATUS_ACCESS_DENIED"); ModelHelper.Log(LogType.TestInfo, "Server supports {0}, RejectUnencryptedAccess is {1}", config.MaxSmbVersionSupported, config.IsGlobalRejectUnencryptedAccessEnabled ? "TRUE" : "FALSE"); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return(false); } return(true); }
/// <summary> /// Verify the signature of a Smb2SinglePacket /// </summary> /// <param name="packet">The packet to be verified</param> /// <param name="cryptoInfo">The cryptoInfo of smb2client</param> /// <returns>True when signature verification succeeds and false when fails</returns> private bool VerifySignature(Smb2SinglePacket packet, Smb2CryptoInfo cryptoInfo) { if (cryptoInfo.DisableVerifySignature) { // Skip the verification. return(true); } try { if (IsErrorPacket(packet.Header)) { packet = packet.Error; } //save the 16-byte signature from the Signature field in the SMB2 Header byte[] originalSignature = packet.Header.Signature; //zero out the 16-byte signature field in the SMB2 Header of the incoming message. packet.Header.Signature = new byte[Smb2Consts.SignatureSize]; byte[] bytesToCompute = packet.ToBytes(); //Compute the message with signing key byte[] computedSignature = new byte[] { }; if (Smb2Utility.IsSmb3xFamily(cryptoInfo.Dialect)) { //[MS-SMB2] 3.1.5.1 //If Session.Connection.Dialect belongs to the SMB 3.x dialect family, //the receiver MUST compute a 16-byte hash by using AES-128-CMAC over the entire message, //beginning with the SMB2 Header from step 2, and using the key provided. //The AES-128-CMAC is specified in [RFC4493]. //TD has mentioned to use Session.SigningKey for SESSION_SETUP Response and Channel.SigningKey for other responses //In the current SDK, the SigningKey is the Channel.SigningKey computedSignature = AesCmac128.ComputeHash(cryptoInfo.SigningKey, bytesToCompute); } else { //[MS-SMB2] 3.1.5.1 //If Session.Connection.Dialect is "2.002" or "2.100", the receiver MUST compute a 32-byte hash by using HMAC-SHA256 over the entire message, //beginning with the SMB2 Header from step 2, and using the key provided. //The HMAC-SHA256 hash is specified in [FIPS180-2] and [RFC2104]. HMACSHA256 hmacSha = new HMACSHA256(cryptoInfo.SigningKey); computedSignature = hmacSha.ComputeHash(bytesToCompute); } packet.Header.Signature = originalSignature; //[MS-SMB2] 3.1.5.1 //If the first 16 bytes (the high-order portion) of the computed signature from step 3 or step 4 matches the saved signature from step 1, the message is signed correctly // compare the first 16 bytes of the originalSignature and computedSignature return(originalSignature.SequenceEqual(computedSignature.Take(16))); } catch (Exception ex) { throw new Exception("Error happened during signature verification of packet: " + packet.ToString() + ". Exception message: " + ex.Message); } }
public void SetupConnection(ModelDialectRevision maxSmbVersionClientSupported, ClientSupportsEncryptionType clientSupportsEncryptionType) { testClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site); testClient.ConnectToServer(testConfig.UnderlyingTransport, testConfig.SutComputerName, testConfig.SutIPAddress); testClient.Smb2Client.Disconnected += new Action(OnServerDisconnected); DialectRevision[] dialects = Smb2Utility.GetDialects(ModelUtility.GetDialectRevision(maxSmbVersionClientSupported)); //Set capabilities according to isClientSupportsEncryption Capabilities_Values commonCapability = Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES; Capabilities_Values encryptionCapability = (clientSupportsEncryptionType == ClientSupportsEncryptionType.ClientSupportsEncryption) ? (commonCapability | Capabilities_Values.GLOBAL_CAP_ENCRYPTION) : commonCapability; uint status; DialectRevision selectedDialect; NEGOTIATE_Response?negotiateResponse = null; status = testClient.Negotiate( dialects, testConfig.IsSMB1NegotiateEnabled, capabilityValue: encryptionCapability, checker: (header, response) => { Site.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should succeed", header.Command); negotiateResponse = response; }, ifHandleRejectUnencryptedAccessSeparately: true, ifAddGLOBAL_CAP_ENCRYPTION: false ); selectedDialect = negotiateResponse.Value.DialectRevision; if (Smb2Utility.IsSmb3xFamily(selectedDialect) && clientSupportsEncryptionType == ClientSupportsEncryptionType.ClientSupportsEncryption) { /// TD section 3.3.5.4 /// SMB2_GLOBAL_CAP_ENCRYPTION if Connection.Dialect belongs to the SMB 3.x dialect, the server supports encryption, /// and SMB2_GLOBAL_CAP_ENCRYPTION is set in the Capabilities field of the request Site.Assert.IsTrue( negotiateResponse.Value.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_ENCRYPTION), "SMB2_GLOBAL_CAP_ENCRYPTION should be set in the negotiate response."); } else { Site.Assert.IsFalse( negotiateResponse.Value.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_ENCRYPTION), "SMB2_GLOBAL_CAP_ENCRYPTION should not be set in the negotiate response."); } }
private static bool VerifySession(ModelSmb2Status status, ModelRequestType modelRequestType) { if (Smb2Utility.IsSmb3xFamily(negotiateDialect) && Session_EncryptData == SessionEncryptDataType.SessionEncryptDataSet && config.IsGlobalRejectUnencryptedAccessEnabled && modelRequestType == ModelRequestType.UnEncryptedRequest) { ModelHelper.Log(LogType.Requirement, "3.3.5.2.9: If Connection.Dialect belongs to the SMB 3.x dialect family, Session.EncryptData is TRUE, " + "and RejectUnencryptedAccess is TRUE, the server MUST locate the Request in Connection.RequestList " + "for which Request.MessageId matches the MessageId value in the SMB2 header of the request. " + "If Request.IsEncrypted is FALSE, the server MUST fail the request with STATUS_ACCESS_DENIED."); ModelHelper.Log(LogType.TestInfo, "All the above conditions are met."); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return(false); } return(true); }
public static void SignByteArray(Smb2CryptoInfo cryptoInfo, byte[] original, out byte[] nonce, out byte[] signature, Smb2Role role, Smb2Command smb2Command, UInt64 messageId = 1) { if (Smb2Utility.IsSmb2Family(cryptoInfo.Dialect)) { // [MS-SMB2] 3.1.4.1 // 3. If Connection.Dialect is "2.02" or "2.1", the sender MUST compute a 32-byte hash using HMAC-SHA256 over the entire message, HMACSHA256 hmacSha = new HMACSHA256(cryptoInfo.SigningKey); signature = hmacSha.ComputeHash(original); nonce = Array.Empty <byte>(); } else if (Smb2Utility.IsSmb3xFamily(cryptoInfo.Dialect)) { if (cryptoInfo.SigningId == SigningAlgorithm.AES_GMAC) { // [MS-SMB2] 3.1.4.1 // 1. If Connection.Dialect belongs to the SMB 3.x dialect family and Connection.SigningAlgorithmId is AES-GMAC, // compute a 16-byte hash using the AES-GMAC over the entire message using nonce as specified nonce = Smb2Utility.ComputeNonce(messageId, role, smb2Command); var(_, tag) = AesGmac.ComputeHash(cryptoInfo.SigningKey, nonce, original); signature = tag; } else { // [MS-SMB2] 3.1.4.1 // 2. If Connection.Dialect belongs to the SMB 3.x dialect family, the sender MUST compute a 16-byte hash using AES-128-CMAC over the entire message signature = AesCmac128.ComputeHash(cryptoInfo.SigningKey, original); nonce = Array.Empty <byte>(); } } else { nonce = Array.Empty <byte>(); signature = Array.Empty <byte>(); } }
public void OpenRequest( ModelDialectRevision clientMaxDialect, PersistentBitType persistentBit, CAShareType connectToCAShare, OplockLeaseType oplockLeaseType, DurableV1RequestContext durableV1RequestContext, DurableV2RequestContext durableV2RequestContext, DurableV1ReconnectContext durableV1ReconnectContext, DurableV2ReconnectContext durableV2ReconnectContext) { requestDialect = Smb2Utility.GetDialects(ModelUtility.GetDialectRevision(clientMaxDialect)); clientCapabilities = Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL; if (persistentBit == PersistentBitType.PersistentBitSet) { clientCapabilities |= Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES; } clientGuid = Guid.NewGuid(); requestedContext = oplockLeaseType; isCAShare = (connectToCAShare == CAShareType.CAShare); IPAddress targetIPAddress; string targetServer; #region Connect to Common Share or CA Share if (!isCAShare) { sharePath = Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); fileName = "PrepareHandle_ConnectTo_CommonShareFile_" + Guid.NewGuid() + ".txt"; targetIPAddress = testConfig.SutIPAddress; targetServer = testConfig.SutComputerName; } else { sharePath = Smb2Utility.GetUncPath(testConfig.CAShareServerName, testConfig.CAShareName); fileName = "PrepareHandle_ConnectTo_CAShareFile_" + Guid.NewGuid().ToString() + ".txt"; targetIPAddress = testConfig.CAShareServerIP; targetServer = testConfig.CAShareServerName; } testClientBeforeDisconnection = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site); testClientBeforeDisconnection.CreditGoal = 20; testClientBeforeDisconnection.ConnectToServer(testConfig.UnderlyingTransport, targetServer, targetIPAddress); testClientBeforeDisconnection.Negotiate( requestDialect, testConfig.IsSMB1NegotiateEnabled, capabilityValue: clientCapabilities, clientGuid: clientGuid, checker: (header, response) => { if (Smb2Utility.IsSmb3xFamily(response.DialectRevision) && handleConfig.IsPersistentHandleSupported && persistentBit == PersistentBitType.PersistentBitSet) { Site.Assert.IsTrue( response.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES), "The server MUST set SMB2_GLOBAL_CAP_PERSISTENT_HANDLES if Connection.Dialect belongs to the SMB 3.x dialect family, " + "SMB2_GLOBAL_CAP_PERSISTENT_HANDLES is set in the Capabilities field of the request, and the server supports persistent handles. " + "Actual capabilities are {0}", response.Capabilities); } }); testClientBeforeDisconnection.SessionSetup( testConfig.DefaultSecurityPackage, targetServer, testConfig.AccountCredential, testConfig.UseServerGssToken); testClientBeforeDisconnection.TreeConnect(sharePath, out treeIdBeforeDisconnection, delegate(Packet_Header responseHeader, TREE_CONNECT_Response response) { if (isCAShare) { if (!response.Capabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_CONTINUOUS_AVAILABILITY)) { // skip test case for CA share is invalid Site.Assert.Inconclusive("This test case is applicable only when CA share is valid."); } } }); #endregion #region Construct Create Contexts Smb2CreateContextRequest[] smb2CreateContextRequest = GetOpenFileCreateContext( durableV1RequestContext, durableV2RequestContext, durableV1ReconnectContext, durableV2ReconnectContext, oplockLeaseType, false, false); #endregion #region Send Create request according to different context combination RequestedOplockLevel_Values requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE; switch (oplockLeaseType) { case OplockLeaseType.NoOplockOrLease: { requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE; } break; case OplockLeaseType.BatchOplock: { requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH; } break; case OplockLeaseType.LeaseV1: case OplockLeaseType.LeaseV2: { requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE; } break; } FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; uint status = OpenCreate( testClientBeforeDisconnection, treeIdBeforeDisconnection, fileName, out fileId, out serverCreateContexts, requestedOplockLevel, smb2CreateContextRequest); #endregion DurableHandleResponseContext durableHandleResponse; LeaseResponseContext leaseResponse; CheckResponseContexts(serverCreateContexts, out durableHandleResponse, out leaseResponse); OpenResponse((ModelSmb2Status)status, durableHandleResponse, leaseResponse, handleConfig); testClientBeforeDisconnection.TreeDisconnect(treeIdAfterDisconnection, (header, response) => { }); testClientBeforeDisconnection.LogOff(); }
public void PrepareOpen( ModelDialectRevision clientMaxDialect, PersistentBitType persistentBit, CAShareType connectToCAShare, ModelHandleType modelHandleType, OplockLeaseType oplockLeaseType) { // Lease V2 cases only apply on the server implements SMB 3.x family. if (oplockLeaseType == OplockLeaseType.LeaseV2) { testConfig.CheckDialect(DialectRevision.Smb30); } // Lease V1 cases only apply on the server implements SMB 2.1 and 3.x family. if (oplockLeaseType == OplockLeaseType.LeaseV1) { testConfig.CheckDialect(DialectRevision.Smb21); } if ((oplockLeaseType == OplockLeaseType.LeaseV1 || oplockLeaseType == OplockLeaseType.LeaseV2) && !testConfig.IsLeasingSupported) { Site.Assert.Inconclusive("Test case is applicable in servers that support leasing."); } requestDialect = Smb2Utility.GetDialects(ModelUtility.GetDialectRevision(clientMaxDialect)); clientCapabilities = Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL; if (persistentBit == PersistentBitType.PersistentBitSet) { clientCapabilities |= Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES; } clientGuid = Guid.NewGuid(); requestedContext = oplockLeaseType; isCAShare = (connectToCAShare == CAShareType.CAShare); IPAddress targetIPAddress; string targetServer; #region Connect to Common Share or CA Share if (!isCAShare) { sharePath = Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); fileName = "PrepareHandle_ConnectTo_CommonShareFile_" + Guid.NewGuid() + ".txt"; targetIPAddress = testConfig.SutIPAddress; targetServer = testConfig.SutComputerName; } else { sharePath = Smb2Utility.GetUncPath(testConfig.CAShareServerName, testConfig.CAShareName); fileName = "PrepareHandle_ConnectTo_CAShareFile_" + Guid.NewGuid().ToString() + ".txt"; targetIPAddress = testConfig.CAShareServerIP; targetServer = testConfig.CAShareServerName; } testClientBeforeDisconnection = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site); testClientBeforeDisconnection.CreditGoal = 20; testClientBeforeDisconnection.ConnectToServer(testConfig.UnderlyingTransport, targetServer, targetIPAddress); testClientBeforeDisconnection.Negotiate( requestDialect, testConfig.IsSMB1NegotiateEnabled, capabilityValue: clientCapabilities, clientGuid: clientGuid, checker: (header, response) => { if (Smb2Utility.IsSmb3xFamily(response.DialectRevision) && handleConfig.IsPersistentHandleSupported && persistentBit == PersistentBitType.PersistentBitSet) { Site.Assert.IsTrue( response.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES), "The server MUST set SMB2_GLOBAL_CAP_PERSISTENT_HANDLES if Connection.Dialect belongs to the SMB 3.x dialect family, " + "SMB2_GLOBAL_CAP_PERSISTENT_HANDLES is set in the Capabilities field of the request, and the server supports persistent handles. " + "Actual capabilities are {0}", response.Capabilities); } }); testClientBeforeDisconnection.SessionSetup( testConfig.DefaultSecurityPackage, targetServer, testConfig.AccountCredential, testConfig.UseServerGssToken); testClientBeforeDisconnection.TreeConnect(sharePath, out treeIdBeforeDisconnection); #endregion #region Create operation according to the handle type and context Smb2CreateContextRequest[] prepareRequestContext = null; Smb2CreateContextResponse[] serverCreateContexts = null; RequestedOplockLevel_Values requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE; switch (oplockLeaseType) { case OplockLeaseType.LeaseV1: { testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); prepareRequestContext = GetPrepareOpenCreateContext(modelHandleType, oplockLeaseType); requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE; } break; case OplockLeaseType.LeaseV2: { testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2); prepareRequestContext = GetPrepareOpenCreateContext(modelHandleType, oplockLeaseType); requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE; } break; case OplockLeaseType.BatchOplock: { prepareRequestContext = GetPrepareOpenHandleContext(modelHandleType); requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH; } break; case OplockLeaseType.NoOplockOrLease: { prepareRequestContext = GetPrepareOpenHandleContext(modelHandleType); requestedOplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE; } break; } PrepareOpenCreate( testClientBeforeDisconnection, treeIdBeforeDisconnection, fileName, out fileIdBeforDisconnection, out serverCreateContexts, requestedOplockLevel, prepareRequestContext); #endregion }
private void ReadFromAlternativeChannel( DialectRevision[] requestDialect, DialectRevision expectedDialect, IPAddress serverIp, IPAddress clientIp, uint lengthRead, uint treeId, FILEID fileId, out string contentRead) { contentRead = ""; alternativeChannelClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, serverIp, clientIp); #region Negotiate status = alternativeChannelClient.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES, clientGuid: clientGuid, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); TestConfig.CheckNegotiateDialect(expectedDialect, response); if (Smb2Utility.IsSmb3xFamily(expectedDialect)) { TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL, response); } }); #endregion #region SESSION_SETUP status = alternativeChannelClient.AlternativeChannelSessionSetup( mainChannelClient, TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken, checker: (header, response) => { }); #endregion if (expectedDialect == DialectRevision.Smb2002 || expectedDialect == DialectRevision.Smb21) { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_REQUEST_NOT_ACCEPTED, status, "SessionSetup is expected to fail with STATUS_REQUEST_NOT_ACCEPTED."); BaseTestSite.Log.Add( LogEntryKind.Debug, "Dialect " + expectedDialect + " is not supported for multiple channel and fail as expected with STATUS_REQUEST_NOT_ACCEPTED."); } else { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, status, "SessionSetup should succeed"); #region READ status = alternativeChannelClient.Read(treeId, fileId, 0, lengthRead, out contentRead); #endregion #region CLOSE file status = alternativeChannelClient.Close(treeId, fileId); #endregion #region TREE_DISCONNECT status = alternativeChannelClient.TreeDisconnect(treeId); #endregion #region LOGOFF status = alternativeChannelClient.LogOff(); #endregion } alternativeChannelClient.Disconnect(); }
private void WriteFromMainChannel( DialectRevision[] requestDialect, DialectRevision expectedDialect, IPAddress serverIp, IPAddress clientIp, string contentWrite, bool isNicRedundantOnServer, out uint treeId, out FILEID fileId) { mainChannelClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, serverIp, clientIp); #region Negotiate mainChannelClient.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES, clientGuid: clientGuid, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); TestConfig.CheckNegotiateDialect(expectedDialect, response); if (Smb2Utility.IsSmb3xFamily(expectedDialect)) { TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL, response); } }); #endregion #region SESSION_SETUP mainChannelClient.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region Retrieve 2nd IP on server for alternative channel if there is if (TestConfig.UnderlyingTransport == Smb2TransportType.Tcp && isNicRedundantOnServer && TestConfig.IsIoCtlCodeSupported(CtlCode_Values.FSCTL_QUERY_NETWORK_INTERFACE_INFO)) { #region TREE_CONNECT to IPC$ string ipcPath = Smb2Utility.GetIPCPath(TestConfig.SutComputerName); mainChannelClient.TreeConnect(ipcPath, out treeId); #endregion #region IOCTL FSCTL_QUERY_NETWORK_INTERFACE_INFO NETWORK_INTERFACE_INFO_Response[] networkInfoResponses; string interfaceAddress; bool secondAddressQueried = false; mainChannelClient.QueryNetworkInterfaceInfo(treeId, out networkInfoResponses); foreach (NETWORK_INTERFACE_INFO_Response netInfoResp in networkInfoResponses) { interfaceAddress = netInfoResp.AddressStorage.Address; if (interfaceAddress != null) { BaseTestSite.Log.Add(LogEntryKind.Debug, "Get NETWORK_INTERFACE_INFO: " + interfaceAddress); if (interfaceAddress == serverIps[1].ToString()) { secondAddressQueried = true; BaseTestSite.Log.Add(LogEntryKind.Debug, "Address queried by IOCTL request with FSCTL_QUERY_NETWORK_INTERFACE_INFO matches server second address {0}", serverIps[1].ToString()); break; } } } BaseTestSite.Assert.IsTrue( secondAddressQueried, "Second address {0} should be queried by IOCTL request with FSCTL_QUERY_NETWORK_INTERFACE_INFO", serverIps[1].ToString()); #endregion } #endregion #region TREE_CONNECT to share string uncSharePath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare); mainChannelClient.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE Smb2CreateContextResponse[] serverCreateContexts; mainChannelClient.Create( treeId, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE, out fileId, out serverCreateContexts); #endregion if (Smb2Utility.IsSmb3xFamily(expectedDialect)) { #region WRITE mainChannelClient.Write(treeId, fileId, contentWrite); #endregion } }
private static bool VerifyTreeConnect(ModelSmb2Status status, ModelRequestType modelRequestType, EncryptionConfig c) { ModelHelper.Log(LogType.Requirement, "3.3.5.2.11 Verifying the Tree Connect"); if (Encryption_TreeId == EncryptionTreeId.NoTreeId) { ModelHelper.Log(LogType.Requirement, "The server MUST look up the TreeConnect in Session.TreeConnectTable by using the TreeId in the SMB2 header of the request. " + "If no tree connect is found, the request MUST be failed with STATUS_NETWORK_NAME_DELETED."); ModelHelper.Log(LogType.TestInfo, "No tree connect is found."); ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier); Condition.IsTrue(status == ModelSmb2Status.STATUS_NETWORK_NAME_DELETED); return(false); } if (Smb2Utility.IsSmb3xFamily(negotiateDialect)) { ModelHelper.Log(LogType.Requirement, "If the Connection.Dialect belongs to the SMB 3.x dialect family, the server MUST fail the request with STATUS_ACCESS_DENIED in the following cases"); ModelHelper.Log(LogType.TestInfo, "The Connection.Dialect is {0}.", negotiateDialect); // Actually the "EncryptData is true" is redundant since it would failed in verify session step if (Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION && ((config.MaxSmbVersionSupported == ModelDialectRevision.Smb311 && Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare) || ((config.MaxSmbVersionSupported == ModelDialectRevision.Smb30 || config.MaxSmbVersionSupported == ModelDialectRevision.Smb302) && (Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare || config.IsGlobalEncryptDataEnabled) && config.IsGlobalRejectUnencryptedAccessEnabled)) && modelRequestType == ModelRequestType.UnEncryptedRequest) { ModelHelper.Log(LogType.Requirement, "\tServer supports the 3.1.1 dialect, TreeConnect.Share.EncryptData is TRUE, " + "Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION, and Request.IsEncrypted is FALSE\n" + "\tServer supports the 3.0 or 3.0.2 dialect, EncryptData or TreeConnect.Share.EncryptData is TRUE, " + "Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION, RejectUnencryptedAccess is TRUE, " + "and Request.IsEncrypted is FALSE"); ModelHelper.Log(LogType.TestInfo, "Server supports {0}, RejectUnencryptedAccess is {1}", config.MaxSmbVersionSupported, config.IsGlobalRejectUnencryptedAccessEnabled ? "TRUE" : "FALSE"); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return(false); } if ((config.IsGlobalEncryptDataEnabled || Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare || modelRequestType == ModelRequestType.EncryptedRequest) && config.IsGlobalRejectUnencryptedAccessEnabled && !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION) { ModelHelper.Log(LogType.Requirement, "\tEncryptData or TreeConnect.Share.EncryptData or Request.IsEncrypted is TRUE, RejectUnencryptedAccess is TRUE, " + "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION."); ModelHelper.Log(LogType.TestInfo, "The server implements {0}, EncryptData is {1}, TreeConnect.Share.EncryptData is {2}, " + "Request.IsEncrypted is {3}, RejectUnencryptedAccess is TRUE, " + "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.", config.MaxSmbVersionSupported, config.IsGlobalEncryptDataEnabled, Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare ? "TRUE" : "FALSE", modelRequestType == ModelRequestType.EncryptedRequest ? "TRUE" : "FALSE"); ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", config.Platform); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return(false); } } return(true); }
public static void TreeConnectResponse( ModelSmb2Status status, ShareEncryptDataType shareEncryptDataType, ModelResponseType modelResponseType, EncryptionConfig c) { Condition.IsTrue(state == ModelState.Connected); Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled); Condition.IsTrue(Session_IsExisted); ModelTreeConnectRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest <ModelTreeConnectRequest>(ref request); if (!VerifySession(status, treeConnectRequest.modelRequestType, c)) { return; } if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported) && (config.IsGlobalEncryptDataEnabled || treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare) && config.IsGlobalRejectUnencryptedAccessEnabled && !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION) { ModelHelper.Log(LogType.Requirement, "3.3.5.7: If the server implements the SMB 3.x dialect family, EncryptData or Share.EncryptData is TRUE, " + "RejectUnencryptedAccess is TRUE, and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION, " + "the server MUST fail the request with STATUS_ACCESS_DENIED."); Condition.IsTrue(config.Platform == c.Platform); ModelHelper.Log(LogType.TestInfo, "The server implements {0}, EncryptData is {1}, Share.EncryptData is {2}, RejectUnencryptedAccess is TRUE, " + "Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.", config.MaxSmbVersionSupported, config.IsGlobalEncryptDataEnabled, treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare ? "TRUE" : "FALSE"); ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", config.Platform); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return; } if (Smb2Utility.IsSmb3xFamily(negotiateDialect) && treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare && config.IsGlobalRejectUnencryptedAccessEnabled && !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION) { ModelHelper.Log(LogType.Requirement, "3.3.5.7: If Connection.Dialect belongs to the SMB 3.x dialect family, " + "Share.EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " + "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION, " + "the server MUST fail the request with STATUS_ACCESS_DENIED."); ModelHelper.Log(LogType.Requirement, "\tSet the SMB2_SHAREFLAG_ENCRYPT_DATA bit."); ModelHelper.Log(LogType.TestInfo, "Connection.Dialect is {0}, and Share.EncryptData is TRUE.", negotiateDialect); Condition.IsTrue(shareEncryptDataType == ShareEncryptDataType.ShareEncryptDataSet); } //TODO: To be implemented after TRANSFORM_HEADER added into Smb2FunctionalClient if (treeConnectRequest.modelRequestType == ModelRequestType.EncryptedRequest) { Condition.IsTrue(modelResponseType == ModelResponseType.EncryptedResponse); } else { Condition.IsTrue(modelResponseType == ModelResponseType.UnEncryptedResponse); } Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS); Encryption_TreeId = (treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare) ? EncryptionTreeId.TreeIdToEncryptShare : EncryptionTreeId.TreeIdToUnEncryptShare; }
public static void SessionSetupResponse(ModelSmb2Status status, SessionEncryptDataType sessionEncryptDataType, EncryptionConfig c) { Condition.IsTrue(state == ModelState.Connected); Condition.IsTrue(config.IsGlobalEncryptDataEnabled == c.IsGlobalEncryptDataEnabled); Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled); if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported) && !Smb2Utility.IsSmb3xFamily(negotiateDialect) && config.IsGlobalEncryptDataEnabled && config.IsGlobalRejectUnencryptedAccessEnabled) { ModelHelper.Log(LogType.Requirement, "3.3.5.5: 1. If the server implements the SMB 3.x dialect family, " + "Connection.Dialect does not belong to the SMB 3.x dialect family, EncryptData is TRUE, " + "and RejectUnencryptedAccess is TRUE, the server MUST fail the request with STATUS_ACCESS_DENIED."); ModelHelper.Log(LogType.TestInfo, "The server implements {0}, Connection.Dialect is {1}, EncryptData is TRUE and RejectUnencryptedAccess is TRUE", config.MaxSmbVersionSupported, negotiateDialect); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return; } if (Smb2Utility.IsSmb3xFamily(negotiateDialect) && config.IsGlobalEncryptDataEnabled && config.IsGlobalRejectUnencryptedAccessEnabled && !Connection_ClientCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION) { ModelHelper.Log(LogType.Requirement, "3.3.5.5: 2. If Connection.Dialect belongs to the SMB 3.x dialect family, " + "EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " + "and Connection.ClientCapabilities does not include the SMB2_GLOBAL_CAP_ENCRYPTION bit, " + "the server MUST fail the request with STATUS_ACCESS_DENIED."); ModelHelper.Log(LogType.TestInfo, "Connection.Dialect is {0}, EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " + "and Connection.ClientCapabilities does not include the SMB2_GLOBAL_CAP_ENCRYPTION bit.", negotiateDialect); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED); return; } if (Smb2Utility.IsSmb3xFamily(negotiateDialect) && config.IsGlobalEncryptDataEnabled && (Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION || config.IsGlobalRejectUnencryptedAccessEnabled)) { ModelHelper.Log(LogType.Requirement, "3.3.5.5.3: 10. If global EncryptData is TRUE, the server MUST do the following: " + "If Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION or RejectUnencryptedAccess is TRUE,"); Condition.IsTrue(sessionEncryptDataType == SessionEncryptDataType.SessionEncryptDataSet); Session_EncryptData = SessionEncryptDataType.SessionEncryptDataSet; } Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS); Session_IsExisted = true; }
public void MultipleChannel_SecondChannelSessionSetupFailAtFirstTime() { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb311); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL); #endregion string contentWrite; string contentRead; uint treeId; FILEID fileId; contentWrite = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb); BaseTestSite.Assert.IsTrue( clientIps.Count > 0, "Client should have at least one IP address"); BaseTestSite.Assert.IsTrue( serverIps.Count > 0, "Server should have more than one IP address"); BaseTestSite.Log.Add( LogEntryKind.TestStep, "Start to write content to file from main channel with client {0} and server {1}", clientIps[0].ToString(), serverIps[0].ToString()); WriteFromMainChannel( serverIps[0], clientIps[0], contentWrite, false, out treeId, out fileId); BaseTestSite.Log.Add( LogEntryKind.TestStep, "Set up alternative channel with client {0} and server {1}", clientIps[0].ToString(), serverIps[0].ToString()); alternativeChannelClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, serverIps[1], clientIps[1]); alternativeChannelClient.Negotiate( TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES, clientGuid: clientGuid, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); TestConfig.CheckNegotiateDialect(DialectRevision.Smb311, response); if (Smb2Utility.IsSmb3xFamily(DialectRevision.Smb311)) { TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL, response); } }); status = alternativeChannelClient.AlternativeChannelSessionSetup( mainChannelClient, TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken, checker: (header, response) => { }, invalidToken: true); BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_INVALID_PARAMETER, status, "The first SessionSetup from alternative channel should return STATUS_INVALID_PARAMETER since the token in buffer field is set to an invalid value."); status = alternativeChannelClient.AlternativeChannelSessionSetup( mainChannelClient, TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken, checker: (header, response) => { }); BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "The second SessionSetup from alternative channel should succeed"); contentRead = ""; status = alternativeChannelClient.Read(treeId, fileId, 0, (uint)contentWrite.Length, out contentRead); // Read should succeed. // If Read response returns STATUS_ACCESS_DEINIED, it means signingkey used by server is wrong, and so that the PreauthIntegrityHashValue (which is used to generate the signingkey) calculated by server is wrong. // It is very possible that server uses the first failed session setup request/response (alternative channel) to calculate PreauthIntegrityHashValue, which is wrong. BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Read from the alternative channel should succeed"); alternativeChannelClient.Close(treeId, fileId); alternativeChannelClient.TreeDisconnect(treeId); alternativeChannelClient.LogOff(); BaseTestSite.Log.Add( LogEntryKind.TestStep, "Verify the contents read from alternative channel are the same as the one written by main channel."); BaseTestSite.Assert.IsTrue( contentWrite.Equals(contentRead), "Content read should be identical to content written."); }
public static void CreateResponse(ModelSmb2Status status, ReturnLeaseContextType returnLeaseContextType, uint leaseState, LeaseFlagsValues leaseFlags, LeasingConfig c) { Condition.IsTrue(state == ModelState.Connected); ModelCreateLeaseRequest createRequest = ModelHelper.RetrieveOutstandingRequest <ModelCreateLeaseRequest>(ref request); Condition.IsTrue(config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported); Condition.IsTrue(config.IsLeasingSupported == c.IsLeasingSupported); if (!c.IsLeasingSupported) { ModelHelper.Log( LogType.Requirement, "3.3.5.9: If the server does not support leasing and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST ignore the \"RqLs\" create context."); ModelHelper.Log(LogType.TestInfo, "The above conditions are met."); ModelHelper.Log(LogType.TestTag, TestTag.Compatibility); Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded); return; } if ((negotiateDialect == DialectRevision.Smb21 || Smb2Utility.IsSmb3xFamily(negotiateDialect)) && c.IsLeasingSupported && (createRequest.ContextType == LeaseContextType.LeaseV1)) // the DataLength field equals 0x20 { ModelHelper.Log( LogType.Requirement, "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " + "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:"); ModelHelper.Log( LogType.Requirement, "\tIf Connection.Dialect is \"2.100\" or belongs to the \"3.x\" dialect family, and the DataLength field equals 0x20, " + "the server MUST attempt to acquire a lease on the open from the underlying object store as described in section 3.3.5.9.8."); ModelHelper.Log(LogType.TestInfo, "All the above conditions are met."); // 3.3.5.9.8 Handling the SMB2_CREATE_REQUEST_LEASE Create Context #region Handle SMB2_CREATE_REQUEST_LEASE Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded); ModelCreateRequestLease requestLease = null; requestLease = createRequest.LeaseContext as ModelCreateRequestLease; smb2Lease = new Smb2Lease(); if (Smb2Utility.IsSmb3xFamily(negotiateDialect)) { ModelHelper.Log(LogType.Requirement, "3.3.5.9.8: If Connection.Dialect belongs to the SMB 3.x dialect family, Lease.Version is set to 1."); smb2Lease.Version = 1; } if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking) { ModelHelper.Log( LogType.Requirement, "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " + "the server MUST request promotion of the lease state from the underlying object store to the new caching state."); ModelHelper.Log(LogType.TestInfo, "The above conditions are met."); //If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state. smb2Lease.LeaseState = requestLease.LeaseState; } // LeaseState MUST be set to Lease.LeaseState. Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState); #endregion Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS); return; } if (Smb2Utility.IsSmb3xFamily(negotiateDialect) && c.IsLeasingSupported && (createRequest.ContextType == LeaseContextType.LeaseV2)) // the DataLength field equals 0x34 { ModelHelper.Log( LogType.Requirement, "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " + "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:"); ModelHelper.Log( LogType.Requirement, "\tIf Connection.Dialect belongs to the \"3.x\" dialect family, and the DataLength field equals 0x34, " + "the server MUST attempt to acquire a lease on the open from the underlying object store, as described in section 3.3.5.9.11."); ModelHelper.Log(LogType.TestInfo, "All the above conditions are met."); // 3.3.5.9.11 Handling the SMB2_CREATE_REQUEST_LEASE_V2 Create Context #region Handle SMB2_CREATE_REQUEST_LEASE_V2 Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded); ModelCreateRequestLeaseV2 requestLease = null; requestLease = createRequest.LeaseContext as ModelCreateRequestLeaseV2; smb2Lease = new Smb2Lease(2); // To reduce parameters and states, use CreateOptions instead of FileAttributes here, as we assume settings in CreateOptions and FileAtributes are consistent. if (createRequest.CreateOptions.HasFlag(CreateOptions_Values.FILE_DIRECTORY_FILE) && (requestLease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING) != 0) { ModelHelper.Log( LogType.Requirement, "3.3.5.9.11: If the FileAttributes field in the request indicates that this operation is on a directory and " + "LeaseState includes SMB2_LEASE_WRITE_CACHING, the server MUST clear the bit SMB2_LEASE_WRITE_CACHING in the LeaseState field."); ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_WRITE_CACHING is cleared."); requestLease.LeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING; } if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking) { ModelHelper.Log( LogType.Requirement, "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " + "the server MUST request promotion of the lease state from the underlying object store to the new caching state.<271> " + "If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state."); smb2Lease.LeaseState = requestLease.LeaseState; // The server MUST increment Lease.Epoch by 1. ModelHelper.Log(LogType.TestInfo, "Lease.Epoch is incremented by 1."); smb2Lease.Epoch++; } // LeaseState MUST be set to Lease.LeaseState. Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState); if (requestLease.LeaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET)) { ModelHelper.Log( LogType.Requirement, "3.3.5.9.11: If SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set in the Flags field of the request, " + "ParentLeaseKey MUST be set to the ParentLeaseKey in the request and SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit MUST be set in the Flags field of the response."); ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set."); Condition.IsTrue(leaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET)); } #endregion Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS); return; } Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded); Condition.IsTrue(leaseState == (uint)LeaseStateValues.SMB2_LEASE_NONE); Condition.IsTrue(leaseFlags == LeaseFlagsValues.NONE); Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS); }
/// <summary> /// Verify the signature of a Smb2SinglePacket /// </summary> /// <param name="packet">The packet to be verified</param> /// <param name="cryptoInfo">The cryptoInfo of smb2client</param> /// <returns>True when signature verification succeeds and false when fails</returns> private bool VerifySignature(Smb2SinglePacket packet, Smb2CryptoInfo cryptoInfo, byte[] messageBytes) { if (cryptoInfo.DisableVerifySignature) { // Skip the verification. return(true); } try { if (IsErrorPacket(packet.Header)) { packet = packet.Error; } byte[] bytesToCompute = messageBytes; // Zero out the 16-byte signature field in the SMB2 Header of the incoming message. Array.Clear(bytesToCompute, System.Runtime.InteropServices.Marshal.SizeOf(packet.Header) - Smb2Consts.SignatureSize, Smb2Consts.SignatureSize); //Compute the message with signing key byte[] computedSignature = null; if (Smb2Utility.IsSmb3xFamily(cryptoInfo.Dialect)) { //[MS-SMB2] 3.1.5.1 //If Session.Connection.Dialect belongs to the SMB 3.x dialect family, //the receiver MUST compute a 16-byte hash by using AES-128-CMAC over the entire message, //beginning with the SMB2 Header from step 2, and using the key provided. //The AES-128-CMAC is specified in [RFC4493]. //TD has mentioned to use Session.SigningKey for SESSION_SETUP Response and Channel.SigningKey for other responses //In the current SDK, the SigningKey is the Channel.SigningKey if (cryptoInfo.SigningId == SigningAlgorithm.AES_GMAC) { var nonce = Smb2Utility.ComputeNonce(packet, this.decodeRole); var(_ciphertext, tag) = AesGmac.ComputeHash(cryptoInfo.SigningKey, nonce, bytesToCompute); computedSignature = tag; } else { computedSignature = AesCmac128.ComputeHash(cryptoInfo.SigningKey, bytesToCompute); } } else { //[MS-SMB2] 3.1.5.1 //If Session.Connection.Dialect is "2.002" or "2.100", the receiver MUST compute a 32-byte hash by using HMAC-SHA256 over the entire message, //beginning with the SMB2 Header from step 2, and using the key provided. //The HMAC-SHA256 hash is specified in [FIPS180-2] and [RFC2104]. HMACSHA256 hmacSha = new HMACSHA256(cryptoInfo.SigningKey); computedSignature = hmacSha.ComputeHash(bytesToCompute); } //[MS-SMB2] 3.1.5.1 //If the first 16 bytes (the high-order portion) of the computed signature from step 3 or step 4 matches the saved signature from step 1, the message is signed correctly // compare the first 16 bytes of the originalSignature and computedSignature return(packet.Header.Signature.SequenceEqual(computedSignature.Take(Smb2Consts.SignatureSize))); } catch (Exception ex) { throw new Exception("Error happened during signature verification of packet: " + packet.ToString() + ". Exception message: " + ex.Message); } }