/// <summary>
        /// Get the pccrtp response with http header "peerdist".
        /// </summary>
        /// <param name="serverAddress"> The content server address.</param>
        /// <param name="port"> The port that the content server is listening.</param>
        /// <param name="uri"> The path of the file to request.</param>
        /// <returns>Only true can be returned that specifies the pccrtp response with
        /// http header "peerdist" is received.</returns>
        /// <exception cref="Exception">No http response with "peerdist" header is received,</exception>
        private bool GetPccrtpResponse(string serverAddress, int port, string uri)
        {
            PccrtpRequest  pccrtpRequest      = this.pccrtpStackClient.CreatePccrtpRequest(serverAddress, port, uri);
            PccrtpResponse pccrtpResponseTemp = this.pccrtpStackClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                int.Parse(Site.Properties["PCCRTP.Protocol.TimeOut"]) * 1000);
            int timesOfSendingPccrtpMsg = 1;

            while (!pccrtpResponseTemp.HttpResponse.ContentEncoding.Equals("peerdist"))
            {
                if (timesOfSendingPccrtpMsg >= 3)
                {
                    throw new InvalidOperationException(string.Format(
                                                            "Send {0} times Pccrtp request message, no http response with \"peerdist\" header is received.",
                                                            timesOfSendingPccrtpMsg));
                }

                pccrtpResponseTemp = this.pccrtpStackClient.SendHttpRequest(
                    Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                    pccrtpRequest,
                    int.Parse(Site.Properties["PCCRTP.Protocol.TimeOut"]) * 1000);
                timesOfSendingPccrtpMsg++;
            }

            this.pccrtpResponse = pccrtpResponseTemp;
            return(true);
        }
Пример #2
0
        /// <summary>
        /// Generate and send an PCCRTP response message to the HTTP/1.1 client (SUT) when testing client endpoint.
        /// </summary>
        /// <param name="requestFileFullPath">Indicate that local full path of the requested file on the driver computer.
        /// </param>
        public void SendPccrtpResponseMessage(string requestFileFullPath)
        {
            PccrtpResponse pccrtpResponse = this.pccrtpServerStack.GenerateResponseMessage(
                requestFileFullPath,
                Site.Properties["PCCRTP.Protocol.ServerSecret"]);

            this.pccrtpServerStack.SentPccrtpResponse(pccrtpResponse);
        }
        /// <summary>
        /// Reset the adapter
        /// </summary>
        public override void Reset()
        {
            base.Reset();

            this.isReceived     = false;
            this.pccrtpResponse = null;
            if (this.pccrrServer != null)
            {
                this.pccrrServer.CloseConnections();
                this.pccrrServer = null;
            }
        }
Пример #4
0
        public void ContentServer_PccrtpServer_ContentInformationVersionIncompatible()
        {
            CheckApplicability();

            PccrtpClient  pccrtpClient  = new PccrtpClient();
            PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest(
                testConfig.ContentServerComputerName,
                testConfig.ContentServerHTTPListenPort,
                testConfig.NameOfFileWithMultipleBlocks,
                BranchCacheVersion.V2);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Send PCCRTP request to trigger hash generation");

            PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                (int)testConfig.Timeout.TotalMilliseconds);

            var contentBeforeHashGeneration = pccrtpResponse.PayloadData;

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Wait until the hash is generated on content server");

            TestUtility.DoUntilSucceed(() => sutControlAdapter.IsHTTPHashExisted(testConfig.ContentServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Modify to an incompatible version");

            pccrtpRequest.HttpHeader[PccrtpConsts.XP2PPeerDistExHttpHeader] = "MinContentInformation=900.0, MaxContentInformation=999.0";

            pccrtpResponse = pccrtpClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                (int)testConfig.Timeout.TotalMilliseconds);

            var contentAfterHashGeneration = pccrtpResponse.PayloadData;

            BaseTestSite.Assert.AreNotEqual(
                "peerdist",
                pccrtpResponse.HttpResponse.ContentEncoding,
                "The content server should return file content when content information version is incompatible");

            BaseTestSite.Assert.IsTrue(
                contentAfterHashGeneration.SequenceEqual(contentBeforeHashGeneration),
                "The content server should return file content when content information version is incompatible");
        }
        /// <summary>
        /// Verify requirements about content information structure.
        /// </summary>
        /// <param name="pccrtpResponse">The PCCRTP response message.</param>
        private void VerifyContentInfomationStructure(PccrtpResponse pccrtpResponse)
        {
            Site.DefaultProtocolDocShortName = "MS-PCCRC";

            this.VerifyContentSegmentsBlocks(pccrtpResponse);

            this.VerifySegmentIdentifiersAndKeys(pccrtpResponse);

            this.VerifyDataStructure(pccrtpResponse);

            this.VerifySegmentDescription(pccrtpResponse);

            this.VerifySegmentContentBlocks(pccrtpResponse);

            Site.DefaultProtocolDocShortName = "MS-PCCRTP";
        }
        /// <summary>
        /// Get the segment IDs computed using content information that is got from the content server.
        /// </summary>
        /// <param name="serverAddress"> The content server address.</param>
        /// <param name="port"> The port that the content server is listening.</param>
        /// <param name="path"> The path of the file to request.</param>
        /// <returns> Returns content info if success.</returns>
        public string[] GetSegmentIds(string serverAddress, int port, string path)
        {
            PccrtpRequest  pccrtpRequest       = this.pccrtpStackClient.CreatePccrtpRequest(serverAddress, port, path);
            PccrtpResponse pccrtpStackResponse = this.pccrtpStackClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                int.Parse(Site.Properties["PCCRR.Protocol.timeout"]) * 1000);
            List <byte[]> segmentIDs = (List <byte[]>) this.pccrtpStackClient.GetSegmentId(pccrtpStackResponse);

            List <string> segmentIdStr = new List <string>();

            foreach (byte[] segmentId in segmentIDs)
            {
                segmentIdStr.Add(ToHexString(segmentId));
            }

            return(segmentIdStr.ToArray());
        }
