/// <summary>
        /// Create SEGMENT_INFO_MESSAGE package.
        /// </summary>
        /// <param name="connectionInfoPort">
        /// A 16-bit unsigned integer that MUST be set by the client to the port
        /// on which it is listening as a server-role peer, for use with the retrieval protocol.
        /// </param>
        /// <param name="segmentInformation">A Content Information data structure.</param>
        /// <returns>Return the SEGMENT_INFO_MESSAGE.</returns>
        public SEGMENT_INFO_MESSAGE CreateSegmentInfoMessage(
            int connectionInfoPort,
            Content_Information_Data_Structure segmentInformation)
        {
            MESSAGE_HEADER messageHeader;

            // MajorVersion (1 byte):  The major part of the version, which MUST be 0x01.
            // MinorVersion (1 byte):  The minor part of the version, which MUST be 0x00.
            // Padding (4 bytes):  The value of this field is indeterminate and MUST be ignored on processing
            messageHeader.MajorVersion = 1;
            messageHeader.MinorVersion = 0;
            messageHeader.MsgType      = PCHC_MESSAGE_TYPE.SEGMENT_INFO_MESSAGE;
            messageHeader.Padding      = new byte[4];
            Content_Information_Data_Structure segmentInfomation = segmentInformation;

            CONNECTION_INFORMATION connectionInfo;

            // Padding (6 bytes):  The value of this field is indeterminated and MUST be ignored on processing.
            // Port (2 bytes): A 16-bit unsigned integer that MUST be set by the client to the port on
            // which it is listening as a server-role peer, for use with the retrieval protocol.
            connectionInfo.Padding = new byte[6];
            connectionInfo.Port    = (ushort)connectionInfoPort;

            // ContentTag (16 bytes):  A structure consisting of 16 bytes of opaque data.
            byte[] contentTag = new byte[16];

            SEGMENT_INFO_MESSAGE segmentInfoMessage;

            segmentInfoMessage.ConnectionInfo = connectionInfo;
            segmentInfoMessage.ContentTag     = contentTag;
            segmentInfoMessage.MsgHeader      = messageHeader;
            segmentInfoMessage.SegmentInfo    = segmentInfomation;

            return(segmentInfoMessage);
        }
        public void VerifyHashGenerationV1(byte[] content, Content_Information_Data_Structure contentInfo)
        {
            const int BLOCKBYTECOUNT    = 0x10000;
            const int SEGMENTBLOCKCOUNT = 512;

            dwHashAlgo_Values hashAlgo = contentInfo.dwHashAlgo;

            int blockTotalCount = content.Length / BLOCKBYTECOUNT;

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

            int segmentCount = blockTotalCount / SEGMENTBLOCKCOUNT;

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

            HashAlgorithm hashAlgorithm;
            HMAC          hmacAlgorithm;
            int           blockHashSize;

            PccrcUtility.GetHashAlgorithm(hashAlgo, out hashAlgorithm, out hmacAlgorithm, out blockHashSize);
            hmacAlgorithm.Key = hashAlgorithm.ComputeHash(testConfig.ServerSecret);

            for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
            {
                List <byte> blockHashList = new List <byte>();

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

                for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
                {
                    var block = content.Skip(BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex).Take(BLOCKBYTECOUNT).ToArray();

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

                    testSite.Assert.IsTrue(
                        blockHash.SequenceEqual((contentInfo.blocks[segmentIndex].BlockHashes).Skip(blockIndex * blockHashSize).Take(blockHashSize).ToArray()),
                        "The local calculated block hash in Segment: {0} Block: {1} should cosistent with the received value.", segmentIndex, blockIndex);

                    blockHashList.AddRange(blockHash);
                }

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

                testSite.Assert.IsTrue(
                    hod.SequenceEqual(contentInfo.segments[segmentIndex].SegmentHashOfData),
                    "The local calculated Hod should cosistent with the received value.");

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

                testSite.Assert.IsTrue(
                    kp.SequenceEqual(contentInfo.segments[segmentIndex].SegmentSecret),
                    "The local calculated Kp should cosistent with the received value.");
            }
        }
        public Content_Information_Data_Structure CreateContentInformationV1()
        {
            var contentInformation = new Content_Information_Data_Structure
            {
                Version    = 0x0100,
                dwHashAlgo = dwHashAlgo_Values.SHA256,
                cSegments  = 1,
                segments   = new SegmentDescription[]
                {
                    new SegmentDescription
                    {
                        cbBlockSize        = DefaultBlockSize,
                        cbSegment          = DefaultBlockSize,
                        SegmentHashOfData  = TestUtility.GenerateRandomArray(32),
                        SegmentSecret      = TestUtility.GenerateRandomArray(32),
                        ullOffsetInContent = 0
                    }
                },
                dwOffsetInFirstSegment   = 0,
                dwReadBytesInLastSegment = DefaultBlockSize,
                blocks = new SegmentContentBlocks[]
                {
                    new SegmentContentBlocks
                    {
                        cBlocks     = 1,
                        BlockHashes = TestUtility.GenerateRandomArray(32),
                    }
                }
            };

            return(contentInformation);
        }
        /// <summary>
        /// This action is used to send SEGMENT_INFO_MESSAGE request to and receive the
        /// correspondent Response Message from the hosted cache server.
        /// </summary>
        /// <param name="paddingInMessageHeader">An array formed by bytes for message header padding</param>
        /// <param name="pccrrPort">The port on which MS-PCCRR server-role will be listening. </param>
        /// <param name="paddingInConnectionInformation">An array formed by bytes for connection information padding</param>
        /// <param name="segmentInformation">The segment information.</param>
        /// <returns>Return the response message of the SegmentInfoMessage</returns>
        public ResponseMessage SendSegmentInfoMessage(
            byte[] paddingInMessageHeader,
            int pccrrPort,
            byte[] paddingInConnectionInformation,
            SegmentInformation segmentInformation)
        {
            // Convert the struct segmentInformation in adapter to the format in stack
            Content_Information_Data_Structure segmentInformationStack =
                ServerHelper.ConvertTostackForContentInfo(segmentInformation);

            // Create the SEGMENT_INFO_MESSAGE struct defined in stack for SendSegmentInfoMessage method
            SEGMENT_INFO_MESSAGE segmentInfoMessage = this.pchcClient.CreateSegmentInfoMessage(
                pccrrPort,
                segmentInformationStack);

            segmentInfoMessage.MsgHeader.Padding      = paddingInMessageHeader;
            segmentInfoMessage.ConnectionInfo.Padding = paddingInConnectionInformation;

            this.ValidateSegmentInfoMessage(segmentInfoMessage);
            try
            {
                RESPONSE_MESSAGE responseMessageStack = this.pchcClient.SendSegmentInfoMessage(segmentInfoMessage);

                ResponseMessage responseMessage = ServerHelper.ConvertFromStackForResponseMsg(responseMessageStack);

                this.ValidateSegmentInfoResponse(responseMessage);

                return(responseMessage);
            }
            catch (NoRESPONSEMESSAGEException)
            {
                throw new NoResponseMessageException();
            }
        }
        /// <summary>
        /// Get the content Info 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="uri"> The path of the file to request.</param>
        /// <returns> Returns content information if success.</returns>
        public Content_Information_Data_Structure GetContentInfo(string serverAddress, int port, string uri)
        {
            if (this.pccrtpResponse == null)
            {
                this.GetPccrtpResponse(serverAddress, port, uri);
            }

            Content_Information_Data_Structure contentInfoStack = this.pccrtpResponse.ContentInfo;

            return(contentInfoStack);
        }
        /// <summary>
        /// Offer the block hashes to the hosted cache server.
        /// </summary>
        /// <param name="contentInfo">The content information</param>
        public void OfferHostedCacheContentInfo(Content_Information_Data_Structure contentInfo)
        {
            // It's important to make sure the hosted cache server having the block hash.
            int connectionInfoPort = int.Parse(Site.Properties["PCHC.SegmentInfoMessage.PccrrTransPort"]);

            SEGMENT_INFO_MESSAGE segmentInfoMsgStack = this.pchcClient.CreateSegmentInfoMessage(
                connectionInfoPort,
                contentInfo);

            this.pchcClient.SendSegmentInfoMessage(segmentInfoMsgStack);
        }
