/// <summary> /// Get the pccrtp response with http header "peerdist". /// </summary> /// <param name="serverAddress"> The content server address.</param> /// <param name="port"> The port that the content server is listening.</param> /// <param name="uri"> The path of the file to request.</param> /// <returns>Only true can be returned that specifies the pccrtp response with /// http header "peerdist" is received.</returns> /// <exception cref="Exception">No http response with "peerdist" header is received,</exception> private bool GetPccrtpResponse(string serverAddress, int port, string uri) { PccrtpRequest pccrtpRequest = this.pccrtpStackClient.CreatePccrtpRequest(serverAddress, port, uri); PccrtpResponse pccrtpResponseTemp = this.pccrtpStackClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, int.Parse(Site.Properties["PCCRTP.Protocol.TimeOut"]) * 1000); int timesOfSendingPccrtpMsg = 1; while (!pccrtpResponseTemp.HttpResponse.ContentEncoding.Equals("peerdist")) { if (timesOfSendingPccrtpMsg >= 3) { throw new InvalidOperationException(string.Format( "Send {0} times Pccrtp request message, no http response with \"peerdist\" header is received.", timesOfSendingPccrtpMsg)); } pccrtpResponseTemp = this.pccrtpStackClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, int.Parse(Site.Properties["PCCRTP.Protocol.TimeOut"]) * 1000); timesOfSendingPccrtpMsg++; } this.pccrtpResponse = pccrtpResponseTemp; return(true); }
/// <summary> /// Generate and send an PCCRTP response message to the HTTP/1.1 client (SUT) when testing client endpoint. /// </summary> /// <param name="requestFileFullPath">Indicate that local full path of the requested file on the driver computer. /// </param> public void SendPccrtpResponseMessage(string requestFileFullPath) { PccrtpResponse pccrtpResponse = this.pccrtpServerStack.GenerateResponseMessage( requestFileFullPath, Site.Properties["PCCRTP.Protocol.ServerSecret"]); this.pccrtpServerStack.SentPccrtpResponse(pccrtpResponse); }
/// <summary> /// Reset the adapter /// </summary> public override void Reset() { base.Reset(); this.isReceived = false; this.pccrtpResponse = null; if (this.pccrrServer != null) { this.pccrrServer.CloseConnections(); this.pccrrServer = null; } }
public void ContentServer_PccrtpServer_ContentInformationVersionIncompatible() { CheckApplicability(); PccrtpClient pccrtpClient = new PccrtpClient(); PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest( testConfig.ContentServerComputerName, testConfig.ContentServerHTTPListenPort, testConfig.NameOfFileWithMultipleBlocks, BranchCacheVersion.V2); BaseTestSite.Log.Add( LogEntryKind.Debug, "Send PCCRTP request to trigger hash generation"); PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, (int)testConfig.Timeout.TotalMilliseconds); var contentBeforeHashGeneration = pccrtpResponse.PayloadData; BaseTestSite.Log.Add( LogEntryKind.Debug, "Wait until the hash is generated on content server"); TestUtility.DoUntilSucceed(() => sutControlAdapter.IsHTTPHashExisted(testConfig.ContentServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval); BaseTestSite.Log.Add( LogEntryKind.Debug, "Modify to an incompatible version"); pccrtpRequest.HttpHeader[PccrtpConsts.XP2PPeerDistExHttpHeader] = "MinContentInformation=900.0, MaxContentInformation=999.0"; pccrtpResponse = pccrtpClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, (int)testConfig.Timeout.TotalMilliseconds); var contentAfterHashGeneration = pccrtpResponse.PayloadData; BaseTestSite.Assert.AreNotEqual( "peerdist", pccrtpResponse.HttpResponse.ContentEncoding, "The content server should return file content when content information version is incompatible"); BaseTestSite.Assert.IsTrue( contentAfterHashGeneration.SequenceEqual(contentBeforeHashGeneration), "The content server should return file content when content information version is incompatible"); }
/// <summary> /// Verify requirements about content information structure. /// </summary> /// <param name="pccrtpResponse">The PCCRTP response message.</param> private void VerifyContentInfomationStructure(PccrtpResponse pccrtpResponse) { Site.DefaultProtocolDocShortName = "MS-PCCRC"; this.VerifyContentSegmentsBlocks(pccrtpResponse); this.VerifySegmentIdentifiersAndKeys(pccrtpResponse); this.VerifyDataStructure(pccrtpResponse); this.VerifySegmentDescription(pccrtpResponse); this.VerifySegmentContentBlocks(pccrtpResponse); Site.DefaultProtocolDocShortName = "MS-PCCRTP"; }
/// <summary> /// Get the segment IDs computed using content information that is got from the content server. /// </summary> /// <param name="serverAddress"> The content server address.</param> /// <param name="port"> The port that the content server is listening.</param> /// <param name="path"> The path of the file to request.</param> /// <returns> Returns content info if success.</returns> public string[] GetSegmentIds(string serverAddress, int port, string path) { PccrtpRequest pccrtpRequest = this.pccrtpStackClient.CreatePccrtpRequest(serverAddress, port, path); PccrtpResponse pccrtpStackResponse = this.pccrtpStackClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, int.Parse(Site.Properties["PCCRR.Protocol.timeout"]) * 1000); List <byte[]> segmentIDs = (List <byte[]>) this.pccrtpStackClient.GetSegmentId(pccrtpStackResponse); List <string> segmentIdStr = new List <string>(); foreach (byte[] segmentId in segmentIDs) { segmentIdStr.Add(ToHexString(segmentId)); } return(segmentIdStr.ToArray()); }
public void ContentServer_PccrtpServer_MissingDataRequestFalse() { CheckApplicability(); PccrtpClient pccrtpClient = new PccrtpClient(); PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest( testConfig.ContentServerComputerName, testConfig.ContentServerHTTPListenPort, testConfig.NameOfFileWithMultipleBlocks); BaseTestSite.Log.Add( LogEntryKind.Debug, "Send PCCRTP request to trigger hash generation"); PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, (int)testConfig.Timeout.TotalMilliseconds); BaseTestSite.Log.Add( LogEntryKind.Debug, "Wait until the hash is generated on content server"); TestUtility.DoUntilSucceed(() => sutControlAdapter.IsHTTPHashExisted(testConfig.ContentServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval); BaseTestSite.Log.Add( LogEntryKind.Debug, "Modify to an incompatible version"); pccrtpRequest.HttpHeader[PccrtpConsts.XP2PPeerDistHttpHeader] = "Version=1.0, MissingDataRequest=false"; pccrtpResponse = pccrtpClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, (int)testConfig.Timeout.TotalMilliseconds); BaseTestSite.Assert.AreEqual( "peerdist", pccrtpResponse.HttpResponse.ContentEncoding, "The content server should return content information when MissingDataRequest is false"); }
/// <summary> /// Send a PCCRTP request message and receive a PCCRTP response message. /// </summary> /// <param name="httpVersion">Indicates the HTTP version type used.</param> /// <param name="isRequestPartialContent">Indicates it is requesting partical content or not.</param> /// <param name="uri">Indicates the URI on the SUT requested by the client.</param> /// <returns>Return the PCCRTP response message received.</returns> public PccrtpResponse SendPccrtpRequestMessage( HttpVersionType httpVersion, bool isRequestPartialContent, string uri) { PccrtpRequest pccrtpRequest = new PccrtpRequest(); PccrtpResponse pccrtpResponse = new PccrtpResponse(); string serverAddress = this.GetProperty("Environment.ContentServer.MachineName"); int port = int.Parse(this.GetProperty("Environment.ContentServer.HTTP.Port")); int timeOut = (int)TimeSpan.FromSeconds( double.Parse(this.GetProperty("PCCRTP.Protocol.TimeOut"))).TotalMilliseconds; int rangeFrom = int.Parse(this.GetProperty("PCCRTP.Protocol.RangeFrom")); int rangeTo = int.Parse(this.GetProperty("PCCRTP.Protocol.RangeTo")); if (isRequestPartialContent) { pccrtpRequest = this.pccrtpClientStack.CreatePccrtpRequest(serverAddress, port, uri); pccrtpResponse = this.pccrtpClientStack.SendHttpRequest( httpVersion, pccrtpRequest, timeOut, rangeFrom, rangeTo); } else { pccrtpRequest = this.pccrtpClientStack.CreatePccrtpRequest(serverAddress, port, uri); pccrtpResponse = this.pccrtpClientStack.SendHttpRequest(httpVersion, pccrtpRequest, timeOut); } if (pccrtpResponse.HttpResponse.ContentEncoding.Equals("peerdist")) { PccrtpBothRoleCapture.VerifyTransport(pccrtpResponse.HttpResponse.ProtocolVersion.ToString()); PccrtpBothRoleCapture.VerifyPccrtpCommonHeader(pccrtpResponse.HttpHeader); this.VerifyPccrtpResponse(pccrtpResponse); this.VerifyContentInfomationStructure(pccrtpResponse); } return(pccrtpResponse); }
public void ContentServer_PccrtpServer_ContentEncodingNotHavePeerDist() { CheckApplicability(); PccrtpClient pccrtpClient = new PccrtpClient(); PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest( testConfig.ContentServerComputerName, testConfig.ContentServerHTTPListenPort, testConfig.NameOfFileWithMultipleBlocks); BaseTestSite.Log.Add( LogEntryKind.Debug, "Send PCCRTP request to trigger hash generation"); PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, (int)testConfig.Timeout.TotalMilliseconds); var contentBeforeHashGeneration = pccrtpResponse.PayloadData; BaseTestSite.Log.Add( LogEntryKind.Debug, "Wait until the hash is generated on content server"); TestUtility.DoUntilSucceed(() => sutControlAdapter.IsHTTPHashExisted(testConfig.ContentServerComputerFQDNOrNetBiosName), testConfig.Timeout, testConfig.RetryInterval); BaseTestSite.Log.Add( LogEntryKind.Debug, "Send HTTP request again without peerdist Accept-Encoding"); var contentAfterHashGeneration = TestUtility.DownloadHTTPFile(testConfig.ContentServerComputerName, testConfig.NameOfFileWithMultipleBlocks); BaseTestSite.Assert.IsTrue( contentAfterHashGeneration.SequenceEqual(contentBeforeHashGeneration), "The content server should return file content when peerdist is not included in Accept-Encoding"); }
private void executeButton_Click(object sender, EventArgs e) { try { if (!CheckInput()) { return; } logger.Clear(); #region Read settings from UI var version = (BranchCacheVersion)branchCacheVersionComboBox.SelectedItem; var operationMode = (OperationMode)operationModeComboBox.SelectedItem; var transport = (ContentInformationTransport)transportComboBox.SelectedItem; var serverSecret = serverSecretTextBox.Text; var filePath = filePathTextBox.Text; var hashAlgoValue = (dwHashAlgo_Values)hashAlgorithmComboBox.SelectedItem; HashAlgorithm hashAlgorithm; HMAC hmacAlgorithm; int hashBlockSize; string server = null; string file = null; string sharedFolder = null; Match filePathMatch = null; switch (transport) { case ContentInformationTransport.PCCRTP: filePathMatch = Regex.Match(filePath, httpFilePathPattern); server = filePathMatch.Groups["Server"].Value; file = filePathMatch.Groups["FileName"].Value; break; case ContentInformationTransport.SMB2: filePathMatch = Regex.Match(filePath, smb2FilePathPattern); server = filePathMatch.Groups["Server"].Value; sharedFolder = filePathMatch.Groups["SharedFolder"].Value; file = filePathMatch.Groups["FileName"].Value; break; default: throw new NotImplementedException(); } SecurityPackageType securityPackageType = (SecurityPackageType)smb2AuthenticationComboBox.SelectedItem; string domainName = domainNameTextBox.Text; string userName = userNameTextBox.Text; string userPassword = userPasswordTextBox.Text; #endregion var timeout = TimeSpan.FromSeconds(60); byte[] content; byte[] contentInformation; Content_Information_Data_Structure contentInformationStructure = new Content_Information_Data_Structure(); Content_Information_Data_Structure_V2 contentInformationStructureV2 = new Content_Information_Data_Structure_V2(); #region Read content and content information if (operationMode == OperationMode.RemoteHashVerification) { switch (transport) { case ContentInformationTransport.PCCRTP: PccrtpClient pccrtpClient = new PccrtpClient(); PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest( server, 80, file, version); PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest( HttpVersionType.HttpVersion11, pccrtpRequest, (int)timeout.TotalMilliseconds); if (pccrtpResponse.HttpResponse.ContentEncoding == "peerdist") { contentInformation = pccrtpResponse.PayloadData; content = Utility.DownloadHTTPFile(server, file); } else { content = pccrtpResponse.PayloadData; Thread.Sleep(5000); // Wait for hash generation pccrtpResponse = pccrtpClient.SendHttpRequest( HttpVersionType.HttpVersion11, pccrtpRequest, (int)timeout.TotalMilliseconds); contentInformation = pccrtpResponse.PayloadData; } break; case ContentInformationTransport.SMB2: using (Smb2ClientTransport smb2Client = new Smb2ClientTransport(timeout)) { smb2Client.OpenFile( server, sharedFolder, file, securityPackageType, domainName, userName, userPassword, AccessMask.GENERIC_READ); content = smb2Client.ReadAllBytes(); Thread.Sleep(5000); // Wait for hash generation HASH_HEADER hashHeader; smb2Client.ReadHash( SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST, version == BranchCacheVersion.V1 ? SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1 : SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2, version == BranchCacheVersion.V1 ? SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED : SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED, 0, uint.MaxValue, out hashHeader, out contentInformation); } break; default: throw new NotImplementedException(); } switch (version) { case BranchCacheVersion.V1: contentInformationStructure = PccrcUtility.ParseContentInformation(contentInformation); break; case BranchCacheVersion.V2: contentInformationStructureV2 = PccrcUtility.ParseContentInformationV2(contentInformation); break; default: throw new NotImplementedException(); } } else { content = File.ReadAllBytes(filePath); } #endregion #region Calculate hash and execute verification switch (version) { case BranchCacheVersion.V1: if (operationMode == OperationMode.RemoteHashVerification) { PccrcUtility.GetHashAlgorithm(contentInformationStructure.dwHashAlgo, out hashAlgorithm, out hmacAlgorithm, out hashBlockSize); } else { PccrcUtility.GetHashAlgorithm(hashAlgoValue, out hashAlgorithm, out hmacAlgorithm, out hashBlockSize); } hmacAlgorithm.Key = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(serverSecret)); logger.LogInfo( "Ks = Hash(ServerSecret): {0}", Utility.ToHexString(hmacAlgorithm.Key)); logger.NewLine(); int blockTotalCount = content.Length / BLOCKBYTECOUNT; if (content.Length > BLOCKBYTECOUNT * blockTotalCount) { blockTotalCount = blockTotalCount + 1; } int segmentCount = blockTotalCount / SEGMENTBLOCKCOUNT; if (blockTotalCount > SEGMENTBLOCKCOUNT * segmentCount) { segmentCount = segmentCount + 1; } for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) { logger.LogInfo("Segment{0}", segmentIndex); logger.NewLine(); logger.Indent(); List <byte> blockHashList = new List <byte>(); List <byte> tempList = new List <byte>(); int blockCount = (segmentIndex == segmentCount - 1) ? (blockTotalCount % SEGMENTBLOCKCOUNT) : (SEGMENTBLOCKCOUNT); for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) { logger.LogInfo( "Block{0} Offset {1} Length {2}", blockIndex, BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex, BLOCKBYTECOUNT); logger.NewLine(); logger.Indent(); var block = content.Skip(BLOCKBYTECOUNT * SEGMENTBLOCKCOUNT * segmentIndex + BLOCKBYTECOUNT * blockIndex).Take(BLOCKBYTECOUNT).ToArray(); byte[] blockHash = hashAlgorithm.ComputeHash(block); logger.LogInfo("BlockHash{0} = Hash(Block): {1}", blockIndex, Utility.ToHexString(blockHash)); if (operationMode == OperationMode.RemoteHashVerification && !blockHash.SequenceEqual(contentInformationStructure.blocks[segmentIndex].BlockHashes.Skip(blockIndex * hashBlockSize).Take(hashBlockSize))) { logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.blocks[segmentIndex].BlockHashes.Skip(blockIndex * hashBlockSize).Take(hashBlockSize).ToArray())); } blockHashList.AddRange(blockHash); logger.Unindent(); logger.NewLine(); } byte[] hod = hashAlgorithm.ComputeHash(blockHashList.ToArray()); logger.LogInfo( "HoD = Hash(BlockHash0 + BlockHash1 + ... + BlockHashN): {0}", Utility.ToHexString(hod)); if (operationMode == OperationMode.RemoteHashVerification && !hod.SequenceEqual(contentInformationStructure.segments[segmentIndex].SegmentHashOfData)) { logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.segments[segmentIndex].SegmentHashOfData)); } logger.NewLine(); byte[] kp = hmacAlgorithm.ComputeHash(hod); logger.LogInfo( "Kp = HMAC(Ks, HoD): {0}", Utility.ToHexString(kp)); if (operationMode == OperationMode.RemoteHashVerification && !kp.SequenceEqual(contentInformationStructure.segments[segmentIndex].SegmentSecret)) { logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructure.segments[segmentIndex].SegmentSecret)); } logger.NewLine(); tempList.AddRange(hod); tempList.AddRange(Encoding.Unicode.GetBytes(HOHODK_APPEND_STRING)); byte[] hoHoDK = hashAlgorithm.ComputeHash(tempList.ToArray()); logger.LogInfo( "hoHoDK = HMAC(HoD + \"MS_P2P_CACHING\"): {0}", Utility.ToHexString(hoHoDK)); logger.NewLine(); logger.Unindent(); } break; case BranchCacheVersion.V2: PccrcUtility.GetHashAlgorithm(dwHashAlgoV2_Values.TRUNCATED_SHA512, out hashAlgorithm, out hmacAlgorithm); hmacAlgorithm.Key = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(serverSecret)).Take(32).ToArray(); logger.LogInfo( "Ks = Hash(ServerSecret): {0}", Utility.ToHexString(hmacAlgorithm.Key)); logger.NewLine(); int segmentLength = BLOCKBYTECOUNT; int chunkCount = 1; if (operationMode == OperationMode.RemoteHashVerification) { chunkCount = contentInformationStructureV2.chunks.Length; } int segmentOffset = 0; for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++) { logger.LogInfo("Chunk{0}", chunkIndex); logger.NewLine(); logger.Indent(); segmentCount = content.Length / segmentLength; if (content.Length > segmentCount * segmentLength) { segmentCount++; } if (operationMode == OperationMode.RemoteHashVerification) { segmentCount = contentInformationStructureV2.chunks[chunkIndex].chunkData.Length; } for (int segmentIndex = 0; segmentIndex < segmentCount; ++segmentIndex) { logger.LogInfo( "Segment{0} Offset {1} Length {2}", segmentIndex, segmentOffset, BLOCKBYTECOUNT); logger.NewLine(); logger.Indent(); if (operationMode == OperationMode.RemoteHashVerification) { segmentLength = (int)contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].cbSegment; } List <byte> tempList = new List <byte>(); var segment = content.Skip(segmentOffset).Take(segmentLength).ToArray(); segmentOffset += segmentLength; //TRANCATED_SHA_512 byte[] hod = hashAlgorithm.ComputeHash(segment).Take(32).ToArray(); logger.LogInfo( "HoD = Hash(Segment): {0}", Utility.ToHexString(hod)); if (operationMode == OperationMode.RemoteHashVerification && !hod.SequenceEqual(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentHashOfData)) { logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentHashOfData)); } logger.NewLine(); byte[] kp = hmacAlgorithm.ComputeHash(hod).Take(32).ToArray(); logger.LogInfo( "Kp = HMAC(Ks, HoD): {0}", Utility.ToHexString(kp)); if (operationMode == OperationMode.RemoteHashVerification && !kp.SequenceEqual(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentSecret)) { logger.LogError("Server Returned: {0}", Utility.ToHexString(contentInformationStructureV2.chunks[chunkIndex].chunkData[segmentIndex].SegmentSecret)); } logger.NewLine(); tempList.AddRange(hod); tempList.AddRange(Encoding.Unicode.GetBytes(HOHODK_APPEND_STRING)); byte[] hoHoDK = hashAlgorithm.ComputeHash(tempList.ToArray()); logger.LogInfo( "hoHoDK = HMAC(HoD + \"MS_P2P_CACHING\"): {0}", Utility.ToHexString(hoHoDK)); logger.NewLine(); logger.Unindent(); } } break; default: throw new NotImplementedException(); } if (operationMode == OperationMode.RemoteHashVerification) { if (logger.HasError) { Utility.ShowMessageBox("Hash verification error found!", MessageBoxIcon.Error); } else { Utility.ShowMessageBox("Hash verification passed!", MessageBoxIcon.Information); } } #endregion } catch (Exception ex) { Utility.ShowMessageBox(ex.Message + "\r\n\r\n" + ex.StackTrace, MessageBoxIcon.Error); } }
/// <summary> /// Verify Content, Segments, and Blocks defined in section 2.1. /// </summary> /// <param name="pccrtpResponse">The HTTP resopnse.</param> private void VerifyContentSegmentsBlocks(PccrtpResponse pccrtpResponse) { Content_Information_Data_Structure contentInfo = pccrtpResponse.ContentInfo; #region MS-PCCRC_R3 // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R3.segment is {0} type", pccrtpResponse.HttpHeader[ACCEPTRANGES]); bool isVerifyR3 = pccrtpResponse.HttpHeader[ACCEPTRANGES].Equals("bytes"); // Verify MS-PCCRC requirement: MS-PCCRC_R3 Site.CaptureRequirementIfIsTrue( isVerifyR3, 3, @"[In Content, Segments, and Blocks] Each segment is a binary string."); #endregion #region MS-PCCRC_R10 bool isVerifyR10 = true; for (int i = 0; i < contentInfo.cSegments - 1; i++) { if (contentInfo.segments[i].cbBlockSize != STANDARDBBLOCKSIZE) { isVerifyR10 = false; break; } } // Check for the last block in the last segment, which may be shorter than the standard block size (64 KB). if (contentInfo.segments[contentInfo.cSegments - 1].cbBlockSize > STANDARDBBLOCKSIZE) { isVerifyR10 = false; } // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R10. Each block size is {0} 64 kilobytes", isVerifyR10 ? string.Empty : "not"); // Verify MS-PCCRC requirement: MS-PCCRC_R10 Site.CaptureRequirementIfIsTrue( isVerifyR10, 10, @"[In Content, Segments, and Blocks] Each block is a binary string of a fixed size (64 kilobytes), except for the last block in the last segment, which again may be shorter."); #endregion #region MS-PCCRC_R4 string allLength = string.Empty; if (pccrtpResponse.HttpHeader.ContainsKey(CONTENTRANGE)) { // Get the value of content length in the response for partial request. allLength = pccrtpResponse.HttpHeader[CONTENTRANGE]; allLength = allLength.Substring(allLength.IndexOf('/') + 1); } else if (pccrtpResponse.HttpHeader.ContainsKey(XP2PPEERDIST)) { // Get the value of content length in the response for full request. allLength = pccrtpResponse.HttpHeader[XP2PPEERDIST]; allLength = allLength.Substring(allLength.LastIndexOf('=') + 1); } bool isVerifyR4 = true; long contentLength = 0; try { contentLength = Convert.ToInt64(allLength); } catch (FormatException e) { throw new FormatException(e.ToString()); } long lastSegmentLength = 0; for (int i = 0; i < contentInfo.cSegments; i++) { // If there are multiple segments, check each segment is of a standard size (32 MB). if (contentLength > STANDARDSEGMENTSIZE) { if (contentInfo.segments[i].cbSegment != STANDARDSEGMENTSIZE) { isVerifyR4 = false; break; } contentLength -= STANDARDSEGMENTSIZE; } else { // Check for the last segment, which may be shorter than the standard segment size (32 MB). if (contentLength != contentInfo.segments[i].cbSegment) { if (i > 0) { lastSegmentLength = contentLength; } isVerifyR4 = false; break; } } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R4.segment size is {0}32 megabytes except possibly the last segment", isVerifyR4 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R4 Site.CaptureRequirementIfIsTrue( isVerifyR4, 4, @"[In Content, Segments, and Blocks] Each segment is of a standard size (32 megabytes), except possibly the last segment which may be smaller if the content size is not a multiple of the standard segment size."); #endregion // MS-PCCRC_R63 is blocked by TDI(Techical Document Issue) about inaccurate definition of // dwReadBytesInLastSegment if the HTTP request is a range retrieval request. if (bool.Parse(Site.Properties.Get("PCCRC.IsTDI.65999.Fixed"))) { #region MS-PCCRC_R63 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R63, the actual value of the dwReadBytesInLastSegment is {0}", contentInfo.dwReadBytesInLastSegment); // Verify MS-PCCRC requirement: MS-PCCRC_R63 Site.CaptureRequirementIfAreEqual <long>( lastSegmentLength, contentInfo.dwReadBytesInLastSegment, 63, @"[In Content Information Data Structure Version 1.0] dwReadBytesInLastSegment (4 bytes): Total number of bytes of the content range which lie within the final segment in the Content Information data structure."); #endregion } }
/// <summary> /// Verify Data Structure of Content Information defined in section 2.3. /// </summary> /// <param name="pccrtpResponse">The HTTP resopnse.</param> private void VerifyDataStructure(PccrtpResponse pccrtpResponse) { Content_Information_Data_Structure contentInfo = pccrtpResponse.ContentInfo; #region MS-PCCRC_R58 int hashLength = 0; int valueOfDwHashAlgo = 0; switch (pccrtpResponse.ContentInfo.dwHashAlgo) { case dwHashAlgo_Values.V1: valueOfDwHashAlgo = 0x0000800C; hashLength = 32; break; case dwHashAlgo_Values.V2: hashLength = 48; valueOfDwHashAlgo = 0x0000800D; break; case dwHashAlgo_Values.V3: hashLength = 64; valueOfDwHashAlgo = 0x0000800E; break; default: break; } // Add the debug information. Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R58, the actual length of dwHashAlgo is: {0}", Marshal.SizeOf(valueOfDwHashAlgo)); // Verify MS-PCCRC requirement: MS-PCCRC_R58 Site.CaptureRequirementIfAreEqual <int>( 4, Marshal.SizeOf(valueOfDwHashAlgo), 58, @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): Hash algorithm to use. <2> "); #endregion #region MS-PCCRC_R581 bool isVerifyR581 = valueOfDwHashAlgo == 0x0000800C || valueOfDwHashAlgo == 0x0000800D || valueOfDwHashAlgo == 0x0000800E; // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R581, the actual value of dwHashAlgo is 0x{0:X8}.", valueOfDwHashAlgo); // Verify MS-PCCRC requirement: MS-PCCRC_R581 Site.CaptureRequirementIfIsTrue( isVerifyR581, 581, @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): MUST be one of the following values:0x0000800C,0x0000800D,0x0000800E."); #endregion #region MS-PCCRC_R59 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R59, , the actual value of dwHashAlgo is 0x{0:X8}.", valueOfDwHashAlgo); // Verify MS-PCCRC requirement: MS-PCCRTP_R59 Site.CaptureRequirementIfAreEqual <int>( 0x0000800C, valueOfDwHashAlgo, 59, @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): When use the SHA-256 hash algorithm, the value is 0x0000800C."); #endregion #region MS-PCCRC_R54 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R54, all fields are {0}in little-endian byte order", BitConverter.IsLittleEndian ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R54 Site.CaptureRequirementIfIsTrue( BitConverter.IsLittleEndian, 54, @"[In Content Information Data Structure Version 1.0] All fields are in little-endian byte order."); #endregion #region MS-PCCRC_R57 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R57, the actual value of Version is 0x{0:X8}", contentInfo.Version); // Verify MS-PCCRC requirement: MS-PCCRTP_R57 Site.CaptureRequirementIfAreEqual <int>( 0x0100, contentInfo.Version, 57, @"[In Content Information Data Structure Version 1.0] Version (2 bytes): MUST be 0x0100."); #endregion #region MS-PCCRC_R53 // The Version is parsed at the first 2 byte word in Content Information by stack. // If MS-PCCRC_R57 is verified successfully, MS-PCCRC_R53 is verified and so captured directly. Site.CaptureRequirement( 53, @"[In Content Information Data Structure Version 1.0] Content Information starts with a single 2 byte WORD value representing the data structure version."); #endregion #region MS-PCCRC_R56 // The Version is parsed at the first 2 byte word in Content Information by stack. // If MS-PCCRC_R57 is verified successfully, it indicates that the low byte is the minor version number // and the high byte is the major version number. Site.CaptureRequirement( 56, @"[In Content Information Data Structure Version 1.0] Version (2 bytes): The low byte is the minor version number and the high byte is the major version number."); #endregion #region MS-PCCRC_R55 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R55, the actual size of the Version is {0}", Marshal.SizeOf(contentInfo.Version)); // Verify MS-PCCRC requirement: MS-PCCRTP_R55 Site.CaptureRequirementIfAreEqual <int>( 2, Marshal.SizeOf(contentInfo.Version), 55, @"[In Content Information Data Structure Version 1.0] Version (2 bytes): Content Information version (0x0100 is version 1.0)."); #endregion #region MS-PCCRC_R64 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R64, the actual value of the cSegments is {0}", contentInfo.cSegments); // Verify MS-PCCRC requirement: MS-PCCRC_R64 Site.CaptureRequirementIfAreEqual <int>( contentInfo.segments.Length, (int)contentInfo.cSegments, 64, @"[In Content Information Data Structure Version 1.0] cSegments (4 bytes): The number of segments which intersect the content range and hence are contained in the Content Information data structure."); #endregion #region MS-PCCRC_R65 bool isVerifyR65 = true; for (int i = 0; i < contentInfo.cSegments; i++) { if (contentInfo.segments[i].cbBlockSize == STANDARDBBLOCKSIZE && contentInfo.segments[i].SegmentHashOfData.Length == hashLength && contentInfo.segments[i].SegmentSecret.Length == hashLength) { isVerifyR65 = true; } else { isVerifyR65 = false; break; } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R65, the segments variable {0} contain the Segment start offset, length, block size, SegmentHashofData and SegmentSecret for each segment.", isVerifyR65 ? string.Empty : "does't"); // Verify MS-PCCRC requirement: MS-PCCRC_R65 Site.CaptureRequirementIfIsTrue( isVerifyR65, 65, @"[In Content Information Data Structure Version 1.0] segments (variable): Segment start offset, length, block size, SegmentHashofData and SegmentSecret for each segment."); #endregion }
/// <summary> /// Verify SegmentDescription defined in section 2.3.1.1. /// </summary> /// <param name="pccrtpResponse">The HTTP response.</param> private void VerifySegmentDescription(PccrtpResponse pccrtpResponse) { #region MS-PCCRC_R67 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R67, the actual number of SegmentDescription fields in segments field is {0}", pccrtpResponse.ContentInfo.segments.Length); // Verify MS-PCCRC requirement: MS-PCCRC_R67 Site.CaptureRequirementIfAreEqual <uint>( pccrtpResponse.ContentInfo.cSegments, (uint)pccrtpResponse.ContentInfo.segments.Length, 67, @"[In SegmentDescription] The segments field is composed of a number cSegments of SegmentDescription fields."); #endregion #region MS-PCCRC_R69 bool isVerifyR69 = true; for (int i = 0; i < pccrtpResponse.ContentInfo.cSegments - 1; i++) { if (pccrtpResponse.ContentInfo.segments[i].cbSegment != STANDARDSEGMENTSIZE) { isVerifyR69 = false; break; } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R69, the actual size of every segment except for the last segment is {0}32 megabytes", isVerifyR69 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R69 Site.CaptureRequirementIfIsTrue( isVerifyR69, 69, @"[In SegmentDescription] Every segment except for the last segment must be exactly 32 megabytes in size."); #endregion int hashLength = 0; switch (pccrtpResponse.ContentInfo.dwHashAlgo) { case dwHashAlgo_Values.V1: hashLength = 32; break; case dwHashAlgo_Values.V2: hashLength = 48; break; case dwHashAlgo_Values.V3: hashLength = 64; break; default: break; } #region MS-PCCRC_R74 bool isVerifyR74 = true; bool isVerifyR77 = true; bool isVerifyR79 = true; bool isVerifyR83 = true; bool isVerifyR76 = true; for (int i = 1; i < pccrtpResponse.ContentInfo.cSegments; i++) { ulong offset = pccrtpResponse.ContentInfo.segments[i - 1].ullOffsetInContent + pccrtpResponse.ContentInfo.segments[i - 1].cbSegment; if (pccrtpResponse.ContentInfo.segments[i].ullOffsetInContent != offset) { isVerifyR74 = false; } if (pccrtpResponse.ContentInfo.segments[i].cbBlockSize != STANDARDBBLOCKSIZE) { isVerifyR77 = false; } if (Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[i].cbBlockSize) != 4) { isVerifyR76 = false; } if (pccrtpResponse.ContentInfo.segments[i].SegmentHashOfData.Length != hashLength) { isVerifyR79 = false; } if (pccrtpResponse.ContentInfo.segments[i].SegmentSecret.Length != hashLength) { isVerifyR83 = false; } } if (pccrtpResponse.ContentInfo.segments[0].ullOffsetInContent != 0) { isVerifyR74 = false; } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R74, the ullOffsetInContent in every SegmentDescription field is {0}content offset at which the start of the segment begins.", isVerifyR74 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R74 Site.CaptureRequirementIfIsTrue( isVerifyR74, 74, @"[In SegmentDescription] ullOffsetInContent (8 bytes): Content offset at which the start of the segment begins."); #endregion #region MS-PCCRC_R75 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R75. The actual size of the cbSegment is {0}.", Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[0].cbSegment)); // Verify MS-PCCRC requirement: MS-PCCRC_R75 Site.CaptureRequirementIfAreEqual <int>( 4, Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[0].cbSegment), 75, @"[In SegmentDescription] cbSegment (4 bytes): Total number of bytes in the segment, regardless of how many of those bytes intersect the content range."); #endregion #region MS-PCCRC_R76 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R76. The actual size of the cbBlockSize is {0}4 bytes.", isVerifyR76 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R76 Site.CaptureRequirementIfIsTrue( isVerifyR76, 76, @"[In SegmentDescription] cbBlockSize (4 bytes): Length of a content block within this segment, in bytes."); #endregion #region MS-PCCRC_R77 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R77, the block size of every segment is {0}65536 bytes", isVerifyR77 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R77 Site.CaptureRequirementIfIsTrue( isVerifyR77, 77, @"[In SegmentDescription] cbBlockSize (4 bytes): Every segment MUST use the block size of 65536 bytes."); #endregion #region MS-PCCRC_R79 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R79, the actual SegmentHashOfData is {0} of length 32", isVerifyR79 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R79 Site.CaptureRequirementIfIsTrue( isVerifyR79, 79, @"[In SegmentDescription] SegmentHashOfData (variable): The hash is of length 32 if dwHashAlgo at the start of the Content Information was 0x800C = SHA-256."); #endregion #region MS-PCCRC_R83 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R83, the actual length of the SegmentSecret is {0}", hashLength); // Verify MS-PCCRC requirement: MS-PCCRC_R83 Site.CaptureRequirementIfIsTrue( isVerifyR83, 83, @"[In SegmentDescription] SegmentSecret (variable):The hash is of length 32 if dwHashAlgo at the start of the Content Information was 0x800C = SHA-256."); #endregion }
/// <summary> /// Verify SegmentContentBlocks defined in section 2.3.1.2. /// </summary> /// <param name="pccrtpResponse">The HTTP response.</param> private void VerifySegmentContentBlocks(PccrtpResponse pccrtpResponse) { #region MS-PCCRC_R86 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R86, the actual number of SegmentContentBlocks fields in blocks field is {0}", pccrtpResponse.ContentInfo.blocks.Length); // Verify MS-PCCRC requirement: MS-PCCRC_R86 Site.CaptureRequirementIfAreEqual <uint>( pccrtpResponse.ContentInfo.cSegments, (uint)pccrtpResponse.ContentInfo.blocks.Length, 86, @"[In SegmentContentBlocks] The blocks field contains a number cSegments of SegmentContentBlocks fields."); #endregion #region MS-PCCRC_R89 bool isVerifyR89 = true; int hashLength = 0; switch (pccrtpResponse.ContentInfo.dwHashAlgo) { case dwHashAlgo_Values.V1: hashLength = 32; break; case dwHashAlgo_Values.V2: hashLength = 48; break; case dwHashAlgo_Values.V3: hashLength = 64; break; default: break; } foreach (SegmentContentBlocks segContentBlocks in pccrtpResponse.ContentInfo.blocks) { if (segContentBlocks.BlockHashes.Length != segContentBlocks.cBlocks * hashLength) { isVerifyR89 = false; break; } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R89, the actual size of BlockHashes field is {0} cBlocks * {1}", isVerifyR89 ? string.Empty : "not ", hashLength); // Verify MS-PCCRC requirement: MS-PCCRC_R89 Site.CaptureRequirementIfIsTrue( isVerifyR89, 89, @"[In SegmentContentBlocks] BlockHashes (variable):The size of this field is cBlocks * (32, 48 or 64, depending on which hash was used)."); #endregion #region MS-PCCRC_R12 // The BlockHashes field is parsed according the cBlocks and the hash algorithm by the stack. // If MS-PCCRC_R89 is verified successfully, it indicates that the BlockHashes is the hash list // of each block in the order the block in the segment.So MS-PCCRC_R12 is captured directly. Site.CaptureRequirement( 12, @"[In Content, Segments, and Blocks] Blocks within a segment are identified by their progressive index within the segment (Block 0 is the first block in the segment, Block 1 the second, and so on)."); #endregion }
/// <summary> /// This class is used to verify the requirements related to PCCRTP response. /// </summary> /// <param name="pccrtpResponse">The PCCRTP response message.</param> private void VerifyPccrtpResponse(PccrtpResponse pccrtpResponse) { #region MS-PCCRTP_R11 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R11. Actual value of X-P2P-PeerDist field is: {0}.", pccrtpResponse.HttpHeader[XP2PPEERDIST]); bool isVerifyR11 = pccrtpResponse.HttpResponse.Headers[XP2PPEERDIST].Contains("Version") && pccrtpResponse.HttpResponse.Headers[XP2PPEERDIST].Contains("ContentLength"); // Verify MS-PCCRTP requirement: MS-PCCRTP_R11 Site.CaptureRequirementIfIsTrue( isVerifyR11, 11, @"[In Message Syntax] The extension-header field can appear in responses, the syntax of this header field value is described as follows: extension-header = X-P2P-PeerDist X-P2P-PeerDist = ""X-P2P-PeerDist"" "":"" peerdist-params [peerdist-params = 1#( version | [content-len] | [missing-data-request] ) version = ""Version"" ""="" major-version ""."" minor-version]. "); #endregion #region MS-PCCRTP_R18 // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R18. Actual Value of Content-Length is {0}", pccrtpResponse.HttpHeader[CONTENTLENGTH]); long contentLength; // Verify MS-PCCRTP requirement: MS-PCCRTP_R18 bool isVerifyR18 = pccrtpResponse.HttpHeader.Values.Contains(pccrtpResponse.HttpHeader[CONTENTLENGTH]) && long.TryParse(pccrtpResponse.HttpHeader[CONTENTLENGTH], out contentLength); Site.CaptureRequirementIfIsTrue( isVerifyR18, 18, @"[In Message Syntax] The content-len [content-len = ""ContentLength"" ""="" 1*DIGIT] parameter contains the length of the entity-body before the PeerDist content encoding is applied to it."); #endregion #region MS-PCCRTP_R34 bool isVerifyR34 = pccrtpResponse.HttpHeader.Values.Contains(pccrtpResponse.HttpHeader["X-P2P-PeerDist"]); // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R34. The response {0} contain PeerDist parameters header field.", isVerifyR34 ? string.Empty : "does not "); // Verify MS-PCCRTP requirement: MS-PCCRTP_R34 Site.CaptureRequirementIfIsTrue( isVerifyR34, 34, @"[In Receiving a PeerDist-Supporting Request] HTTP/1.1 server MUST also include the PeerDist parameters header field in the response."); #endregion #region MS-PCCRTP_R35 // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R35. Actual Value of Version is {0}", pccrtpResponse.HttpHeader[XP2PPEERDIST]); // Verify MS-PCCRTP requirement: MS-PCCRTP_R35 bool isVerifyR35 = pccrtpResponse.HttpHeader[XP2PPEERDIST].Contains("Version"); Site.CaptureRequirementIfIsTrue( isVerifyR35, 35, @"[In Receiving a PeerDist-Supporting Request] The PeerDist parameters header field MUST contain the Version parameter containing the version of the PeerDist content encoding used in the response."); #endregion #region MS-PCCRTP_R36 bool isVerifyR36 = pccrtpResponse.HttpHeader[XP2PPEERDIST].Contains("ContentLength"); // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R36. Actual Value of ContentLength is {0} in PeerDist Header field", isVerifyR36 ? string.Empty : "not"); // Verify MS-PCCRTP requirement: MS-PCCRTP_R36 Site.CaptureRequirementIfIsTrue( isVerifyR36, 36, @"[In Receiving a PeerDist-Supporting Request] the PeerDist parameters header field MUST also contain the ContentLength parameter specifying the content length of the response entity-body before the PeerDist content encoding has been applied to it."); #endregion #region MS-PCCRTP_R48 string[] headerValues = pccrtpResponse.HttpHeader[XP2PPEERDIST].Split(new char[] { ',' }); string versionString = headerValues[0].Substring(headerValues[0].IndexOf('=') + 1); // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R48. Actual Value of peerdist version is {0}", versionString); if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2) { // Verify MS-PCCRTP requirement: MS-PCCRTP_R48 Site.CaptureRequirementIfAreEqual <string>( "1.0", versionString, 48, @"[In Appendix A: Product Behavior]<3> Section 1.7: HTTP/1.1 servers in Windows Server 2008 R2 set the PeerDist version parameter to 1.0."); } #endregion #region MS-PCCRTP_R52 if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2) { bool isContainEtag = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("ETag"); bool isContainLastModified = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("Last-Modified"); bool isContainBoth = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("ETag") && pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("Last-Modified"); // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R52.The response actually does {0} contain an ETag header field, does {1} contain a Last-Modified header field, does {2} contain both header fields.", isContainEtag ? string.Empty : "not", isContainLastModified ? string.Empty : "not", isContainBoth ? string.Empty : "not"); bool isVerifyR52 = isContainEtag || isContainLastModified || isContainBoth; // Verify MS-PCCRTP requirement: MS-PCCRTP_R52 Site.CaptureRequirementIfIsTrue( isVerifyR52, 52, @"[In Appendix A: Product Behavior] <7> Section 3.2:The HTTP/1.1 server in Windows Server 2008 R2 sends a PeerDist-encoded response only when the response contains an ETag header field or a Last-Modified header field or both header fields."); } #endregion #region MS-PCCRTP_R54 if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2) { bool isVerifyR54 = pccrtpResponse.HttpResponse.ContentEncoding.Equals("peerdist") && !pccrtpResponse.ContentInfo.Equals(null); // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R54. The HTTP/1.1 server in Windows Server 2008 R2 does {0} use the algorithms and data structures defined in [MS-PCCRC].", isVerifyR54 ? string.Empty : "not"); // Verify MS-PCCRTP requirement: MS-PCCRTP_R54 Site.CaptureRequirementIfIsTrue( isVerifyR54, 54, @"[In Appendix A: Product Behavior]<9> Section 3.2.5.1: The HTTP/1.1 server in Windows Server 2008 R2 uses the algorithms and data structures defined in [MS-PCCRC] to generate the PeerDist Content Information only when it receives an HTTP/1.1 request. "); } #endregion #region MS-PCCRRP_R8001 bool isVerifyR8001 = pccrtpResponse.HttpHeader.ContainsKey(CONTENTENCODING) && pccrtpResponse.HttpHeader[CONTENTENCODING].Contains("peerdist"); // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R8001, the PeerDist content-encoding value is {0} specified in the Accept-Encoding and Content-Encoding header fields.", isVerifyR8001 ? string.Empty : "not "); // Verify MS-PCCRTP requirement: MS-PCCRTP_R8001 Site.CaptureRequirementIfIsTrue( isVerifyR8001, 8001, @"[In Message Syntax] The PeerDist content-encoding value can be specified in the Accept-Encoding and Content-Encoding header fields,as shown in the following examples: Content-Encoding: peerdist."); #endregion }
/// <summary> /// Verify Segment Identifiers (HoHoDK) and Keys defined in section 2.2. /// </summary> /// <param name="pccrtpResponse">The HTTP response.</param> private void VerifySegmentIdentifiersAndKeys(PccrtpResponse pccrtpResponse) { #region MS-PCCRC_R26 bool isVerifyR26 = pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V1 || pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V2 || pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V3; // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R26. the dwhashAlgo of hash is {0}", pccrtpResponse.ContentInfo.dwHashAlgo); // Verify MS-PCCRTP requirement: MS-PCCRC_R26 Site.CaptureRequirementIfIsTrue( isVerifyR26, 26, @"[In Segment Identifiers (HoHoDk) and Keys] Notation: Hash: The input hash function, which MUST be one of the hash functions listed in section 2.3."); #endregion #region MS-PCCRC_R37 bool isVerifyR37 = true; if (pccrtpResponse.ContentInfo.segments != null && pccrtpResponse.ContentInfo.blocks != null) { for (int i = 0; i < pccrtpResponse.ContentInfo.segments.Length; i++) { if (pccrtpResponse.ContentInfo.segments[i].SegmentHashOfData == null || pccrtpResponse.ContentInfo.segments[i].SegmentSecret == null) { isVerifyR37 = false; break; } } } else { isVerifyR37 = false; } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R37. BlockHashes, SegmentHashOfData , SegmentSecret are {0}inclueded in the Content Information Data Structure.", isVerifyR37 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R37 Site.CaptureRequirementIfIsTrue( isVerifyR37, 37, @"[In Segment Identifiers (HoHoDk) and Keys] ContentInfo includes only the list of block hashes, the HoD, and Kp."); #endregion #region MS-PCCRC_R3701 // Verify MS-PCCRC requirement: MS-PCCRC_R3701 // The ContentInfo is parsed according the definition of Content Information Data Structure by the stack. // If ContentInfo improperly includes Ke and HoHoDk, then an exception will be thrown in the stack layer. // The program runs into here which has indicated that Ke and HoHoDk are not included in ContentInfo. // So MS-PCCRC_R3701 is captured directly. Site.CaptureRequirement( 3701, @"[In Segment Identifiers (HoHoDk) and Keys]Ke and HoHoDk are not included in ContentInfo."); #endregion }
public byte[] RetrieveContentData(string filename) { switch (testConfig.ContentTransport) { case ContentInformationTransport.PCCRTP: PccrtpClient pccrtpClient = new PccrtpClient(); PccrtpRequest pccrtpRequest = pccrtpClient.CreatePccrtpRequest( testConfig.ContentServerComputerName, testConfig.ContentServerHTTPListenPort, filename); PccrtpResponse pccrtpResponse = pccrtpClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, (int)testConfig.Timeout.TotalMilliseconds); testSite.Assert.AreNotEqual( "peerdist", pccrtpResponse.HttpResponse.ContentEncoding, "The content server should not have content information ready yet"); return(pccrtpResponse.PayloadData); case ContentInformationTransport.SMB2: using (BranchCacheSmb2ClientTransport smb2Client = new BranchCacheSmb2ClientTransport(testConfig.Timeout, testSite, testConfig.SupportBranchCacheV1, testConfig.SupportBranchCacheV2)) { smb2Client.OpenFile( testConfig.ContentServerComputerName, testConfig.SharedFolderName, filename, testConfig.SecurityPackageType, testConfig.DomainName, testConfig.UserName, testConfig.UserPassword, AccessMask.GENERIC_READ); HASH_HEADER hashHeader; byte[] hashData = null; uint status = 0; if (testConfig.SupportBranchCacheV1) { status = smb2Client.ReadHash( SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST, SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_1, SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_HASH_BASED, 0, uint.MaxValue, out hashHeader, out hashData); testSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, status, "The content server should not have content information ready yet"); testSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_HASH_NOT_PRESENT, status, RequirementCategory.HashNotPresent, RequirementCategory.HashNotPresentMessage); } if (testConfig.SupportBranchCacheV2) { status = smb2Client.ReadHash( SRV_READ_HASH_Request_HashType_Values.SRV_HASH_TYPE_PEER_DIST, SRV_READ_HASH_Request_HashVersion_Values.SRV_HASH_VER_2, SRV_READ_HASH_Request_HashRetrievalType_Values.SRV_HASH_RETRIEVE_FILE_BASED, 0, uint.MaxValue, out hashHeader, out hashData); testSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, status, "The content server should not have content information ready yet"); testSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_HASH_NOT_PRESENT, status, RequirementCategory.HashNotPresent, RequirementCategory.HashNotPresentMessage); } return(smb2Client.ReadAllBytes()); } default: throw new NotImplementedException(); } }