public void HAAsyncExtendTest() { HAKsiService haService = new HAKsiService(SigningServices, ExtendingServices, PublicationsFileService); ManualResetEvent waitHandle = new ManualResetEvent(false); CalendarHashChain cal = null; object testObject = new object(); bool isAsyncCorrect = false; haService.BeginExtend(1455400000, delegate(IAsyncResult ar) { try { isAsyncCorrect = ar.AsyncState == testObject; cal = haService.EndExtend(ar); } finally { waitHandle.Set(); } }, testObject); Assert.IsTrue(waitHandle.WaitOne(10000), "Wait handle timed out."); Assert.IsNotNull(cal, "Calendar hash chain should not be null."); Assert.AreEqual(true, isAsyncCorrect, "Unexpected async state."); }
public void AsyncExtendWithInvalidPassTest(KsiService service) { ManualResetEvent waitHandle = new ManualResetEvent(false); Exception ex = null; CalendarHashChain cal = null; service.BeginExtend(1455400000, delegate(IAsyncResult ar) { try { cal = service.EndExtend(ar); } catch (Exception e) { ex = e; } finally { waitHandle.Set(); } }, null); Assert.IsTrue(waitHandle.WaitOne(10000), "Wait handle timed out."); Assert.IsNull(cal, "Calendar hash chain should be null."); Assert.IsNotNull(ex, "Exception should not be null."); Assert.AreEqual("Server responded with error message. Status: 258; Message: Failed hmac check.", ex.Message); }
public void AsyncExtendTest(KsiService service) { ManualResetEvent waitHandle = new ManualResetEvent(false); CalendarHashChain cal = null; object testObject = new object(); bool isAsyncCorrect = false; service.BeginExtend(1455400000, delegate(IAsyncResult ar) { try { isAsyncCorrect = ar.AsyncState == testObject; cal = service.EndExtend(ar); } catch (Exception ex) { Assert.Fail("Unexpected exception: " + ex); } finally { waitHandle.Set(); } }, testObject); Assert.IsTrue(waitHandle.WaitOne(10000), "Wait handle timed out."); Assert.IsNotNull(cal, "Calendar hash chain should not be null."); Assert.AreEqual(true, isAsyncCorrect, "Unexpected async state."); }
public void TcpExtendWithReusedSocketTest() { KsiService service = GetTcpKsiService(); ulong aggregationTime = 1455478441; IAsyncResult ar1 = service.BeginExtend(aggregationTime, null, null); IAsyncResult ar2 = service.BeginExtend(aggregationTime, null, null); CalendarHashChain cal1 = service.EndExtend(ar1); Assert.AreEqual(aggregationTime, cal1.AggregationTime, "Unexpected calendar aggregation time"); CalendarHashChain cal2 = service.EndExtend(ar2); Assert.AreEqual(aggregationTime, cal2.AggregationTime, "Unexpected calendar aggregation time"); Socket socket1 = GetExtendingSocket(service); IAsyncResult ar3 = service.BeginExtend(aggregationTime, null, null); IAsyncResult ar4 = service.BeginExtend(aggregationTime, null, null); CalendarHashChain cal3 = service.EndExtend(ar3); Assert.AreEqual(aggregationTime, cal3.AggregationTime, "Unexpected calendar aggregation time"); CalendarHashChain cal4 = service.EndExtend(ar4); Assert.AreEqual(aggregationTime, cal4.AggregationTime, "Unexpected calendar aggregation time"); Socket socket2 = GetExtendingSocket(service); Assert.AreEqual(socket1, socket2, "Sockets should be equal"); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { CalendarHashChain calendarHashChain = GetSignature(context).CalendarHashChain; // If calendar hash chain is missing, verification successful if (calendarHashChain == null) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); } IEnumerator <CalendarHashChain.Link> linksEnumerator = calendarHashChain.GetLeftLinksEnumerator(); CalendarHashChain.Link link = linksEnumerator.MoveNext() ? linksEnumerator.Current : null; while (link != null) { if (link.Value.Algorithm.IsObsolete(calendarHashChain.PublicationTime)) { Logger.Debug("Calendar hash chain contains obsolete aggregation algorithm at publication time. Algorithm: {0}; Publication time: {1}", link.Value.Algorithm.Name, calendarHashChain.PublicationTime); return(new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Int16)); } link = linksEnumerator.MoveNext() ? linksEnumerator.Current : null; } return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); PublicationData publicationData; if (context.UserPublication != null) { publicationData = context.UserPublication; } else { PublicationRecordInPublicationFile publicationRecord = GetNearestPublicationRecord(GetPublicationsFile(context), signature.AggregationTime, true); if (publicationRecord == null) { // if suitable publication record does not exist in publications file then return NA return(new VerificationResult(GetRuleName(), VerificationResultCode.Na, VerificationError.Gen02)); } publicationData = publicationRecord.PublicationData; } CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, publicationData.PublicationTime); HashAlgorithm deprecatedHashAlgorithm = GetDeprecatedHashAlgorithm(extendedCalendarHashChain); if (deprecatedHashAlgorithm != null) { Logger.Debug("Extender response calendar hash chain contains deprecated aggregation algorithm at publication time. Algorithm: {0}; Publication time: {1}", deprecatedHashAlgorithm.Name, extendedCalendarHashChain.PublicationTime); return(new VerificationResult(GetRuleName(), VerificationResultCode.Na, VerificationError.Gen02)); } return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
public void TcpExtendesWithSocketReuseAndTimeoutTest() { KsiService service = GetTcpKsiService(); ulong aggregationTime = 1455478441; IAsyncResult ar1 = service.BeginExtend(aggregationTime, null, null); CalendarHashChain cal1 = service.EndExtend(ar1); Socket socket1 = GetExtendingSocket(service); Assert.AreEqual(aggregationTime, cal1.AggregationTime, "Unexpected calendar aggregation time"); Socket socket2 = GetExtendingSocket(service); Assert.AreEqual(socket1, socket2, "Sockets should be equal"); // after 20 sec server will close connection Thread.Sleep(23000); IAsyncResult ar2 = service.BeginExtend(aggregationTime, null, null); CalendarHashChain cal2 = service.EndExtend(ar2); Assert.AreEqual(aggregationTime, cal2.AggregationTime, "Unexpected calendar aggregation time"); socket2 = GetExtendingSocket(service); Assert.AreNotEqual(socket1, socket2, "Sockets should not be equal"); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { CalendarHashChain calendarHashChain = GetCalendarHashChain(GetSignature(context)); CalendarHashChain extendedSignatureCalendarHashChain = GetExtendedCalendarHashChain(context, calendarHashChain.PublicationTime); return(calendarHashChain.OutputHash != extendedSignatureCalendarHashChain.OutputHash ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Cal01) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { PublicationData userPublication = GetUserPublication(context); CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, userPublication.PublicationTime); return(extendedCalendarHashChain.PublicationData.PublicationHash != userPublication.PublicationHash ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub01) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { ulong publicationTime = GetUserPublication(context).PublicationTime; CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, publicationTime); return(extendedCalendarHashChain.InputHash != GetSignature(context).GetLastAggregationHashChainRootHash() ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub03) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <summary> /// Get calendar has chain from KSI signature /// </summary> /// <param name="signature">KSI signature</param> /// <param name="allowNullValue">indicates if returning null value is allowed</param> /// <returns>calendar hash chain</returns> public static CalendarHashChain GetCalendarHashChain(IKsiSignature signature, bool allowNullValue = false) { CalendarHashChain calendarHashChain = signature.CalendarHashChain; if (!allowNullValue && calendarHashChain == null) { throw new KsiVerificationException("Calendar hash chain is missing from KSI signature."); } return(calendarHashChain); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); ulong publicationTime = GetCalendarHashChain(signature).PublicationData.PublicationTime; CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, publicationTime); return(GetCalendarHashChain(signature).AreRightLinksEqual(extendedCalendarHashChain) ? new VerificationResult(GetRuleName(), VerificationResultCode.Ok) : new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Cal04)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); ulong aggregationTime = signature.AggregationTime; PublicationRecordInPublicationFile publicationRecord = GetNearestPublicationRecord(GetPublicationsFile(context), aggregationTime); CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, publicationRecord.PublicationData.PublicationTime); return(extendedCalendarHashChain.InputHash != signature.GetLastAggregationHashChainRootHash() ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub03) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <summary> /// Get extended calendar hash chain from given publication time. /// </summary> /// <param name="context">verification context</param> /// <param name="publicationTime">publication time</param> /// <returns></returns> public static CalendarHashChain GetExtendedCalendarHashChain(IVerificationContext context, ulong publicationTime) { CalendarHashChain hashChain = context.GetExtendedCalendarHashChain(publicationTime); if (hashChain == null) { throw new KsiVerificationException("Received invalid extended calendar hash chain from context extension function: null."); } return(hashChain); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { CalendarHashChain calendarHashChain = GetSignature(context).CalendarHashChain; // If calendar hash chain is missing, verification successful if (calendarHashChain == null) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); } return(calendarHashChain.AggregationTime != calendarHashChain.CalculateRegistrationTime() ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Int05) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { PublicationData userPublication = GetUserPublication(context); CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, userPublication.PublicationTime); if (userPublication.PublicationTime != extendedCalendarHashChain.PublicationData.PublicationTime) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub02)); } return(GetSignature(context).AggregationTime != extendedCalendarHashChain.CalculateRegistrationTime() ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub02) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <summary> /// Get extended calendar hash chain from given publication time. /// </summary> /// <param name="publicationTime">publication time</param> /// <returns>extended calendar hash chain</returns> public CalendarHashChain GetExtendedCalendarHashChain(ulong?publicationTime) { if (KsiService == null) { throw new KsiVerificationException("Invalid KSI service in context: null."); } if (Signature == null) { throw new KsiVerificationException("Invalid KSI signature in context: null."); } ulong cacheKey = publicationTime ?? 0; lock (_cacheLock) { if (_calendarHashChainCache == null) { _calendarHashChainCache = new Dictionary <ulong, CalendarHashChain>(); } else if (_calendarHashChainCache.ContainsKey(cacheKey)) { // when getting latest calendar hash chain and last extend is more than 1 sec ago then do not take from cache // otherwise take from cache if (publicationTime != null || _latestCalendarGetTime + 10000000 > DateTime.Now.Ticks) { return(_calendarHashChainCache[cacheKey]); } _calendarHashChainCache.Remove(cacheKey); } } CalendarHashChain calendarHashChain = publicationTime == null ? KsiService.Extend(Signature.AggregationTime) : KsiService.Extend(Signature.AggregationTime, publicationTime.Value); lock (_cacheLock) { _calendarHashChainCache[cacheKey] = calendarHashChain; if (publicationTime == null) { _latestCalendarGetTime = DateTime.Now.Ticks; } } return(calendarHashChain); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); CalendarHashChain calendarHashChain = GetCalendarHashChain(signature, true); // If calendar hash chain is missing, verification successful if (calendarHashChain == null) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); } return(signature.GetLastAggregationHashChainRootHash() != calendarHashChain.InputHash ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Int03) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); CalendarAuthenticationRecord calendarAuthenticationRecord = signature.CalendarAuthenticationRecord; if (calendarAuthenticationRecord == null) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); } CalendarHashChain calendarHashChain = GetCalendarHashChain(signature); return(calendarHashChain.PublicationTime != calendarAuthenticationRecord.PublicationData.PublicationTime ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Int06) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); PublicationRecordInPublicationFile publicationRecord = GetNearestPublicationRecord(GetPublicationsFile(context), signature.AggregationTime); CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, publicationRecord.PublicationData.PublicationTime); if (publicationRecord.PublicationData.PublicationTime != extendedCalendarHashChain.PublicationTime) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub02)); } return(signature.AggregationTime != extendedCalendarHashChain.CalculateRegistrationTime() ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub02) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <summary> /// Extend signature to publication. /// </summary> /// <param name="signature">KSI signature</param> /// <param name="publicationRecord">publication</param> /// <returns>extended KSI signature</returns> public IKsiSignature Extend(IKsiSignature signature, PublicationRecordInSignature publicationRecord) { if (signature == null) { throw new ArgumentNullException(nameof(signature)); } if (publicationRecord == null) { throw new ArgumentNullException(nameof(publicationRecord)); } CalendarHashChain calendarHashChain = _ksiService.Extend(signature.AggregationTime, publicationRecord.PublicationData.PublicationTime); return(signature.Extend(calendarHashChain, publicationRecord, _ksiSignatureFactoryForExtending)); }
public void HAExtendingWithSingleServiceTest() { IKsiService haService = new HAKsiService( null, new List <IKsiService>() { GetStaticKsiService(File.ReadAllBytes(Path.Combine(TestSetup.LocalPath, Resources.KsiService_ExtendResponsePdu_RequestId_1043101455)), 1043101455) }, null); CalendarHashChain cal = haService.Extend(123); Assert.AreEqual(1455478441, cal.AggregationTime, "Unexpected aggregation time."); Assert.AreEqual(1455494400, cal.PublicationTime, "Unexpected publication time."); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); CalendarHashChain calendarHashChain = GetCalendarHashChain(signature, true); CalendarHashChain extendedCalendarHashChain = calendarHashChain == null ? context.GetExtendedLatestCalendarHashChain() : context.GetExtendedCalendarHashChain(calendarHashChain.PublicationTime); if (extendedCalendarHashChain == null) { throw new KsiVerificationException("Received invalid extended calendar hash chain from context extension function: null."); } return(signature.GetLastAggregationHashChainRootHash() != extendedCalendarHashChain.InputHash ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Cal02) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <summary> /// Get first deprecated hash algorithm from calendar hash chain. /// </summary> /// <param name="calendarHashChain"></param> /// <returns></returns> public static HashAlgorithm GetDeprecatedHashAlgorithm(CalendarHashChain calendarHashChain) { IEnumerator <CalendarHashChain.Link> linksEnumerator = calendarHashChain.GetLeftLinksEnumerator(); CalendarHashChain.Link link = linksEnumerator.MoveNext() ? linksEnumerator.Current : null; while (link != null) { if (link.Value.Algorithm.IsDeprecated(calendarHashChain.PublicationTime)) { return(link.Value.Algorithm); } link = linksEnumerator.MoveNext() ? linksEnumerator.Current : null; } return(null); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); CalendarHashChain calendarHashChain = GetCalendarHashChain(signature, true); // If calendar hash chain is missing, verification is successful if (calendarHashChain == null) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); } ReadOnlyCollection <AggregationHashChain> aggregationHashChains = GetAggregationHashChains(signature, false); ulong aggregationTime = aggregationHashChains[aggregationHashChains.Count - 1].AggregationTime; return(aggregationTime != calendarHashChain.AggregationTime ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Int04) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IPublicationsFile publicationsFile = GetPublicationsFile(context); IKsiSignature signature = GetSignature(context); PublicationRecordInPublicationFile publicationRecord = GetNearestPublicationRecord(publicationsFile, signature.AggregationTime, true); if (publicationRecord == null) { // if suitable publication record does not exist in publications file then return NA return(new VerificationResult(GetRuleName(), VerificationResultCode.Na, VerificationError.Gen02)); } CalendarHashChain extendedCalendarHashChain = GetExtendedCalendarHashChain(context, publicationRecord.PublicationData.PublicationTime); return(extendedCalendarHashChain.OutputHash != publicationRecord.PublicationData.PublicationHash ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Pub01) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { IKsiSignature signature = GetSignature(context); CalendarHashChain calendarHashChain = GetCalendarHashChain(signature, true); CalendarHashChain extendedCalendarHashChain = calendarHashChain?.PublicationData == null ? context.GetExtendedLatestCalendarHashChain() : context.GetExtendedCalendarHashChain(calendarHashChain.PublicationData.PublicationTime); if (extendedCalendarHashChain == null) { throw new KsiVerificationException("Received invalid extended calendar hash chain from context extension function: null."); } ReadOnlyCollection <AggregationHashChain> aggregationHashChains = GetAggregationHashChains(signature, false); ulong aggregationTime = aggregationHashChains[aggregationHashChains.Count - 1].AggregationTime; return(aggregationTime != extendedCalendarHashChain.AggregationTime ? new VerificationResult(GetRuleName(), VerificationResultCode.Fail, VerificationError.Cal03) : new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
/// <see cref="VerificationRule.Verify" /> public override VerificationResult Verify(IVerificationContext context) { CalendarHashChain calendarHashChain = GetSignature(context).CalendarHashChain; // If calendar hash chain is missing, verification successful if (calendarHashChain == null) { return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); } HashAlgorithm deprecatedHashAlgorithm = GetDeprecatedHashAlgorithm(calendarHashChain); if (deprecatedHashAlgorithm != null) { Logger.Debug("Calendar hash chain contains deprecated aggregation algorithm at publication time. Algorithm: {0}; Publication time: {1}", deprecatedHashAlgorithm.Name, calendarHashChain.PublicationTime); return(new VerificationResult(GetRuleName(), VerificationResultCode.Na, VerificationError.Gen02)); } return(new VerificationResult(GetRuleName(), VerificationResultCode.Ok)); }
public void ToStringTest() { Assembly assembly = typeof(AggregationHashChain).Assembly; Type linkType = assembly.GetType("Guardtime.KSI.Signature.CalendarHashChain+Link"); CalendarHashChain tag = TestUtil.GetCompositeTag <CalendarHashChain>(Constants.CalendarHashChain.TagType, new ITlvTag[] { new IntegerTag(Constants.CalendarHashChain.PublicationTimeTagType, false, false, 1), new IntegerTag(Constants.CalendarHashChain.AggregationTimeTagType, false, false, 0), new ImprintTag(Constants.CalendarHashChain.InputHashTagType, false, false, new DataHash(HashAlgorithm.Sha2256, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 })), // add links (ITlvTag)Activator.CreateInstance(linkType, new ImprintTag((uint)LinkDirection.Left, false, false, new DataHash(HashAlgorithm.Sha2256, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }))) }); CalendarHashChain tag2 = new CalendarHashChain(new RawTag(tag.Type, tag.NonCritical, tag.Forward, tag.EncodeValue())); Assert.AreEqual(tag.ToString(), tag2.ToString()); }
public void HAGetConfigResultsWithExtendRequestTest() { // Test getting extender configurations via ExtenderConfigChanged event handler when using Extend method. // Testing getting different configurations in a sequence HAKsiService haService = GetHAService( new List <PduPayload>() { GetExtendResponsePayload(Resources.KsiService_ExtendResponsePdu_RequestId_1043101454), GetExtenderConfigResponsePayload(4, new List <string>() { "uri-1" }, 1136073601, 1136073602) }, new List <PduPayload>() { GetExtendResponsePayload(Resources.KsiService_ExtendResponsePdu_RequestId_1043101455), GetExtenderConfigResponsePayload(4, new List <string>() { "uri-2" }, 1136073601, 1136073602) }); TestKsiService secondService = (TestKsiService)haService.ExtendingServices[1]; secondService.RequestId = 1043101455; ExtenderConfig resultConf = null; int changeCount = 0; ManualResetEvent waitHandle = new ManualResetEvent(false); haService.ExtenderConfigChanged += delegate(object sender, ExtenderConfigChangedEventArgs e) { resultConf = e.ExtenderConfig; changeCount++; if (changeCount == 2) { waitHandle.Set(); } }; CalendarHashChain cal = haService.Extend(123); Assert.AreEqual(1455494400, cal.PublicationTime, "Unexpected calendar hash chain publication time."); waitHandle.WaitOne(1000); Assert.IsNotNull(resultConf, "Could not get extender config using event handler."); Assert.AreEqual(4, resultConf.MaxRequests, "Unexpected max requests value"); Assert.AreEqual(1, resultConf.ParentsUris.Count, "Unexpected parent uri count"); Assert.IsTrue(resultConf.ParentsUris[0] == "uri-1" || resultConf.ParentsUris[0] == "uri-2", "Unexpected parent uri value at position 0"); Assert.AreEqual(1136073601, resultConf.CalendarFirstTime, "Unexpected calendar first time value"); Assert.AreEqual(1136073602, resultConf.CalendarLastTime, "Unexpected calendar last time value"); // changing extender algorithm or parent uri should not change merged config TestKsiService newService = (TestKsiService)GetService(new List <PduPayload>() { GetExtendResponsePayload(Resources.KsiService_ExtendResponsePdu_RequestId_1043101455), GetExtenderConfigResponsePayload(4, new List <string>() { "uri-2-changed" }, 1136073601, 1136073602) }); secondService.ExtendingServiceProtocol.RequestResult = newService.ExtendingServiceProtocol.RequestResult; resultConf = null; changeCount = 0; haService.Extend(123); Thread.Sleep(1000); Assert.IsNull(resultConf, "Extender config should have not changed (2nd request)"); Assert.AreEqual(0, changeCount, "Unexpected change count (2nd request)"); // changing max requests should change merged config newService = (TestKsiService)GetService(new List <PduPayload>() { GetExtendResponsePayload(Resources.KsiService_ExtendResponsePdu_RequestId_1043101455), GetExtenderConfigResponsePayload(5, new List <string>() { "uri-2" }, 1136073601, 1136073602) }); secondService.ExtendingServiceProtocol.RequestResult = newService.ExtendingServiceProtocol.RequestResult; waitHandle.Reset(); resultConf = null; changeCount = 0; haService.Extend(123); waitHandle.WaitOne(1000); Assert.IsNotNull(resultConf, "Could not get extender config using event handler (after 3rd extend request)."); Assert.AreEqual(5, resultConf.MaxRequests, "Unexpected max requests value (after 3rd extend request)"); Assert.AreEqual(1, resultConf.ParentsUris.Count, "Unexpected parent uri count (after 3rd extend request)"); Assert.IsTrue(resultConf.ParentsUris[0] == "uri-1" || resultConf.ParentsUris[0] == "uri-2", "Unexpected parent uri value at position 0 (after 3rd extend request)"); Assert.AreEqual(1136073601, resultConf.CalendarFirstTime, "Unexpected calendar first time value (after 3rd extend request)"); Assert.AreEqual(1136073602, resultConf.CalendarLastTime, "Unexpected calendar last time value (after 3rd extend request)"); // changing first time should change merged config newService = (TestKsiService)GetService(new List <PduPayload>() { GetExtendResponsePayload(Resources.KsiService_ExtendResponsePdu_RequestId_1043101455), GetExtenderConfigResponsePayload(5, new List <string>() { "uri-2" }, 1136073600, 1136073602) }); secondService.ExtendingServiceProtocol.RequestResult = newService.ExtendingServiceProtocol.RequestResult; waitHandle.Reset(); resultConf = null; changeCount = 0; haService.Extend(123); waitHandle.WaitOne(1000); Assert.IsNotNull(resultConf, "Could not get extender config using event handler (after 4th extend request)."); Assert.AreEqual(5, resultConf.MaxRequests, "Unexpected max requests value (after 4th extend request)"); Assert.AreEqual(1, resultConf.ParentsUris.Count, "Unexpected parent uri count (after 4th extend request)"); Assert.IsTrue(resultConf.ParentsUris[0] == "uri-1" || resultConf.ParentsUris[0] == "uri-2", "Unexpected parent uri value at position 0 (after 4th extend request)"); Assert.AreEqual(1136073600, resultConf.CalendarFirstTime, "Unexpected calendar first time value (after 4th extend request)"); Assert.AreEqual(1136073602, resultConf.CalendarLastTime, "Unexpected calendar last time value (after 4th extend request)"); // changing last time should change merged config newService = (TestKsiService)GetService(new List <PduPayload>() { GetExtendResponsePayload(Resources.KsiService_ExtendResponsePdu_RequestId_1043101455), GetExtenderConfigResponsePayload(5, new List <string>() { "uri-2" }, 1136073600, 1136073603) }); secondService.ExtendingServiceProtocol.RequestResult = newService.ExtendingServiceProtocol.RequestResult; waitHandle.Reset(); resultConf = null; changeCount = 0; haService.Extend(123); waitHandle.WaitOne(1000); Assert.IsNotNull(resultConf, "Could not get extender config using event handler (after 5th extend request)."); Assert.AreEqual(5, resultConf.MaxRequests, "Unexpected max requests value (after 5th extend request)"); Assert.AreEqual(1, resultConf.ParentsUris.Count, "Unexpected parent uri count (after 5th extend request)"); Assert.IsTrue(resultConf.ParentsUris[0] == "uri-1" || resultConf.ParentsUris[0] == "uri-2", "Unexpected parent uri value at position 0 (after 5th extend request)"); Assert.AreEqual(1136073600, resultConf.CalendarFirstTime, "Unexpected calendar first time value (after 5th extend request)"); Assert.AreEqual(1136073603, resultConf.CalendarLastTime, "Unexpected calendar last time value (after 5th extend request)"); // extending again should not change merged config waitHandle.Reset(); resultConf = null; changeCount = 0; haService.Extend(123); waitHandle.WaitOne(1000); Assert.IsNull(resultConf, "Extender config should have not changed (after 6th extend request)"); Assert.AreEqual(0, changeCount, "Unexpected change count."); }