Пример #7
0
        public void ContentServer_PccrtpServer_MissingDataRequestFalse()
        {
            CheckApplicability();

            PccrtpClient  pccrtpClient  = new PccrtpClient();
            PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest(
                testConfig.ContentServerComputerName,
                testConfig.ContentServerHTTPListenPort,
                testConfig.NameOfFileWithMultipleBlocks);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Send PCCRTP request to trigger hash generation");

            PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                (int)testConfig.Timeout.TotalMilliseconds);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Wait until the hash is generated on content server");

            TestUtility.DoUntilSucceed(() => sutControlAdapter.IsHTTPHashExisted(testConfig.ContentServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Modify to an incompatible version");

            pccrtpRequest.HttpHeader[PccrtpConsts.XP2PPeerDistHttpHeader] = "Version=1.0, MissingDataRequest=false";

            pccrtpResponse = pccrtpClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                (int)testConfig.Timeout.TotalMilliseconds);

            BaseTestSite.Assert.AreEqual(
                "peerdist",
                pccrtpResponse.HttpResponse.ContentEncoding,
                "The content server should return content information when MissingDataRequest is false");
        }
        /// <summary>
        /// Send a PCCRTP request message and receive a PCCRTP response message.
        /// </summary>
        /// <param name="httpVersion">Indicates the HTTP version type used.</param>
        /// <param name="isRequestPartialContent">Indicates it is requesting partical content or not.</param>
        /// <param name="uri">Indicates the URI on the SUT requested by the client.</param>
        /// <returns>Return the PCCRTP response message received.</returns>
        public PccrtpResponse SendPccrtpRequestMessage(
            HttpVersionType httpVersion,
            bool isRequestPartialContent,
            string uri)
        {
            PccrtpRequest  pccrtpRequest  = new PccrtpRequest();
            PccrtpResponse pccrtpResponse = new PccrtpResponse();
            string         serverAddress  = this.GetProperty("Environment.ContentServer.MachineName");
            int            port           = int.Parse(this.GetProperty("Environment.ContentServer.HTTP.Port"));
            int            timeOut        = (int)TimeSpan.FromSeconds(
                double.Parse(this.GetProperty("PCCRTP.Protocol.TimeOut"))).TotalMilliseconds;
            int rangeFrom = int.Parse(this.GetProperty("PCCRTP.Protocol.RangeFrom"));
            int rangeTo   = int.Parse(this.GetProperty("PCCRTP.Protocol.RangeTo"));

            if (isRequestPartialContent)
            {
                pccrtpRequest  = this.pccrtpClientStack.CreatePccrtpRequest(serverAddress, port, uri);
                pccrtpResponse = this.pccrtpClientStack.SendHttpRequest(
                    httpVersion,
                    pccrtpRequest,
                    timeOut,
                    rangeFrom,
                    rangeTo);
            }
            else
            {
                pccrtpRequest  = this.pccrtpClientStack.CreatePccrtpRequest(serverAddress, port, uri);
                pccrtpResponse = this.pccrtpClientStack.SendHttpRequest(httpVersion, pccrtpRequest, timeOut);
            }

            if (pccrtpResponse.HttpResponse.ContentEncoding.Equals("peerdist"))
            {
                PccrtpBothRoleCapture.VerifyTransport(pccrtpResponse.HttpResponse.ProtocolVersion.ToString());
                PccrtpBothRoleCapture.VerifyPccrtpCommonHeader(pccrtpResponse.HttpHeader);
                this.VerifyPccrtpResponse(pccrtpResponse);
                this.VerifyContentInfomationStructure(pccrtpResponse);
            }

            return(pccrtpResponse);
        }
