summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/Bindings/StandardExpirationBindingElementTests.cs16
-rw-r--r--src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs10
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs9
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingStrings.resx5
4 files changed, 37 insertions, 3 deletions
diff --git a/src/DotNetOpenAuth.Test/Messaging/Bindings/StandardExpirationBindingElementTests.cs b/src/DotNetOpenAuth.Test/Messaging/Bindings/StandardExpirationBindingElementTests.cs
index 9ba433d..e0c2de6 100644
--- a/src/DotNetOpenAuth.Test/Messaging/Bindings/StandardExpirationBindingElementTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/Bindings/StandardExpirationBindingElementTests.cs
@@ -6,6 +6,8 @@
namespace DotNetOpenAuth.Test.Messaging.Bindings {
using System;
+
+ using DotNetOpenAuth.Configuration;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
using DotNetOpenAuth.Test.Mocks;
@@ -30,10 +32,22 @@ namespace DotNetOpenAuth.Test.Messaging.Bindings {
this.ParameterizedReceiveProtectedTest(DateTime.UtcNow, false);
}
+ [TestCase]
+ public void VerifyFutureTimestampWithinClockSkewIsAccepted() {
+ this.Channel = CreateChannel(MessageProtections.Expiration);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow + DotNetOpenAuthSection.Configuration.Messaging.MaximumClockSkew - TimeSpan.FromSeconds(1), false);
+ }
+
[TestCase, ExpectedException(typeof(ExpiredMessageException))]
- public void VerifyBadTimestampIsRejected() {
+ public void VerifyOldTimestampIsRejected() {
this.Channel = CreateChannel(MessageProtections.Expiration);
this.ParameterizedReceiveProtectedTest(DateTime.UtcNow - StandardExpirationBindingElement.MaximumMessageAge - TimeSpan.FromSeconds(1), false);
}
+
+ [TestCase, ExpectedException(typeof(ProtocolException))]
+ public void VerifyFutureTimestampIsRejected() {
+ this.Channel = CreateChannel(MessageProtections.Expiration);
+ this.ParameterizedReceiveProtectedTest(DateTime.UtcNow + DotNetOpenAuthSection.Configuration.Messaging.MaximumClockSkew + TimeSpan.FromSeconds(1), false);
+ }
}
}
diff --git a/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs b/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs
index ddfa88a..4396c16 100644
--- a/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs
+++ b/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs
@@ -83,11 +83,19 @@ namespace DotNetOpenAuth.Messaging.Bindings {
if (expiringMessage != null) {
// Yes the UtcCreationDate is supposed to always be in UTC already,
// but just in case a given message failed to guarantee that, we do it here.
- DateTime expirationDate = expiringMessage.UtcCreationDate.ToUniversalTimeSafe() + MaximumMessageAge;
+ DateTime creationDate = expiringMessage.UtcCreationDate.ToUniversalTimeSafe();
+ DateTime expirationDate = creationDate + MaximumMessageAge;
if (expirationDate < DateTime.UtcNow) {
throw new ExpiredMessageException(expirationDate, expiringMessage);
}
+ // Mitigate HMAC attacks (just guessing the signature until they get it) by
+ // disallowing post-dated messages.
+ ErrorUtilities.VerifyProtocol(
+ creationDate <= DateTime.UtcNow + DotNetOpenAuthSection.Configuration.Messaging.MaximumClockSkew,
+ MessagingStrings.MessageTimestampInFuture,
+ creationDate);
+
return MessageProtections.Expiration;
}
diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
index 6f8c4f9..ca69f5f 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
@@ -313,6 +313,15 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Looks up a localized string similar to This message has a timestamp of {0}, which is beyond the allowable clock skew for in the future..
+ /// </summary>
+ internal static string MessageTimestampInFuture {
+ get {
+ return ResourceManager.GetString("MessageTimestampInFuture", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to A non-empty string was expected..
/// </summary>
internal static string NonEmptyStringExpected {
diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
index bdf4f68..102f044 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
+++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
@@ -303,4 +303,7 @@
<data name="SessionRequired" xml:space="preserve">
<value>An HttpContext.Current.Session object is required.</value>
</data>
-</root> \ No newline at end of file
+ <data name="MessageTimestampInFuture" xml:space="preserve">
+ <value>This message has a timestamp of {0}, which is beyond the allowable clock skew for in the future.</value>
+ </data>
+</root>