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);
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #5
0
        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);
        }
Beispiel #15
0
        /// <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);
            }
        }