Пример #9
0
        public void ContentServer_PccrtpServer_ContentEncodingNotHavePeerDist()
        {
            CheckApplicability();

            PccrtpClient  pccrtpClient  = new PccrtpClient();
            PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest(
                testConfig.ContentServerComputerName,
                testConfig.ContentServerHTTPListenPort,
                testConfig.NameOfFileWithMultipleBlocks);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Send PCCRTP request to trigger hash generation");

            PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest(
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                pccrtpRequest,
                (int)testConfig.Timeout.TotalMilliseconds);

            var contentBeforeHashGeneration = pccrtpResponse.PayloadData;

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Wait until the hash is generated on content server");

            TestUtility.DoUntilSucceed(() => sutControlAdapter.IsHTTPHashExisted(testConfig.ContentServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Send HTTP request again without peerdist Accept-Encoding");

            var contentAfterHashGeneration = TestUtility.DownloadHTTPFile(testConfig.ContentServerComputerName, testConfig.NameOfFileWithMultipleBlocks);

            BaseTestSite.Assert.IsTrue(
                contentAfterHashGeneration.SequenceEqual(contentBeforeHashGeneration),
                "The content server should return file content when peerdist is not included in Accept-Encoding");
        }
Пример #10
0
        private void executeButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (!CheckInput())
                {
                    return;
                }

                logger.Clear();

                #region Read settings from UI

                var version       = (BranchCacheVersion)branchCacheVersionComboBox.SelectedItem;
                var operationMode = (OperationMode)operationModeComboBox.SelectedItem;
                var transport     = (ContentInformationTransport)transportComboBox.SelectedItem;

                var serverSecret = serverSecretTextBox.Text;
                var filePath     = filePathTextBox.Text;

                var           hashAlgoValue = (dwHashAlgo_Values)hashAlgorithmComboBox.SelectedItem;
                HashAlgorithm hashAlgorithm;
                HMAC          hmacAlgorithm;
                int           hashBlockSize;

                string server        = null;
                string file          = null;
                string sharedFolder  = null;
                Match  filePathMatch = null;
                switch (transport)
                {
                case ContentInformationTransport.PCCRTP:
                    filePathMatch = Regex.Match(filePath, httpFilePathPattern);
                    server        = filePathMatch.Groups["Server"].Value;
                    file          = filePathMatch.Groups["FileName"].Value;
                    break;

                case ContentInformationTransport.SMB2:
                    filePathMatch = Regex.Match(filePath, smb2FilePathPattern);
                    server        = filePathMatch.Groups["Server"].Value;
                    sharedFolder  = filePathMatch.Groups["SharedFolder"].Value;
                    file          = filePathMatch.Groups["FileName"].Value;
                    break;

                default:
                    throw new NotImplementedException();
                }


                SecurityPackageType securityPackageType = (SecurityPackageType)smb2AuthenticationComboBox.SelectedItem;

                string domainName   = domainNameTextBox.Text;
                string userName     = userNameTextBox.Text;
                string userPassword = userPasswordTextBox.Text;

                #endregion

                var timeout = TimeSpan.FromSeconds(60);

                byte[] content;
                byte[] contentInformation;

                Content_Information_Data_Structure    contentInformationStructure   = new Content_Information_Data_Structure();
                Content_Information_Data_Structure_V2 contentInformationStructureV2 = new Content_Information_Data_Structure_V2();

                #region Read content and content information

                if (operationMode == OperationMode.RemoteHashVerification)
                {
                    switch (transport)
                    {
                    case ContentInformationTransport.PCCRTP:
                        PccrtpClient  pccrtpClient  = new PccrtpClient();
                        PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest(
                            server,
                            80,
                            file,
                            version);
                        PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest(
                            HttpVersionType.HttpVersion11,
                            pccrtpRequest,
                            (int)timeout.TotalMilliseconds);

                        if (pccrtpResponse.HttpResponse.ContentEncoding == "peerdist")
                        {
                            contentInformation = pccrtpResponse.PayloadData;

                            content = Utility.DownloadHTTPFile(server, file);
                        }
                        else
                        {
                            content = pccrtpResponse.PayloadData;

                            Thread.Sleep(5000);     // Wait for hash generation

                            pccrtpResponse = pccrtpClient.SendHttpRequest(
                                HttpVersionType.HttpVersion11,
                                pccrtpRequest,
                                (int)timeout.TotalMilliseconds);

                            contentInformation = pccrtpResponse.PayloadData;
                        }

                        break;

                    case ContentInformationTransport.SMB2:
                        using (Smb2ClientTransport smb2Client = new Smb2ClientTransport(timeout))
                        {
                            smb2Client.OpenFile(
                                server,
                                sharedFolder,
                                file,
                                securityPackageType,
                                domainName,
                                userName,
                                userPassword,
                                AccessMask.GENERIC_READ);

                            content = smb2Client.ReadAllBytes();

                            Thread.Sleep(5000);     // Wait for hash generation

                            HASH_HEADER hashHeader;
                            smb2Client.ReadHash(
                                SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                                version == BranchCacheVersion.V1 ? SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1 : SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2,
                                version == BranchCacheVersion.V1 ? SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED : SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED,
                                0,
                                uint.MaxValue,
                                out hashHeader,
                                out contentInformation);
                        }

                        break;

                    default:
                        throw new NotImplementedException();
                    }

                    switch (version)
                    {
                    case BranchCacheVersion.V1:
                        contentInformationStructure = PccrcUtility.ParseContentInformation(contentInformation);
                        break;

                    case BranchCacheVersion.V2:
                        contentInformationStructureV2 = PccrcUtility.ParseContentInformationV2(contentInformation);
                        break;

                    default:
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    content = File.ReadAllBytes(filePath);
                }

                #endregion

                #region Calculate hash and execute verification

                switch (version)
                {
                case BranchCacheVersion.V1:

                    if (operationMode == OperationMode.RemoteHashVerification)
                    {
                        PccrcUtility.GetHashAlgorithm(contentInformationStructure.dwHashAlgo, out hashAlgorithm, out hmacAlgorithm, out hashBlockSize);
                    }
                    else
                    {
                        PccrcUtility.GetHashAlgorithm(hashAlgoValue, out hashAlgorithm, out hmacAlgorithm, out hashBlockSize);
                    }
                    hmacAlgorithm.Key = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(serverSecret));

                    logger.LogInfo(
                        "Ks = Hash(ServerSecret): {0}",
                        Utility.ToHexString(hmacAlgorithm.Key));

                    logger.NewLine();

                    int blockTotalCount = content.Length / BLOCKBYTECOUNT;
                    if (content.Length > BLOCKBYTECOUNT * blockTotalCount)
                    {
                        blockTotalCount = blockTotalCount + 1;
                    }

                    int segmentCount = blockTotalCount / SEGMENTBLOCKCOUNT;
                    if (blockTotalCount > SEGMENTBLOCKCOUNT * segmentCount)
                    {
                        segmentCount = segmentCount + 1;
                    }

                    for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
                    {
                        logger.LogInfo("Segment{0}", segmentIndex);
                        logger.NewLine();
                        logger.Indent();

                        List <byte> blockHashList = new List <byte>();

                        List <byte> tempList = new List <byte>();

                        int blockCount = (segmentIndex == segmentCount - 1) ? (blockTotalCount % SEGMENTBLOCKCOUNT) : (SEGMENTBLOCKCOUNT);

                        for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
                        {
                            logger.LogInfo(
                                "Block{0} Offset {1} Length {2}",
                                blockIndex,
                                BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex,
                                BLOCKBYTECOUNT);
                            logger.NewLine();
                            logger.Indent();

                            var block = content.Skip(BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex).Take(BLOCKBYTECOUNT).ToArray();

                            byte[] blockHash = hashAlgorithm.ComputeHash(block);

                            logger.LogInfo("BlockHash{0} = Hash(Block): {1}", blockIndex, Utility.ToHexString(blockHash));

                            if (operationMode == OperationMode.RemoteHashVerification &&
                                !blockHash.SequenceEqual(contentInformationStructure.blocks[segmentIndex].BlockHashes.Skip(blockIndex * hashBlockSize).Take(hashBlockSize)))
                            {
                                logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.blocks[segmentIndex].BlockHashes.Skip(blockIndex * hashBlockSize).Take(hashBlockSize).ToArray()));
                            }

                            blockHashList.AddRange(blockHash);

                            logger.Unindent();
                            logger.NewLine();
                        }

                        byte[] hod = hashAlgorithm.ComputeHash(blockHashList.ToArray());

                        logger.LogInfo(
                            "HoD = Hash(BlockHash0 + BlockHash1 + ... + BlockHashN): {0}",
                            Utility.ToHexString(hod));

                        if (operationMode == OperationMode.RemoteHashVerification &&
                            !hod.SequenceEqual(contentInformationStructure.segments[segmentIndex].SegmentHashOfData))
                        {
                            logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.segments[segmentIndex].SegmentHashOfData));
                        }

                        logger.NewLine();

                        byte[] kp = hmacAlgorithm.ComputeHash(hod);

                        logger.LogInfo(
                            "Kp = HMAC(Ks, HoD): {0}",
                            Utility.ToHexString(kp));

                        if (operationMode == OperationMode.RemoteHashVerification &&
                            !kp.SequenceEqual(contentInformationStructure.segments[segmentIndex].SegmentSecret))
                        {
                            logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.segments[segmentIndex].SegmentSecret));
                        }

                        logger.NewLine();

                        tempList.AddRange(hod);
                        tempList.AddRange(Encoding.Unicode.GetBytes(HOHODK_APPEND_STRING));

                        byte[] hoHoDK = hashAlgorithm.ComputeHash(tempList.ToArray());

                        logger.LogInfo(
                            "hoHoDK = HMAC(HoD + \"MS_P2P_CACHING\"): {0}",
                            Utility.ToHexString(hoHoDK));

                        logger.NewLine();

                        logger.Unindent();
                    }
                    break;

                case BranchCacheVersion.V2:

                    PccrcUtility.GetHashAlgorithm(dwHashAlgoV2_Values.TRUNCATED_SHA512, out hashAlgorithm, out hmacAlgorithm);
                    hmacAlgorithm.Key = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(serverSecret)).Take(32).ToArray();

                    logger.LogInfo(
                        "Ks = Hash(ServerSecret): {0}",
                        Utility.ToHexString(hmacAlgorithm.Key));

                    logger.NewLine();

                    int segmentLength = BLOCKBYTECOUNT;
                    int chunkCount    = 1;

                    if (operationMode == OperationMode.RemoteHashVerification)
                    {
                        chunkCount = contentInformationStructureV2.chunks.Length;
                    }

                    int segmentOffset = 0;
                    for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++)
                    {
                        logger.LogInfo("Chunk{0}", chunkIndex);
                        logger.NewLine();
                        logger.Indent();

                        segmentCount = content.Length / segmentLength;
                        if (content.Length > segmentCount * segmentLength)
                        {
                            segmentCount++;
                        }

                        if (operationMode == OperationMode.RemoteHashVerification)
                        {
                            segmentCount = contentInformationStructureV2.chunks[chunkIndex].chunkData.Length;
                        }

                        for (int segmentIndex = 0; segmentIndex < segmentCount; ++segmentIndex)
                        {
                            logger.LogInfo(
                                "Segment{0} Offset {1} Length {2}",
                                segmentIndex,
                                segmentOffset,
                                BLOCKBYTECOUNT);
                            logger.NewLine();
                            logger.Indent();

                            if (operationMode == OperationMode.RemoteHashVerification)
                            {
                                segmentLength = (int)contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].cbSegment;
                            }

                            List <byte> tempList = new List <byte>();

                            var segment = content.Skip(segmentOffset).Take(segmentLength).ToArray();

                            segmentOffset += segmentLength;

                            //TRANCATED_SHA_512
                            byte[] hod = hashAlgorithm.ComputeHash(segment).Take(32).ToArray();

                            logger.LogInfo(
                                "HoD = Hash(Segment): {0}",
                                Utility.ToHexString(hod));

                            if (operationMode == OperationMode.RemoteHashVerification &&
                                !hod.SequenceEqual(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentHashOfData))
                            {
                                logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentHashOfData));
                            }

                            logger.NewLine();

                            byte[] kp = hmacAlgorithm.ComputeHash(hod).Take(32).ToArray();

                            logger.LogInfo(
                                "Kp = HMAC(Ks, HoD): {0}",
                                Utility.ToHexString(kp));

                            if (operationMode == OperationMode.RemoteHashVerification &&
                                !kp.SequenceEqual(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentSecret))
                            {
                                logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentSecret));
                            }

                            logger.NewLine();

                            tempList.AddRange(hod);
                            tempList.AddRange(Encoding.Unicode.GetBytes(HOHODK_APPEND_STRING));

                            byte[] hoHoDK = hashAlgorithm.ComputeHash(tempList.ToArray());

                            logger.LogInfo(
                                "hoHoDK = HMAC(HoD + \"MS_P2P_CACHING\"): {0}",
                                Utility.ToHexString(hoHoDK));

                            logger.NewLine();

                            logger.Unindent();
                        }
                    }

                    break;

                default:
                    throw new NotImplementedException();
                }

                if (operationMode == OperationMode.RemoteHashVerification)
                {
                    if (logger.HasError)
                    {
                        Utility.ShowMessageBox("Hash verification error found!", MessageBoxIcon.Error);
                    }
                    else
                    {
                        Utility.ShowMessageBox("Hash verification passed!", MessageBoxIcon.Information);
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                Utility.ShowMessageBox(ex.Message + "\r\n\r\n" + ex.StackTrace, MessageBoxIcon.Error);
            }
        }
        /// <summary>
        /// Verify Content, Segments, and Blocks defined in section 2.1.
        /// </summary>
        /// <param name="pccrtpResponse">The HTTP resopnse.</param>
        private void VerifyContentSegmentsBlocks(PccrtpResponse pccrtpResponse)
        {
            Content_Information_Data_Structure contentInfo = pccrtpResponse.ContentInfo;

            #region MS-PCCRC_R3

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRC_R3.segment is {0} type",
                pccrtpResponse.HttpHeader[ACCEPTRANGES]);

            bool isVerifyR3 = pccrtpResponse.HttpHeader[ACCEPTRANGES].Equals("bytes");

            // Verify MS-PCCRC requirement: MS-PCCRC_R3
            Site.CaptureRequirementIfIsTrue(
                isVerifyR3,
                3,
                @"[In Content, Segments, and Blocks] Each segment is a binary string.");

            #endregion

            #region MS-PCCRC_R10

            bool isVerifyR10 = true;
            for (int i = 0; i < contentInfo.cSegments - 1; i++)
            {
                if (contentInfo.segments[i].cbBlockSize != STANDARDBBLOCKSIZE)
                {
                    isVerifyR10 = false;
                    break;
                }
            }

            // Check for the last block in the last segment, which may be shorter than the standard block size (64 KB).
            if (contentInfo.segments[contentInfo.cSegments - 1].cbBlockSize > STANDARDBBLOCKSIZE)
            {
                isVerifyR10 = false;
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRC_R10. Each block size is {0} 64 kilobytes",
                isVerifyR10 ? string.Empty : "not");

            // Verify MS-PCCRC requirement: MS-PCCRC_R10
            Site.CaptureRequirementIfIsTrue(
                isVerifyR10,
                10,
                @"[In Content, Segments, and Blocks] Each block is a binary string of a fixed size (64 kilobytes), 
                except for the last block in the last segment, which again may be shorter.");

            #endregion

            #region MS-PCCRC_R4

            string allLength = string.Empty;

            if (pccrtpResponse.HttpHeader.ContainsKey(CONTENTRANGE))
            {
                // Get the value of content length in the response for partial request.
                allLength = pccrtpResponse.HttpHeader[CONTENTRANGE];
                allLength = allLength.Substring(allLength.IndexOf('/') + 1);
            }
            else if (pccrtpResponse.HttpHeader.ContainsKey(XP2PPEERDIST))
            {
                // Get the value of content length in the response for full request.
                allLength = pccrtpResponse.HttpHeader[XP2PPEERDIST];
                allLength = allLength.Substring(allLength.LastIndexOf('=') + 1);
            }

            bool isVerifyR4    = true;
            long contentLength = 0;

            try
            {
                contentLength = Convert.ToInt64(allLength);
            }
            catch (FormatException e)
            {
                throw new FormatException(e.ToString());
            }

            long lastSegmentLength = 0;
            for (int i = 0; i < contentInfo.cSegments; i++)
            {
                // If there are multiple segments, check each segment is of a standard size (32 MB).
                if (contentLength > STANDARDSEGMENTSIZE)
                {
                    if (contentInfo.segments[i].cbSegment != STANDARDSEGMENTSIZE)
                    {
                        isVerifyR4 = false;
                        break;
                    }

                    contentLength -= STANDARDSEGMENTSIZE;
                }
                else
                {
                    // Check for the last segment, which may be shorter than the standard segment size (32 MB).
                    if (contentLength != contentInfo.segments[i].cbSegment)
                    {
                        if (i > 0)
                        {
                            lastSegmentLength = contentLength;
                        }

                        isVerifyR4 = false;
                        break;
                    }
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRC_R4.segment size is {0}32 megabytes except possibly the last segment",
                isVerifyR4 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R4
            Site.CaptureRequirementIfIsTrue(
                isVerifyR4,
                4,
                @"[In Content, Segments, and Blocks] Each segment is of a standard size (32 megabytes), 
                except possibly the last segment which may be smaller if the content size is not a multiple 
                of the standard segment size.");

            #endregion

            // MS-PCCRC_R63 is blocked by TDI(Techical Document Issue) about inaccurate definition of
            // dwReadBytesInLastSegment if the HTTP request is a range retrieval request.
            if (bool.Parse(Site.Properties.Get("PCCRC.IsTDI.65999.Fixed")))
            {
                #region MS-PCCRC_R63

                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    @"Verify MS-PCCRC_R63, the actual value of the dwReadBytesInLastSegment is {0}",
                    contentInfo.dwReadBytesInLastSegment);

                // Verify MS-PCCRC requirement: MS-PCCRC_R63
                Site.CaptureRequirementIfAreEqual <long>(
                    lastSegmentLength,
                    contentInfo.dwReadBytesInLastSegment,
                    63,
                    @"[In Content Information Data Structure Version 1.0] dwReadBytesInLastSegment (4 bytes):  Total 
                        number of bytes of the content range which lie within the final segment in the Content 
                        Information data structure.");

                #endregion
            }
        }
        /// <summary>
        /// Verify Data Structure of Content Information defined in section 2.3.
        /// </summary>
        /// <param name="pccrtpResponse">The HTTP resopnse.</param>
        private void VerifyDataStructure(PccrtpResponse pccrtpResponse)
        {
            Content_Information_Data_Structure contentInfo = pccrtpResponse.ContentInfo;

            #region MS-PCCRC_R58

            int hashLength        = 0;
            int valueOfDwHashAlgo = 0;
            switch (pccrtpResponse.ContentInfo.dwHashAlgo)
            {
            case dwHashAlgo_Values.V1:
                valueOfDwHashAlgo = 0x0000800C;
                hashLength        = 32;
                break;

            case dwHashAlgo_Values.V2:
                hashLength        = 48;
                valueOfDwHashAlgo = 0x0000800D;
                break;

            case dwHashAlgo_Values.V3:
                hashLength        = 64;
                valueOfDwHashAlgo = 0x0000800E;
                break;

            default:
                break;
            }

            // Add the debug information.
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R58, the actual length of dwHashAlgo is: {0}",
                Marshal.SizeOf(valueOfDwHashAlgo));

            // Verify MS-PCCRC requirement: MS-PCCRC_R58
            Site.CaptureRequirementIfAreEqual <int>(
                4,
                Marshal.SizeOf(valueOfDwHashAlgo),
                58,
                @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes):  Hash algorithm to use. <2> ");

            #endregion

            #region MS-PCCRC_R581

            bool isVerifyR581 = valueOfDwHashAlgo == 0x0000800C ||
                                valueOfDwHashAlgo == 0x0000800D ||
                                valueOfDwHashAlgo == 0x0000800E;

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R581, the actual value of dwHashAlgo is 0x{0:X8}.",
                valueOfDwHashAlgo);

            // Verify MS-PCCRC requirement: MS-PCCRC_R581
            Site.CaptureRequirementIfIsTrue(
                isVerifyR581,
                581,
                @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): MUST be one of the following 
                values:0x0000800C,0x0000800D,0x0000800E.");

            #endregion

            #region MS-PCCRC_R59

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R59, , the actual value of dwHashAlgo is 0x{0:X8}.",
                valueOfDwHashAlgo);

            // Verify MS-PCCRC requirement: MS-PCCRTP_R59
            Site.CaptureRequirementIfAreEqual <int>(
                0x0000800C,
                valueOfDwHashAlgo,
                59,
                @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes):  When use the SHA-256 hash 
                algorithm, the value is 0x0000800C.");

            #endregion

            #region MS-PCCRC_R54

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R54, all fields are {0}in little-endian byte order",
                BitConverter.IsLittleEndian ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R54
            Site.CaptureRequirementIfIsTrue(
                BitConverter.IsLittleEndian,
                54,
                @"[In Content Information Data Structure Version 1.0] All fields are in little-endian byte order.");

            #endregion

            #region MS-PCCRC_R57

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R57, the actual value of Version is 0x{0:X8}",
                contentInfo.Version);

            // Verify MS-PCCRC requirement: MS-PCCRTP_R57
            Site.CaptureRequirementIfAreEqual <int>(
                0x0100,
                contentInfo.Version,
                57,
                @"[In Content Information Data Structure Version 1.0] Version (2 bytes):  MUST be 0x0100.");

            #endregion

            #region MS-PCCRC_R53

            // The Version is parsed at the first 2 byte word in Content Information by stack.
            // If MS-PCCRC_R57 is verified successfully, MS-PCCRC_R53 is verified and so captured directly.
            Site.CaptureRequirement(
                53,
                @"[In Content Information Data Structure Version 1.0] Content Information starts with a single 2 byte 
                WORD value representing the data structure version.");

            #endregion

            #region MS-PCCRC_R56

            // The Version is parsed at the first 2 byte word in Content Information by stack.
            // If MS-PCCRC_R57 is verified successfully, it indicates that the low byte is the minor version number
            // and the high byte is the major version number.
            Site.CaptureRequirement(
                56,
                @"[In Content Information Data Structure Version 1.0] Version (2 bytes):  The low byte is the minor 
                version number and the high byte is the major version number.");

            #endregion

            #region MS-PCCRC_R55

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R55, the actual size of the Version is {0}",
                Marshal.SizeOf(contentInfo.Version));

            // Verify MS-PCCRC requirement: MS-PCCRTP_R55
            Site.CaptureRequirementIfAreEqual <int>(
                2,
                Marshal.SizeOf(contentInfo.Version),
                55,
                @"[In Content Information Data Structure Version 1.0] Version (2 bytes):  Content Information version 
                (0x0100 is version 1.0).");

            #endregion

            #region MS-PCCRC_R64

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R64, the actual value of the cSegments is {0}",
                contentInfo.cSegments);

            // Verify MS-PCCRC requirement: MS-PCCRC_R64
            Site.CaptureRequirementIfAreEqual <int>(
                contentInfo.segments.Length,
                (int)contentInfo.cSegments,
                64,
                @"[In Content Information Data Structure Version 1.0] cSegments (4 bytes):  The number of segments 
                which intersect the content range and hence are contained in the Content Information data structure.");

            #endregion

            #region MS-PCCRC_R65

            bool isVerifyR65 = true;

            for (int i = 0; i < contentInfo.cSegments; i++)
            {
                if (contentInfo.segments[i].cbBlockSize == STANDARDBBLOCKSIZE &&
                    contentInfo.segments[i].SegmentHashOfData.Length == hashLength &&
                    contentInfo.segments[i].SegmentSecret.Length == hashLength)
                {
                    isVerifyR65 = true;
                }
                else
                {
                    isVerifyR65 = false;
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R65, the segments variable {0} contain the Segment start offset, 
                length, block size, SegmentHashofData and SegmentSecret for each segment.",
                isVerifyR65 ? string.Empty : "does't");

            // Verify MS-PCCRC requirement: MS-PCCRC_R65
            Site.CaptureRequirementIfIsTrue(
                isVerifyR65,
                65,
                @"[In Content Information Data Structure Version 1.0] segments (variable):  Segment start offset, length, 
                block size, SegmentHashofData and SegmentSecret for each segment.");

            #endregion
        }
        /// <summary>
        /// Verify SegmentDescription defined in section 2.3.1.1.
        /// </summary>
        /// <param name="pccrtpResponse">The HTTP response.</param>
        private void VerifySegmentDescription(PccrtpResponse pccrtpResponse)
        {
            #region MS-PCCRC_R67

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R67, the actual number of SegmentDescription fields in segments field is {0}",
                pccrtpResponse.ContentInfo.segments.Length);

            // Verify MS-PCCRC requirement: MS-PCCRC_R67
            Site.CaptureRequirementIfAreEqual <uint>(
                pccrtpResponse.ContentInfo.cSegments,
                (uint)pccrtpResponse.ContentInfo.segments.Length,
                67,
                @"[In SegmentDescription] The segments field is composed of a number cSegments of 
                SegmentDescription fields.");

            #endregion

            #region MS-PCCRC_R69

            bool isVerifyR69 = true;
            for (int i = 0; i < pccrtpResponse.ContentInfo.cSegments - 1; i++)
            {
                if (pccrtpResponse.ContentInfo.segments[i].cbSegment != STANDARDSEGMENTSIZE)
                {
                    isVerifyR69 = false;
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R69, the actual size of every segment except for the last segment is {0}32 megabytes",
                isVerifyR69 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R69
            Site.CaptureRequirementIfIsTrue(
                isVerifyR69,
                69,
                @"[In SegmentDescription] Every segment except for the last segment must be exactly 
                32 megabytes in size.");

            #endregion

            int hashLength = 0;
            switch (pccrtpResponse.ContentInfo.dwHashAlgo)
            {
            case dwHashAlgo_Values.V1:
                hashLength = 32;
                break;

            case dwHashAlgo_Values.V2:
                hashLength = 48;
                break;

            case dwHashAlgo_Values.V3:
                hashLength = 64;
                break;

            default:
                break;
            }

            #region MS-PCCRC_R74

            bool isVerifyR74 = true;
            bool isVerifyR77 = true;
            bool isVerifyR79 = true;
            bool isVerifyR83 = true;
            bool isVerifyR76 = true;

            for (int i = 1; i < pccrtpResponse.ContentInfo.cSegments; i++)
            {
                ulong offset = pccrtpResponse.ContentInfo.segments[i - 1].ullOffsetInContent
                               + pccrtpResponse.ContentInfo.segments[i - 1].cbSegment;
                if (pccrtpResponse.ContentInfo.segments[i].ullOffsetInContent != offset)
                {
                    isVerifyR74 = false;
                }

                if (pccrtpResponse.ContentInfo.segments[i].cbBlockSize != STANDARDBBLOCKSIZE)
                {
                    isVerifyR77 = false;
                }

                if (Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[i].cbBlockSize) != 4)
                {
                    isVerifyR76 = false;
                }

                if (pccrtpResponse.ContentInfo.segments[i].SegmentHashOfData.Length != hashLength)
                {
                    isVerifyR79 = false;
                }

                if (pccrtpResponse.ContentInfo.segments[i].SegmentSecret.Length != hashLength)
                {
                    isVerifyR83 = false;
                }
            }

            if (pccrtpResponse.ContentInfo.segments[0].ullOffsetInContent != 0)
            {
                isVerifyR74 = false;
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R74, the ullOffsetInContent in every SegmentDescription field is {0}content offset 
                at which the start of the segment begins.",
                isVerifyR74 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R74
            Site.CaptureRequirementIfIsTrue(
                isVerifyR74,
                74,
                @"[In SegmentDescription] ullOffsetInContent (8 bytes):  Content offset at which the start 
                of the segment begins.");

            #endregion

            #region MS-PCCRC_R75

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R75. The actual size of the cbSegment is {0}.",
                Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[0].cbSegment));

            // Verify MS-PCCRC requirement: MS-PCCRC_R75
            Site.CaptureRequirementIfAreEqual <int>(
                4,
                Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[0].cbSegment),
                75,
                @"[In SegmentDescription] cbSegment (4 bytes):  Total number of bytes in the segment, 
                regardless of how many of those bytes intersect the content range.");

            #endregion

            #region MS-PCCRC_R76

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R76. The actual size of the cbBlockSize is {0}4 bytes.",
                isVerifyR76 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R76
            Site.CaptureRequirementIfIsTrue(
                isVerifyR76,
                76,
                @"[In SegmentDescription] cbBlockSize (4 bytes):  
                Length of a content block within this segment, in bytes.");

            #endregion

            #region MS-PCCRC_R77

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R77, the block size of every segment is {0}65536 bytes",
                isVerifyR77 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R77
            Site.CaptureRequirementIfIsTrue(
                isVerifyR77,
                77,
                @"[In SegmentDescription] cbBlockSize (4 bytes): Every segment MUST use the block size of 65536 bytes.");

            #endregion

            #region MS-PCCRC_R79

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R79, the actual SegmentHashOfData is {0} of length 32",
                isVerifyR79 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R79
            Site.CaptureRequirementIfIsTrue(
                isVerifyR79,
                79,
                @"[In SegmentDescription]  SegmentHashOfData (variable): The hash is of length 32 if dwHashAlgo 
                at the start of the Content Information was 0x800C = SHA-256.");

            #endregion

            #region MS-PCCRC_R83

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R83, the actual length of the SegmentSecret is {0}",
                hashLength);

            // Verify MS-PCCRC requirement: MS-PCCRC_R83
            Site.CaptureRequirementIfIsTrue(
                isVerifyR83,
                83,
                @"[In SegmentDescription]  SegmentSecret (variable):The hash is of length 32 if dwHashAlgo 
                at the start of the Content Information was 0x800C = SHA-256.");

            #endregion
        }
        /// <summary>
        /// Verify SegmentContentBlocks defined in section 2.3.1.2.
        /// </summary>
        /// <param name="pccrtpResponse">The HTTP response.</param>
        private void VerifySegmentContentBlocks(PccrtpResponse pccrtpResponse)
        {
            #region MS-PCCRC_R86

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R86, the actual number of SegmentContentBlocks fields in blocks field is {0}",
                pccrtpResponse.ContentInfo.blocks.Length);

            // Verify MS-PCCRC requirement: MS-PCCRC_R86
            Site.CaptureRequirementIfAreEqual <uint>(
                pccrtpResponse.ContentInfo.cSegments,
                (uint)pccrtpResponse.ContentInfo.blocks.Length,
                86,
                @"[In SegmentContentBlocks] The blocks field contains a number cSegments of 
                SegmentContentBlocks fields.");

            #endregion

            #region MS-PCCRC_R89

            bool isVerifyR89 = true;

            int hashLength = 0;
            switch (pccrtpResponse.ContentInfo.dwHashAlgo)
            {
            case dwHashAlgo_Values.V1:
                hashLength = 32;
                break;

            case dwHashAlgo_Values.V2:
                hashLength = 48;
                break;

            case dwHashAlgo_Values.V3:
                hashLength = 64;
                break;

            default:
                break;
            }

            foreach (SegmentContentBlocks segContentBlocks in pccrtpResponse.ContentInfo.blocks)
            {
                if (segContentBlocks.BlockHashes.Length != segContentBlocks.cBlocks * hashLength)
                {
                    isVerifyR89 = false;
                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R89, the actual size of BlockHashes field is {0} cBlocks * {1}",
                isVerifyR89 ? string.Empty : "not ",
                hashLength);

            // Verify MS-PCCRC requirement: MS-PCCRC_R89
            Site.CaptureRequirementIfIsTrue(
                isVerifyR89,
                89,
                @"[In SegmentContentBlocks] BlockHashes (variable):The size of this field is 
                cBlocks * (32, 48 or 64, depending on which hash was used).");

            #endregion

            #region MS-PCCRC_R12

            // The BlockHashes field is parsed according the cBlocks and the hash algorithm by the stack.
            // If MS-PCCRC_R89 is verified successfully, it indicates that the BlockHashes is the hash list
            // of each block in the order the block in the segment.So MS-PCCRC_R12 is captured directly.
            Site.CaptureRequirement(
                12,
                @"[In Content, Segments, and Blocks] Blocks within a segment are identified by their progressive 
                index within the segment (Block 0 is the first block in the segment, Block 1 the second, and so on).");

            #endregion
        }
Пример #15
0
        /// <summary>
        /// This class is used to verify the requirements related to PCCRTP response.
        /// </summary>
        /// <param name="pccrtpResponse">The PCCRTP response message.</param>
        private void VerifyPccrtpResponse(PccrtpResponse pccrtpResponse)
        {
            #region MS-PCCRTP_R11

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRTP_R11. Actual value of X-P2P-PeerDist field is: {0}.",
                pccrtpResponse.HttpHeader[XP2PPEERDIST]);

            bool isVerifyR11 = pccrtpResponse.HttpResponse.Headers[XP2PPEERDIST].Contains("Version") &&
                               pccrtpResponse.HttpResponse.Headers[XP2PPEERDIST].Contains("ContentLength");

            // Verify MS-PCCRTP requirement: MS-PCCRTP_R11
            Site.CaptureRequirementIfIsTrue(
                isVerifyR11,
                11,
                @"[In Message Syntax] The extension-header field can appear in  responses, the syntax of this header
                field value is described as follows:
                extension-header = X-P2P-PeerDist 
                X-P2P-PeerDist = ""X-P2P-PeerDist"" "":"" peerdist-params [peerdist-params = 1#( version | [content-len]
                | [missing-data-request] )
                version = ""Version"" ""="" major-version ""."" minor-version].
                ");

            #endregion

            #region MS-PCCRTP_R18

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRTP_R18. Actual Value of Content-Length is {0}",
                pccrtpResponse.HttpHeader[CONTENTLENGTH]);

            long contentLength;

            // Verify MS-PCCRTP requirement: MS-PCCRTP_R18
            bool isVerifyR18 = pccrtpResponse.HttpHeader.Values.Contains(pccrtpResponse.HttpHeader[CONTENTLENGTH]) &&
                               long.TryParse(pccrtpResponse.HttpHeader[CONTENTLENGTH], out contentLength);

            Site.CaptureRequirementIfIsTrue(
                isVerifyR18,
                18,
                @"[In Message Syntax] The content-len [content-len = ""ContentLength"" ""="" 1*DIGIT] parameter contains
                the length of the entity-body before the PeerDist content encoding is applied to it.");

            #endregion

            #region MS-PCCRTP_R34

            bool isVerifyR34 = pccrtpResponse.HttpHeader.Values.Contains(pccrtpResponse.HttpHeader["X-P2P-PeerDist"]);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRTP_R34. The response {0} contain PeerDist parameters header field.",
                isVerifyR34 ? string.Empty : "does not ");

            // Verify MS-PCCRTP requirement: MS-PCCRTP_R34
            Site.CaptureRequirementIfIsTrue(
                isVerifyR34,
                34,
                @"[In Receiving a PeerDist-Supporting Request] HTTP/1.1 server MUST also include the PeerDist parameters
                header field in the response.");

            #endregion

            #region MS-PCCRTP_R35

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRTP_R35. Actual Value of Version is {0}",
                pccrtpResponse.HttpHeader[XP2PPEERDIST]);

            // Verify MS-PCCRTP requirement: MS-PCCRTP_R35
            bool isVerifyR35 = pccrtpResponse.HttpHeader[XP2PPEERDIST].Contains("Version");

            Site.CaptureRequirementIfIsTrue(
                isVerifyR35,
                35,
                @"[In Receiving a PeerDist-Supporting Request] The PeerDist parameters header field MUST contain 
                the Version parameter containing the version of the PeerDist content encoding used in the response.");

            #endregion

            #region MS-PCCRTP_R36

            bool isVerifyR36 = pccrtpResponse.HttpHeader[XP2PPEERDIST].Contains("ContentLength");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRTP_R36. Actual Value of ContentLength is {0} in PeerDist Header field",
                isVerifyR36 ? string.Empty : "not");

            // Verify MS-PCCRTP requirement: MS-PCCRTP_R36
            Site.CaptureRequirementIfIsTrue(
                isVerifyR36,
                36,
                @"[In Receiving a PeerDist-Supporting Request] the PeerDist parameters header field MUST also contain 
                the ContentLength parameter specifying the content length of the response entity-body 
                before the PeerDist content encoding has been applied to it.");

            #endregion

            #region MS-PCCRTP_R48

            string[] headerValues  = pccrtpResponse.HttpHeader[XP2PPEERDIST].Split(new char[] { ',' });
            string   versionString = headerValues[0].Substring(headerValues[0].IndexOf('=') + 1);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRTP_R48. Actual Value of peerdist version is {0}",
                versionString);

            if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2)
            {
                // Verify MS-PCCRTP requirement: MS-PCCRTP_R48
                Site.CaptureRequirementIfAreEqual <string>(
                    "1.0",
                    versionString,
                    48,
                    @"[In Appendix A: Product Behavior]<3> Section 1.7: HTTP/1.1 servers in Windows Server 2008 R2 
                set the PeerDist version parameter to 1.0.");
            }

            #endregion

            #region MS-PCCRTP_R52

            if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2)
            {
                bool isContainEtag         = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("ETag");
                bool isContainLastModified = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("Last-Modified");
                bool isContainBoth         = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("ETag") &&
                                             pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("Last-Modified");

                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    @"Verify MS-PCCRTP_R52.The response actually does {0} contain an ETag header field, 
                    does {1} contain a Last-Modified header field, does {2} contain both header fields.",
                    isContainEtag ? string.Empty : "not",
                    isContainLastModified ? string.Empty : "not",
                    isContainBoth ? string.Empty : "not");

                bool isVerifyR52 = isContainEtag || isContainLastModified || isContainBoth;

                // Verify MS-PCCRTP requirement: MS-PCCRTP_R52
                Site.CaptureRequirementIfIsTrue(
                    isVerifyR52,
                    52,
                    @"[In Appendix A: Product Behavior]  <7> Section 3.2:The HTTP/1.1 server in Windows Server 2008 R2 
                    sends a PeerDist-encoded response only when the response contains an ETag header field or a 
                    Last-Modified header field or both header fields.");
            }

            #endregion

            #region MS-PCCRTP_R54

            if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2)
            {
                bool isVerifyR54 = pccrtpResponse.HttpResponse.ContentEncoding.Equals("peerdist") &&
                                   !pccrtpResponse.ContentInfo.Equals(null);

                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    @"Verify MS-PCCRTP_R54. The HTTP/1.1 server in Windows Server 2008 R2 does {0} 
                    use the algorithms and data structures defined in [MS-PCCRC].",
                    isVerifyR54 ? string.Empty : "not");

                // Verify MS-PCCRTP requirement: MS-PCCRTP_R54
                Site.CaptureRequirementIfIsTrue(
                    isVerifyR54,
                    54,
                    @"[In Appendix A: Product Behavior]<9> Section 3.2.5.1:   The HTTP/1.1 server 
                    in Windows Server 2008 R2 uses the algorithms and data structures defined in [MS-PCCRC] 
                    to generate the PeerDist Content Information only when it receives an HTTP/1.1 request. ");
            }

            #endregion

            #region MS-PCCRRP_R8001

            bool isVerifyR8001 = pccrtpResponse.HttpHeader.ContainsKey(CONTENTENCODING) &&
                                 pccrtpResponse.HttpHeader[CONTENTENCODING].Contains("peerdist");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRTP_R8001, the PeerDist content-encoding value is {0} specified 
                in the Accept-Encoding and Content-Encoding header fields.",
                isVerifyR8001 ? string.Empty : "not ");

            // Verify MS-PCCRTP requirement: MS-PCCRTP_R8001
            Site.CaptureRequirementIfIsTrue(
                isVerifyR8001,
                8001,
                @"[In Message Syntax] The PeerDist content-encoding value can be specified in the Accept-Encoding 
                and Content-Encoding header fields,as shown in the following examples: Content-Encoding: peerdist.");

            #endregion
        }
        /// <summary>
        /// Verify Segment Identifiers (HoHoDK) and Keys defined in section 2.2.
        /// </summary>
        /// <param name="pccrtpResponse">The HTTP response.</param>
        private void VerifySegmentIdentifiersAndKeys(PccrtpResponse pccrtpResponse)
        {
            #region MS-PCCRC_R26

            bool isVerifyR26 = pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V1 ||
                               pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V2 ||
                               pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V3;

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-PCCRC_R26. the dwhashAlgo of hash is {0}",
                pccrtpResponse.ContentInfo.dwHashAlgo);

            // Verify MS-PCCRTP requirement: MS-PCCRC_R26
            Site.CaptureRequirementIfIsTrue(
                isVerifyR26,
                26,
                @"[In Segment Identifiers (HoHoDk) and Keys] Notation: Hash: The input hash function,
                which MUST be one of the hash functions listed in section 2.3.");

            #endregion

            #region MS-PCCRC_R37

            bool isVerifyR37 = true;
            if (pccrtpResponse.ContentInfo.segments != null && pccrtpResponse.ContentInfo.blocks != null)
            {
                for (int i = 0; i < pccrtpResponse.ContentInfo.segments.Length; i++)
                {
                    if (pccrtpResponse.ContentInfo.segments[i].SegmentHashOfData == null ||
                        pccrtpResponse.ContentInfo.segments[i].SegmentSecret == null)
                    {
                        isVerifyR37 = false;
                        break;
                    }
                }
            }
            else
            {
                isVerifyR37 = false;
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R37. BlockHashes, SegmentHashOfData , SegmentSecret are {0}inclueded in the Content 
                Information Data Structure.",
                isVerifyR37 ? string.Empty : "not ");

            // Verify MS-PCCRC requirement: MS-PCCRC_R37
            Site.CaptureRequirementIfIsTrue(
                isVerifyR37,
                37,
                @"[In Segment Identifiers (HoHoDk) and Keys]  ContentInfo includes only the list of block hashes, 
                the HoD, and Kp.");

            #endregion

            #region MS-PCCRC_R3701

            // Verify MS-PCCRC requirement: MS-PCCRC_R3701
            // The ContentInfo is parsed according the definition of Content Information Data Structure by the stack.
            // If ContentInfo improperly includes Ke and HoHoDk, then an exception will be thrown in the stack layer.
            // The program runs into here which has indicated that Ke and HoHoDk are not included in ContentInfo.
            // So MS-PCCRC_R3701 is captured directly.
            Site.CaptureRequirement(
                3701,
                @"[In Segment Identifiers (HoHoDk) and Keys]Ke and HoHoDk are not included in ContentInfo.");

            #endregion
        }
        public byte[] RetrieveContentData(string filename)
        {
            switch (testConfig.ContentTransport)
            {
            case ContentInformationTransport.PCCRTP:

                PccrtpClient  pccrtpClient  = new PccrtpClient();
                PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest(
                    testConfig.ContentServerComputerName,
                    testConfig.ContentServerHTTPListenPort,
                    filename);

                PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest(
                    Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11,
                    pccrtpRequest,
                    (int)testConfig.Timeout.TotalMilliseconds);

                testSite.Assert.AreNotEqual(
                    "peerdist",
                    pccrtpResponse.HttpResponse.ContentEncoding,
                    "The content server should not have content information ready yet");

                return(pccrtpResponse.PayloadData);

            case ContentInformationTransport.SMB2:

                using (BranchCacheSmb2ClientTransport smb2Client = new BranchCacheSmb2ClientTransport(testConfig.Timeout, testSite, testConfig.SupportBranchCacheV1, testConfig.SupportBranchCacheV2))
                {
                    smb2Client.OpenFile(
                        testConfig.ContentServerComputerName,
                        testConfig.SharedFolderName,
                        filename,
                        testConfig.SecurityPackageType,
                        testConfig.DomainName,
                        testConfig.UserName,
                        testConfig.UserPassword,
                        AccessMask.GENERIC_READ);

                    HASH_HEADER hashHeader;
                    byte[]      hashData = null;

                    uint status = 0;

                    if (testConfig.SupportBranchCacheV1)
                    {
                        status = smb2Client.ReadHash(
                            SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                            SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1,
                            SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED,
                            0,
                            uint.MaxValue,
                            out hashHeader,
                            out hashData);

                        testSite.Assert.AreNotEqual(
                            Smb2Status.STATUS_SUCCESS,
                            status,
                            "The content server should not have content information ready yet");

                        testSite.CaptureRequirementIfAreEqual(
                            Smb2Status.STATUS_HASH_NOT_PRESENT,
                            status,
                            RequirementCategory.HashNotPresent,
                            RequirementCategory.HashNotPresentMessage);
                    }

                    if (testConfig.SupportBranchCacheV2)
                    {
                        status = smb2Client.ReadHash(
                            SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST,
                            SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2,
                            SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED,
                            0,
                            uint.MaxValue,
                            out hashHeader,
                            out hashData);

                        testSite.Assert.AreNotEqual(
                            Smb2Status.STATUS_SUCCESS,
                            status,
                            "The content server should not have content information ready yet");

                        testSite.CaptureRequirementIfAreEqual(
                            Smb2Status.STATUS_HASH_NOT_PRESENT,
                            status,
                            RequirementCategory.HashNotPresent,
                            RequirementCategory.HashNotPresentMessage);
                    }

                    return(smb2Client.ReadAllBytes());
                }

            default:
                throw new NotImplementedException();
            }
        }