Example #7
0
        /// <summary>
        /// Convert the ContentInformaiton struct defined in stack to adapter
        /// </summary>
        /// <param name="contentInfoStack">The contentInformation  defined in pccrc</param>
        /// <returns>Return the ContentInformaiton type defined in adapter</returns>
        public static SegmentInformation ConvertFromstackForContentInfo(Content_Information_Data_Structure contentInfoStack)
        {
            SegmentInformation contentInfo;

            contentInfo.DwHashAlgo               = ConvertFromStackFordwHash(contentInfoStack.dwHashAlgo);
            contentInfo.DwOffsetInFirstSegment   = contentInfoStack.dwOffsetInFirstSegment;
            contentInfo.DwReadBytesInLastSegment = contentInfoStack.dwReadBytesInLastSegment;
            contentInfo.Version   = contentInfoStack.Version;
            contentInfo.CSegments = contentInfoStack.cSegments;
            contentInfo.Blocks    = ConvertFromStackForSegBlocks(contentInfoStack.blocks);
            contentInfo.Segments  = ConvertFromStackForSegDescription(contentInfoStack.segments);

            return(contentInfo);
        }
        /// <summary>
        /// Generate PCCRTP response message to reply the client request.
        /// </summary>
        /// <param name="resourceLocator">The client request URI.</param>
        /// <param name="serverSecret">The server secret set on the server endpoint.</param>
        /// <returns>Returns the PCCRTP response message.</returns>
        public PccrtpResponse GenerateResponseMessage(string resourceLocator, string serverSecret)
        {
            PccrtpResponse pccrtpResponse = new PccrtpResponse();
            Dictionary <string, string> tempHttpHeader = new Dictionary <string, string>();
            HashGeneration hashHelp = new HashGeneration(serverSecret, dwHashAlgo_Values.SHA256);

            byte[] fileData = PccrcUtility.ReadFile(resourceLocator);
            Content_Information_Data_Structure contentInfo = hashHelp.GenerateContentInformation(fileData);

            tempHttpHeader.Add(CONTENTENCODING, "peerdist");
            tempHttpHeader.Add(XP2PPEERDIST, "Version=1.0, ContentLength=" + fileData.Length);
            pccrtpResponse.HttpHeader = tempHttpHeader;

            pccrtpResponse.PayloadData = contentInfo.ToByteArray();

            return(pccrtpResponse);
        }
        public void HostedCacheServer_PchcServer_InitialOffer_SegmentInfoRetrieved()
        {
            CheckApplicability();

            Content_Information_Data_Structure contentInformation = contentInformationUtility.CreateContentInformationV1();

            PCHCClient pchcClient = new PCHCClient(
                TransferProtocol.HTTPS,
                testConfig.HostedCacheServerComputerName,
                testConfig.HostedCacheServerHTTPSListenPort,
                PchcConsts.HttpsUrl,
                testConfig.DomainName,
                testConfig.UserName,
                testConfig.UserPassword);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Send initial offer message to hosted cache server");

            INITIAL_OFFER_MESSAGE initialOfferMessage = pchcClient.CreateInitialOfferMessage(
                testConfig.ClientContentRetrievalListenPort,
                contentInformation.GetSegmentId(0));

            pchcClient.SendInitialOfferMessage(initialOfferMessage);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Supply segment info to hosted cache server");

            SEGMENT_INFO_MESSAGE segmentInfoMessage = pchcClient.CreateSegmentInfoMessage(
                testConfig.ClientContentRetrievalListenPort,
                contentInformation,
                0);

            pchcClient.SendSegmentInfoMessage(segmentInfoMessage);

            Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pchc.RESPONSE_MESSAGE responseMessage2 = pchcClient.SendInitialOfferMessage(initialOfferMessage);

            TestClassBase.BaseTestSite.Assert.AreEqual <RESPONSE_CODE>(
                RESPONSE_CODE.INTERESTED,
                responseMessage2.ResponseCode,
                @"The hosted cache MUST specify a response code of 0 
                        if it already has block hash.");
        }
        /// <summary>
        /// Validate pccrc cSegments part.
        /// </summary>
        /// <param name="segmentInformation">Content information data structure.</param>
        /// <param name="hashLength">The hash length.</param>
        private void ValidatePccrcCSegment(Content_Information_Data_Structure segmentInformation, int hashLength)
        {
            #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}",
                segmentInformation.segments.Length);

            // Verify MS-PCCRC requirement: MS-PCCRC_R67
            Site.CaptureRequirementIfAreEqual <uint>(
                segmentInformation.cSegments,
                (uint)segmentInformation.segments.Length,
                PCCRCDOCSHORTNAME,
                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 < segmentInformation.cSegments - 1; i++)
            {
                if (segmentInformation.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,
                PCCRCDOCSHORTNAME,
                69,
                @"[In SegmentDescription] Every segment except for the last segment must be exactly 
                32 megabytes in size");

            #endregion

            #region MS-PCCRC_R74
            bool isVerifyR74 = true;

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

            if (segmentInformation.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,
                PCCRCDOCSHORTNAME,
                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(segmentInformation.segments[0].cbSegment));

            // Verify MS-PCCRC requirement: MS-PCCRC_R75
            Site.CaptureRequirementIfAreEqual <int>(
                4,
                Marshal.SizeOf(segmentInformation.segments[0].cbSegment),
                PCCRCDOCSHORTNAME,
                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 cbSegment is {0}.",
                Marshal.SizeOf(segmentInformation.segments[0].cbBlockSize));

            // Verify MS-PCCRC requirement: MS-PCCRC_R76
            Site.CaptureRequirementIfAreEqual <int>(
                4,
                Marshal.SizeOf(segmentInformation.segments[0].cbBlockSize),
                PCCRCDOCSHORTNAME,
                76,
                @"[In SegmentDescription] cbBlockSize (4 bytes):  
                Length of a content block within this segment, in bytes.");

            #endregion

            #region MS-PCCRC_R77
            bool isVerifyR77 = true;
            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (segmentInformation.segments[i].cbBlockSize != 65536)
                {
                    isVerifyR77 = false;
                }
            }

            // 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,
                PCCRCDOCSHORTNAME,
                77,
                @"[In SegmentDescription] cbBlockSize (4 bytes): 
                Every segment MUST use the block size of 65536 bytes.");

            #endregion

            #region MS-PCCRC_R79
            bool isVerifyR79 = true;
            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (segmentInformation.segments[i].SegmentHashOfData.Length != hashLength)
                {
                    isVerifyR79 = false;
                }
            }

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

            // Verify MS-PCCRC requirement: MS-PCCRC_R79
            Site.CaptureRequirementIfIsTrue(
                isVerifyR79,
                PCCRCDOCSHORTNAME,
                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
            bool isVerifyR83 = true;
            for (int i = 0; i < segmentInformation.cSegments; i++)
            {
                if (segmentInformation.segments[i].SegmentSecret.Length != hashLength)
                {
                    isVerifyR83 = false;
                }
            }

            // 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,
                PCCRCDOCSHORTNAME,
                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>
        /// Validate the SegmentInformation in the Segment_info-Message.
        /// </summary>
        /// <param name="segmentInformation">The segmentInformation need to be validate.</param>
        private void ValidateSegmentInformation(Content_Information_Data_Structure segmentInformation)
        {
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R43:The SegmentInformation is an instance of  Content_Information_Data_Structure.");

            // Capture MS-PCHC R43
            Site.CaptureRequirement(
                43,
                @"[In SEGMENT_INFO_MESSAGE] SegmentInformation (variable): 
                A Content Information data structure ([MS-PCCRC] section 2.3).");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R45:The SegmentInformation is an instance of Content_Information_Data_Structure 
                which surely contains the subfields of the segment's Content Information data structure, 
                and SegmentContentBlocks. And can be validated unmarshalled correctly from stack.");

            // Capture MS-PCHC R45
            Site.CaptureRequirement(
                45,
                @"[In SEGMENT_INFO_MESSAGE] The SegmentInformation field also contains the subfields of 
                the segment's Content Information data structure, SegmentDescription, and SegmentContentBlocks, 
                as specified in [MS-PCCRC] sections 2.3.1.1 and 2.3.1.2, respectively.");

            // Capture MS-PCHC R49
            Site.CaptureRequirementIfAreEqual <uint>(
                1,
                segmentInformation.cSegments,
                49,
                "[In SEGMENT_INFO_MESSAGE, SEGMENT_INFORMATION (variable)] The cSegments field MUST be set to 1.");

            // Capture MS-PCHC R50
            Site.Assert.IsInstanceOfType(
                segmentInformation.segments,
                typeof(SegmentDescription[]),
                @"Validate the segments is SegmentDescription array, in MS-PCHC client, 
                only the size of the SegmentDescription will be verified,the actual is {0} array.",
                segmentInformation.segments);

            Site.CaptureRequirementIfAreEqual <int>(
                1,
                segmentInformation.segments.Length,
                50,
                @"[In SEGMENT_INFO_MESSAGE, SEGMENT_INFORMATION (variable)] The segments field MUST contain the single 
                SegmentDescription ([MS-PCCRC] section 2.3.1.1) in the original Content Information data structure 
                corresponding to the segment being offered.");

            // Capture MS-PCHC R51
            Site.Assert.IsInstanceOfType(
                segmentInformation.blocks,
                typeof(SegmentContentBlocks[]),
                @"Validate the blocks is SegmentContentBlocks array, in MS-PCHC client, 
                only the size of the SegmentContentBlocks will be verified, the actual is {0} array.",
                segmentInformation.blocks);

            Site.CaptureRequirementIfAreEqual <int>(
                1,
                segmentInformation.blocks.Length,
                51,
                @"[In SEGMENT_INFO_MESSAGE, SEGMENT_INFORMATION (variable)] The blocks field MUST 
                contain a single SegmentContentBlocks ([MS-PCCRC] section 2.3.1.2) corresponding 
                to the segment being offered, copied from the blocks field in the original 
                Content Information data structure.");
        }
        public void HostedCacheServer_PccrrClient_MessageHeader_CryptoAlgoId(CryptoAlgoId_Values algoId)
        {
            CheckApplicability();

            EventQueue eventQueue = new EventQueue(BaseTestSite);

            eventQueue.Timeout = testConfig.Timeout;

            byte[] content = TestUtility.GenerateRandomArray(ContentInformationUtility.DefaultBlockSize);
            Content_Information_Data_Structure contentInformation = contentInformationUtility.CreateContentInformationV1();

            ProtoVersion protoVersion = new ProtoVersion {
                MajorVersion = 1, MinorVersion = 0
            };

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Start PCCRR server to be ready to serve content to hosted cache server");

            using (PccrrTestServerV1 pccrrTestServer = new PccrrTestServerV1())
            {
                pccrrTestServer.Start(
                    testConfig.ClientContentRetrievalListenPort,
                    algoId,
                    protoVersion,
                    contentInformation,
                    content,
                    eventQueue);

                PCHCClient pchcClient = new PCHCClient(
                    TransferProtocol.HTTPS,
                    testConfig.HostedCacheServerComputerName,
                    testConfig.HostedCacheServerHTTPSListenPort,
                    PchcConsts.HttpsUrl,
                    testConfig.DomainName,
                    testConfig.UserName,
                    testConfig.UserPassword);

                SEGMENT_INFO_MESSAGE segmentInfoMessage = pchcClient.CreateSegmentInfoMessage(
                    testConfig.ClientContentRetrievalListenPort,
                    contentInformation,
                    0);
                pchcClient.SendSegmentInfoMessage(segmentInfoMessage);

                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Offer content block 0 of segment 0 to hosted cache server to hosted cache server");

                int blockCount = 0;
                TestUtility.DoUntilSucceed(delegate()
                {
                    eventQueue.Expect <MessageArrivedEventArgs>(typeof(PccrrServer).GetEvent("MessageArrived"), delegate(System.Net.IPEndPoint sender, PccrrPacket pccrrPacket)
                    {
                        var pccrrGetBlksRequest = pccrrPacket as PccrrGETBLKSRequestPacket;

                        if (pccrrGetBlksRequest != null)
                        {
                            blockCount++;
                        }
                    });
                    return(blockCount == 1);
                }, TimeSpan.MaxValue, TimeSpan.Zero);

                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Wait until cache is available on hosted cache server");

                TestUtility.DoUntilSucceed(() => sutControlAdapter.IsLocalCacheExisted(testConfig.HostedCacheServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval);
            }

            PccrrClient pccrrClient = new PccrrClient(testConfig.HostedCacheServerComputerName, testConfig.HostedCacheServerHTTPListenPort);
            Aes         aes         = PccrrUtitlity.CreateAes(algoId);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Retrieve block 0 of segment 0 from hosted cache server",
                0);
            PccrrGETBLKSRequestPacket pccrrBlkRequest = pccrrClient.CreateMsgGetBlksRequest(
                contentInformation.GetSegmentId(0),
                algoId,
                MsgType_Values.MSG_GETBLKS,
                (uint)0,
                1);

            pccrrClient.SendPacket(
                pccrrBlkRequest,
                testConfig.Timeout);
            PccrrBLKResponsePacket pccrrBlkResponse
                = (PccrrBLKResponsePacket)pccrrClient.ExpectPacket();

            byte[] block = pccrrBlkResponse.MsgBLK.Block;

            if (algoId != CryptoAlgoId_Values.NoEncryption)
            {
                block = PccrrUtitlity.Decrypt(aes, block, contentInformation.segments[0].SegmentSecret, pccrrBlkResponse.MsgBLK.IVBlock);
            }

            BaseTestSite.Assert.IsTrue(
                Enumerable.SequenceEqual(content, block),
                "The retrieved cached data should be the same as server data.");
        }
        public void HostedCacheServer_PccrrClient_MessageHeader_ProtoVerIncompatible()
        {
            CheckApplicability();

            EventQueue eventQueue = new EventQueue(BaseTestSite);

            eventQueue.Timeout = testConfig.Timeout;

            Content_Information_Data_Structure contentInformation = contentInformationUtility.CreateContentInformationV1();

            CryptoAlgoId_Values cryptoAlgoId = CryptoAlgoId_Values.AES_128;
            ProtoVersion        protoVersion = new ProtoVersion {
                MajorVersion = 1, MinorVersion = 0
            };

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Start PCCRR server to be ready to serve content to hosted cache server");
            using (PccrrTestIncompatibleProtoVerServer pccrrTestServer = new PccrrTestIncompatibleProtoVerServer())
            {
                pccrrTestServer.Start(
                    testConfig.ClientContentRetrievalListenPort,
                    cryptoAlgoId,
                    protoVersion,
                    contentInformation,
                    new byte[0],
                    eventQueue);

                PCHCClient pchcClient = new PCHCClient(
                    TransferProtocol.HTTPS,
                    testConfig.HostedCacheServerComputerName,
                    testConfig.HostedCacheServerHTTPSListenPort,
                    PchcConsts.HttpsUrl,
                    testConfig.DomainName,
                    testConfig.UserName,
                    testConfig.UserPassword);

                SEGMENT_INFO_MESSAGE segmentInfoMessage = pchcClient.CreateSegmentInfoMessage(
                    testConfig.ClientContentRetrievalListenPort,
                    contentInformation,
                    0);
                pchcClient.SendSegmentInfoMessage(segmentInfoMessage);


                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Offer PccrrBLKSResponse with incompatible proto version to hosted cache server");
                int blockCount = 0;
                TestUtility.DoUntilSucceed(delegate()
                {
                    eventQueue.Expect <MessageArrivedEventArgs>(typeof(PccrrServer).GetEvent("MessageArrived"), delegate(System.Net.IPEndPoint sender, PccrrPacket pccrrPacket)
                    {
                        var pccrrGetBlksRequest = pccrrPacket as PccrrGETBLKSRequestPacket;

                        if (pccrrGetBlksRequest != null)
                        {
                            blockCount++;
                        }
                    });
                    return(blockCount == 1);
                }, TimeSpan.MaxValue, TimeSpan.Zero);

                TestUtility.DoUntilSucceed(() => sutControlAdapter.IsLocalCacheExisted(testConfig.HostedCacheServerComputerFQDNOrNetBiosName), testConfig.NegativeTestTimeout, testConfig.RetryInterval);
            }
        }
        public void HostedCacheServer_PchcServer_InitialOffer_ContentRereieved()
        {
            CheckApplicability();

            EventQueue eventQueue = new EventQueue(BaseTestSite);

            eventQueue.Timeout = testConfig.Timeout;

            Content_Information_Data_Structure contentInformation = contentInformationUtility.CreateContentInformationV1();

            CryptoAlgoId_Values cryptoAlgoId = CryptoAlgoId_Values.AES_128;

            using (PccrrTestServerV1 pccrrTestServer = new PccrrTestServerV1())
            {
                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Start PCCRR server to be ready to serve content to hosted cache server");

                pccrrTestServer.Start(
                    testConfig.ClientContentRetrievalListenPort,
                    cryptoAlgoId,
                    new ProtoVersion {
                    MajorVersion = 1, MinorVersion = 0
                },
                    contentInformation,
                    TestUtility.GenerateRandomArray(ContentInformationUtility.DefaultBlockSize),
                    eventQueue);

                PCHCClient pchcClient = new PCHCClient(
                    TransferProtocol.HTTPS,
                    testConfig.HostedCacheServerComputerName,
                    testConfig.HostedCacheServerHTTPSListenPort,
                    PchcConsts.HttpsUrl,
                    testConfig.DomainName,
                    testConfig.UserName,
                    testConfig.UserPassword);

                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Send initial offer message to hosted cache server");

                SEGMENT_INFO_MESSAGE segmentInfoMessage = pchcClient.CreateSegmentInfoMessage(
                    testConfig.ClientContentRetrievalListenPort,
                    contentInformation,
                    0);
                pchcClient.SendSegmentInfoMessage(segmentInfoMessage);

                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Make sure all blocks in segment 0 are retrieved by hosted cache server");

                int blockCount = 0;
                TestUtility.DoUntilSucceed(delegate()
                {
                    eventQueue.Expect <MessageArrivedEventArgs>(typeof(PccrrServer).GetEvent("MessageArrived"), delegate(System.Net.IPEndPoint sender, PccrrPacket pccrrPacket)
                    {
                        var pccrrGetBlksRequest = pccrrPacket as PccrrGETBLKSRequestPacket;

                        if (pccrrGetBlksRequest != null)
                        {
                            blockCount++;
                        }
                    });
                    return(blockCount == contentInformation.segments[0].BlockCount);
                }, TimeSpan.MaxValue, TimeSpan.Zero);

                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Wait until cache is available on hosted cache server");

                TestUtility.DoUntilSucceed(() => sutControlAdapter.IsLocalCacheExisted(testConfig.HostedCacheServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval);

                INITIAL_OFFER_MESSAGE initialOfferMessage = pchcClient.CreateInitialOfferMessage(
                    testConfig.ClientContentRetrievalListenPort,
                    contentInformation.GetSegmentId(0));
                Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pchc.RESPONSE_MESSAGE responseMessage2
                    = pchcClient.SendInitialOfferMessage(initialOfferMessage);

                TestClassBase.BaseTestSite.Assert.AreEqual <RESPONSE_CODE>(
                    RESPONSE_CODE.INTERESTED,
                    responseMessage2.ResponseCode,
                    @"The hosted cache MUST specify a response code of 0 
                        if it already has block data and block hash.");
            }
        }
Example #15
0
        public void HostedCacheServer_BVT_CacheOfferingRetrieval_V1()
        {
            CheckApplicability();

            EventQueue eventQueue = new EventQueue(BaseTestSite);

            eventQueue.Timeout = testConfig.Timeout;

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Trigger hash generation on content server");

            byte[] content = contentInformationUtility.RetrieveContentData();

            Content_Information_Data_Structure contentInformation =
                PccrcUtility.ParseContentInformation(contentInformationUtility.RetrieveContentInformation(BranchCacheVersion.V1));

            CryptoAlgoId_Values cryptoAlgoId = CryptoAlgoId_Values.AES_128;

            PccrrClient pccrrClient = new PccrrClient(testConfig.HostedCacheServerComputerName, testConfig.HostedCacheServerHTTPListenPort);

            for (int i = 0; i < contentInformation.cSegments; ++i)
            {
                var pccrrBlkListRequest = pccrrClient.CreateMsgGetBlkListRequest(
                    contentInformation.GetSegmentId(i),
                    new BLOCK_RANGE[] { new BLOCK_RANGE {
                                            Index = 0, Count = contentInformation.segments[i].BlockCount
                                        } },
                    cryptoAlgoId,
                    MsgType_Values.MSG_GETBLKLIST);
                pccrrClient.SendPacket(
                    pccrrBlkListRequest,
                    testConfig.Timeout);
                var pccrrBlkListResponse
                    = (PccrrBLKLISTResponsePacket)pccrrClient.ExpectPacket();

                BaseTestSite.Assert.AreEqual <uint>(
                    0,
                    pccrrBlkListResponse.MsgBLKLIST.BlockRangeCount,
                    "The server MUST set the BlockRangeCount field to zero if it doesn't have the requested blocks data.");
            }

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Retrieve content information from content server");

            using (PccrrTestServerV1 pccrrTestServer = new PccrrTestServerV1())
            {
                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Start PCCRR server to be ready to serve content to hosted cache server");

                pccrrTestServer.Start(
                    testConfig.ClientContentRetrievalListenPort,
                    cryptoAlgoId,
                    contentInformation,
                    content,
                    eventQueue);

                PCHCClient pchcClient = new PCHCClient(
                    TransferProtocol.HTTPS,
                    testConfig.HostedCacheServerComputerName,
                    testConfig.HostedCacheServerHTTPSListenPort,
                    PchcConsts.HttpsUrl,
                    testConfig.DomainName,
                    testConfig.UserName,
                    testConfig.UserPassword);

                for (int i = 0; i < contentInformation.cSegments; i++)
                {
                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Offer content segment {0} to hosted cache server",
                        i);

                    INITIAL_OFFER_MESSAGE initialOfferMessage = pchcClient.CreateInitialOfferMessage(
                        testConfig.ClientContentRetrievalListenPort,
                        contentInformation.GetSegmentId(i));
                    Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pchc.RESPONSE_MESSAGE responseMessage
                        = pchcClient.SendInitialOfferMessage(initialOfferMessage);

                    TestClassBase.BaseTestSite.Assert.AreEqual <RESPONSE_CODE>(
                        RESPONSE_CODE.INTERESTED,
                        responseMessage.ResponseCode,
                        @"The hosted cache MUST specify a response code of 1 
                        if its list of block hashes associated with the segment is incomplete.");

                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Supply segment info to hosted cache server");

                    SEGMENT_INFO_MESSAGE segmentInfoMessage = pchcClient.CreateSegmentInfoMessage(
                        testConfig.ClientContentRetrievalListenPort,
                        contentInformation,
                        i);
                    responseMessage = pchcClient.SendSegmentInfoMessage(segmentInfoMessage);

                    TestClassBase.BaseTestSite.Assert.AreEqual <RESPONSE_CODE>(
                        RESPONSE_CODE.OK,
                        responseMessage.ResponseCode,
                        @"The hosted cache MUST send a response code of 0 when SEGMENT_INFO_MESSAGE request received");

                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Make sure all blocks in segment {0} are retrieved by hosted cache server",
                        i);

                    int blockCount = 0;
                    TestUtility.DoUntilSucceed(delegate()
                    {
                        eventQueue.Expect <MessageArrivedEventArgs>(typeof(PccrrServer).GetEvent("MessageArrived"), delegate(System.Net.IPEndPoint sender, PccrrPacket pccrrPacket)
                        {
                            var pccrrGetBlksRequest = pccrrPacket as PccrrGETBLKSRequestPacket;

                            if (pccrrGetBlksRequest != null)
                            {
                                blockCount++;
                            }
                        });
                        return(blockCount == contentInformation.segments[i].BlockCount);
                    }, TimeSpan.MaxValue, TimeSpan.Zero);
                }

                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Wait until cache is available on hosted cache server");

                TestUtility.DoUntilSucceed(() => sutControlAdapter.IsLocalCacheExisted(testConfig.HostedCacheServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval);
            }

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

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Negotiate PCCRR version");

            var pccrrNegotiateRequest = pccrrClient.CreateMsgNegoRequest(
                new ProtoVersion {
                MajorVersion = 1, MinorVersion = 0
            },
                new ProtoVersion {
                MajorVersion = 1, MinorVersion = ushort.MaxValue
            },
                cryptoAlgoId,
                MsgType_Values.MSG_NEGO_REQ);

            pccrrClient.SendPacket(
                pccrrNegotiateRequest,
                testConfig.Timeout);
            var pccrrNegotiateResponse
                = (PccrrNegoResponsePacket)pccrrClient.ExpectPacket();

            if (testConfig.SupportBranchCacheV1)
            {
                BaseTestSite.Assert.IsTrue(
                    pccrrNegotiateResponse.MsgNegoResp.MinSupporteProtocolVersion.MajorVersion <= 1 &&
                    pccrrNegotiateResponse.MsgNegoResp.MaxSupporteProtocolVersion.MajorVersion >= 1,
                    "SupportedProtocolVersion doesn't match configuration");
            }

            if (testConfig.SupportBranchCacheV2)
            {
                BaseTestSite.Assert.IsTrue(
                    pccrrNegotiateResponse.MsgNegoResp.MinSupporteProtocolVersion.MajorVersion <= 2 &&
                    pccrrNegotiateResponse.MsgNegoResp.MaxSupporteProtocolVersion.MajorVersion >= 2,
                    "SupportedProtocolVersion doesn't match configuration");
            }

            Aes aes = PccrrUtitlity.CreateAes(cryptoAlgoId);

            for (int i = 0; i < contentInformation.cSegments; i++)
            {
                BaseTestSite.Log.Add(
                    LogEntryKind.Debug,
                    "Retrieve block list for segment {0}",
                    i);

                var pccrrBlkListRequest = pccrrClient.CreateMsgGetBlkListRequest(
                    contentInformation.GetSegmentId(i),
                    new BLOCK_RANGE[] { new BLOCK_RANGE {
                                            Index = 0, Count = contentInformation.segments[i].BlockCount
                                        } },
                    cryptoAlgoId,
                    MsgType_Values.MSG_GETBLKLIST);
                pccrrClient.SendPacket(
                    pccrrBlkListRequest,
                    testConfig.Timeout);
                var pccrrBlkListResponse
                    = (PccrrBLKLISTResponsePacket)pccrrClient.ExpectPacket();

                BaseTestSite.Assert.AreNotEqual <uint>(
                    0,
                    pccrrBlkListResponse.MsgBLKLIST.BlockRangeCount,
                    "The server MUST set the BlockRangeCount field to a value greater than zero if it has the requested blocks data.");

                for (int j = 0; j < contentInformation.segments[i].BlockCount; j++)
                {
                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Retrieve block {0} for segment {1}",
                        j,
                        i);

                    PccrrGETBLKSRequestPacket pccrrBlkRequest = pccrrClient.CreateMsgGetBlksRequest(
                        contentInformation.GetSegmentId(i),
                        cryptoAlgoId,
                        MsgType_Values.MSG_GETBLKS,
                        (uint)j,
                        1);
                    pccrrClient.SendPacket(
                        pccrrBlkRequest,
                        testConfig.Timeout);
                    PccrrBLKResponsePacket pccrrBlkResponse
                        = (PccrrBLKResponsePacket)pccrrClient.ExpectPacket();

                    BaseTestSite.Assert.AreNotEqual <uint>(
                        0,
                        pccrrBlkResponse.MsgBLK.SizeOfBlock,
                        "The server MUST set the SizeOfBlock field to a value greater than zero if it has the requested blocks data.");

                    byte[] block = pccrrBlkResponse.MsgBLK.Block;

                    if (cryptoAlgoId != CryptoAlgoId_Values.NoEncryption)
                    {
                        block = PccrrUtitlity.Decrypt(aes, block, contentInformation.segments[i].SegmentSecret, pccrrBlkResponse.MsgBLK.IVBlock);
                    }

                    retrievedContent.AddRange(block);
                }
            }

            BaseTestSite.Assert.IsTrue(
                Enumerable.SequenceEqual(content, retrievedContent),
                "The retrieved cached data should be the same as server data.");
        }
        /// <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 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>
        /// Validate the segmentInformation In SEGMTNE_INFO_MESSAGE.
        /// </summary>
        /// <param name="segmentInformation">The segmetnInformation.</param>
        private void ValidateSegmentInformationFromPccrc(Content_Information_Data_Structure segmentInformation)
        {
            int valueOfDwHashAlgo = 0;
            int hashLength        = 0;

            switch (segmentInformation.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;
            }

            #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,
                PCCRCDOCSHORTNAME,
                54,
                @"[In Content Information Data Structure Version] All fields[Version,dwHashAlgo,
                dwOffsetInFirstSegment,dwReadBytesInLastSegment,cSegments,segments (variable),
                blocks (variable)]  are in little-endian byte order.");

            #endregion

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

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

            #endregion

            this.ValidatePccrcSegmentInfoVersion(segmentInformation, valueOfDwHashAlgo, hashLength);

            this.ValidatePccrcCSegment(segmentInformation, hashLength);

            #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}",
                segmentInformation.blocks.Length);

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

            #endregion

            #region MS-PCCRC_R89

            bool isVerifyR89 = true;

            foreach (SegmentContentBlocks segContentBlocks in segmentInformation.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} cBlokcs * {1}",
                isVerifyR89 ? string.Empty : "not ",
                hashLength);

            // Verify MS-PCCRC requirement: MS-PCCRC_R89
            Site.CaptureRequirementIfIsTrue(
                isVerifyR89,
                PCCRCDOCSHORTNAME,
                89,
                @"[In SegmentContentBlocks] BlockHashes (variable):The size of this field is 
                cBlocks * (32, 48 or 64, depending on which hash was used).");
            #endregion
        }
Example #19
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>
        /// Validate pccrc segment info version part.
        /// </summary>
        /// <param name="segmentInformation">Content Information data structure.</param>
        /// <param name="valueOfDwHashAlgo">Value of DwHashAlgo.</param>
        /// <param name="hashLength">The length of hash.</param>
        private void ValidatePccrcSegmentInfoVersion(Content_Information_Data_Structure segmentInformation, int valueOfDwHashAlgo, int hashLength)
        {
            #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}",
                segmentInformation.Version);

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

            #endregion

            #region MS-PCCRC_R53
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R53:Content Information starts the data structure version.
                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 captured directly.");

            Site.CaptureRequirement(
                PCCRCDOCSHORTNAME,
                53,
                @"[In Content Information Data Structure Version] Content Information starts with 
                a single 2 byte WORD value representing the data structure version.");

            #endregion

            #region MS-PCCRC_R56
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R56, 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 
                numberand the high byte is the major version number.");

            Site.CaptureRequirement(
                PCCRCDOCSHORTNAME,
                56,
                @"[In Content Information Data Structure Version] Version (2 bytes):  The low byte is the minor
                version number and the high byte is the major version number.");

            #endregion

            #region MS-PCCRC_R58

            // 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),
                PCCRCDOCSHORTNAME,
                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,
                PCCRCDOCSHORTNAME,
                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, When segmentInformation.dwHashAlgo is 0x0000800C, 
                it is the SHA-256 hash algorithm. The actual value of dwHashAlgo is 0x{0:X8}.",
                valueOfDwHashAlgo);

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

            #endregion

            #region MS-PCCRC_R62

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R62, dwOffsetInFirstSegment (4 bytes). 
                In MS-PCHC client, only the size of the dwOffsetInFirstSegment will be verified.");

            // Verify MS-PCCRC requirement: MS-PCCRC_R62
            Site.CaptureRequirementIfAreEqual <int>(
                Marshal.SizeOf(segmentInformation.dwOffsetInFirstSegment),
                4,
                PCCRCDOCSHORTNAME,
                62,
                @"[In Content Information Data Structure Version] dwOffsetInFirstSegment (4 bytes):  
                Number of bytes into the first segment within the Content Information data structure at 
                which the content range begins.");
            #endregion

            #region MS-PCCRC_R63
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCCRC_R63, dwReadBytesInLastSegment (4 bytes).
                In MS_PCHC client, only the size of the dwReadBytesInLastSegment will be verified.");

            // Verify MS-PCCRC requirement: MS-PCCRC_R63
            Site.CaptureRequirementIfAreEqual <int>(
                Marshal.SizeOf(segmentInformation.dwReadBytesInLastSegment),
                4,
                PCCRCDOCSHORTNAME,
                63,
                @"[In Content Information Data Structure Version] dwReadBytesInLastSegment (4 bytes):  
                Total number of bytes of the content range which lie within the final segment in the 
                Content Information data structure.");
            #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}, 
                the size of the cSegments is {1} bytes.",
                segmentInformation.cSegments,
                Marshal.SizeOf(segmentInformation.cSegments));

            // Verify MS-PCCRC requirement: MS-PCCRC_R64
            Site.CaptureRequirementIfAreEqual <int>(
                segmentInformation.segments.Length,
                (int)segmentInformation.cSegments,
                PCCRCDOCSHORTNAME,
                64,
                @"[In Content Information Data Structure Version] 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 < segmentInformation.cSegments; i++)
            {
                if (!(segmentInformation.segments[i].cbBlockSize == 65536 &&
                      segmentInformation.segments[i].SegmentHashOfData.Length == hashLength &&
                      segmentInformation.segments[i].SegmentSecret.Length == hashLength))
                {
                    isVerifyR65 = false;
                    break;
                }
            }

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

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

            #endregion
        }
        public void Start(int port, CryptoAlgoId_Values cryptoAlgoId, ProtoVersion protoVersion, Content_Information_Data_Structure contentInformation, byte[] content, EventQueue eventQueue)
        {
            this.contentInformation = contentInformation;

            base.Start(port, cryptoAlgoId, protoVersion, content, eventQueue);
        }