diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs index a80359e3d82..4e553d5f8ec 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/EncryptedMessagesTests.cs @@ -68,153 +68,6 @@ public void TestFixtureTearDown() } protected abstract IJsonServiceClient CreateClient(); - - [Test] - public void Can_Send_Encrypted_Message() - { - var client = CreateClient(); - - var request = new HelloSecure { Name = "World" }; - - byte[] cryptKey, authKey, iv; - AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv); - - var cryptAuthKeys = cryptKey.Combine(authKey); - - var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); - var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); - - var timestamp = DateTime.UtcNow.ToUnixTime(); - var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson(); - - var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); - var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); - - var encryptedMessage = new EncryptedMessage - { - EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), - EncryptedBody = Convert.ToBase64String(authEncryptedBytes), - }; - - var encResponse = client.Post(encryptedMessage); - - authEncryptedBytes = Convert.FromBase64String(encResponse.EncryptedBody); - - if (!HmacUtils.Verify(authEncryptedBytes, authKey)) - throw new Exception("Invalid EncryptedBody"); - - var decryptedBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); - - var responseJson = decryptedBytes.FromUtf8Bytes(); - var response = responseJson.FromJson(); - - Assert.That(response.Result, Is.EqualTo("Hello, World!")); - } - - [Test] - public void Does_throw_on_old_messages() - { - var client = CreateClient(); - - var request = new HelloSecure { Name = "World" }; - - byte[] cryptKey, authKey, iv; - AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv); - - var cryptAuthKeys = cryptKey.Combine(authKey); - - var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); - var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); - - var timestamp = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(21)).ToUnixTime(); - - var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson(); - - var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); - var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); - - try - { - var encryptedMessage = new EncryptedMessage - { - EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), - EncryptedBody = Convert.ToBase64String(authEncryptedBytes), - }; - var encResponse = client.Post(encryptedMessage); - - Assert.Fail("Should throw"); - } - catch (WebServiceException ex) - { - ex.StatusDescription.Print(); - - var errorResponse = (EncryptedMessageResponse)ex.ResponseDto; - - authEncryptedBytes = Convert.FromBase64String(errorResponse.EncryptedBody); - if (!HmacUtils.Verify(authEncryptedBytes, authKey)) - throw new Exception("EncryptedBody is Invalid"); - - var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); - var responseJson = responseBytes.FromUtf8Bytes(); - var response = responseJson.FromJson(); - Assert.That(response.ResponseStatus.Message, Is.EqualTo("Request too old")); - } - } - - [Test] - public void Does_throw_on_replayed_messages() - { - var client = CreateClient(); - - var request = new HelloSecure { Name = "World" }; - - byte[] cryptKey, iv; - AesUtils.CreateKeyAndIv(out cryptKey, out iv); - - byte[] authKey = AesUtils.CreateKey(); - - var cryptAuthKeys = cryptKey.Combine(authKey); - - var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); - var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); - - var timestamp = DateTime.UtcNow.ToUnixTime(); - var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson(); - - var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); - var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); - - var encryptedMessage = new EncryptedMessage - { - EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), - EncryptedBody = Convert.ToBase64String(authEncryptedBytes), - }; - - var encResponse = client.Post(encryptedMessage); - - try - { - client.Post(encryptedMessage); - - Assert.Fail("Should throw"); - } - catch (WebServiceException ex) - { - ex.StatusDescription.Print(); - - var errorResponse = (EncryptedMessageResponse)ex.ResponseDto; - - authEncryptedBytes = Convert.FromBase64String(errorResponse.EncryptedBody); - if (!HmacUtils.Verify(authEncryptedBytes, authKey)) - throw new Exception("EncryptedBody is Invalid"); - - var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); - var responseJson = responseBytes.FromUtf8Bytes(); - var response = responseJson.FromJson(); - Assert.That(response.ResponseStatus.Message, Is.EqualTo("Nonce already seen")); - } - } - [Test] public void Can_Send_Encrypted_Message_with_ServiceClients() { @@ -372,6 +225,21 @@ public void Can_call_GET_only_Services() Assert.That(response.Result, Is.EqualTo("Hello, World!")); } + [Test] + public void Can_send_large_messages() + { + var client = CreateClient(); + IEncryptedClient encryptedClient = client.GetEncryptedClient(client.Get("/publickey")); + + var request = new LargeMessage { + Messages = 100.Times(i => new HelloSecure {Name = "Name" + i}) + }; + + var response = encryptedClient.Send(request); + + Assert.That(response.Messages.Count, Is.EqualTo(request.Messages.Count)); + } + [Test] public void Can_send_auto_batched_requests() { @@ -386,6 +254,152 @@ public void Can_send_auto_batched_requests() Assert.That(responseNames, Is.EqualTo(names.Map(x => "Hello, {0}!".Fmt(x)))); } + + [Test] + public void Can_Send_Encrypted_Message() + { + var client = CreateClient(); + + var request = new HelloSecure { Name = "World" }; + + byte[] cryptKey, authKey, iv; + AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var timestamp = DateTime.UtcNow.ToUnixTime(); + var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson(); + + var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + var encryptedMessage = new EncryptedMessage + { + EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), + EncryptedBody = Convert.ToBase64String(authEncryptedBytes), + }; + + var encResponse = client.Post(encryptedMessage); + + authEncryptedBytes = Convert.FromBase64String(encResponse.EncryptedBody); + + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("Invalid EncryptedBody"); + + var decryptedBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + + var responseJson = decryptedBytes.FromUtf8Bytes(); + var response = responseJson.FromJson(); + + Assert.That(response.Result, Is.EqualTo("Hello, World!")); + } + + [Test] + public void Does_throw_on_old_messages() + { + var client = CreateClient(); + + var request = new HelloSecure { Name = "World" }; + + byte[] cryptKey, authKey, iv; + AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var timestamp = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(21)).ToUnixTime(); + + var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson(); + + var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + try + { + var encryptedMessage = new EncryptedMessage + { + EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), + EncryptedBody = Convert.ToBase64String(authEncryptedBytes), + }; + var encResponse = client.Post(encryptedMessage); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.StatusDescription.Print(); + + var errorResponse = (EncryptedMessageResponse)ex.ResponseDto; + + authEncryptedBytes = Convert.FromBase64String(errorResponse.EncryptedBody); + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("EncryptedBody is Invalid"); + + var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + var responseJson = responseBytes.FromUtf8Bytes(); + var response = responseJson.FromJson(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("Request too old")); + } + } + + [Test] + public void Does_throw_on_replayed_messages() + { + var client = CreateClient(); + + var request = new HelloSecure { Name = "World" }; + + byte[] cryptKey, iv; + AesUtils.CreateKeyAndIv(out cryptKey, out iv); + + byte[] authKey = AesUtils.CreateKey(); + + var cryptAuthKeys = cryptKey.Combine(authKey); + + var rsaEncCryptAuthKeys = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml); + var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv); + + var timestamp = DateTime.UtcNow.ToUnixTime(); + var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson(); + + var encryptedBytes = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv); + var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv); + + var encryptedMessage = new EncryptedMessage + { + EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys), + EncryptedBody = Convert.ToBase64String(authEncryptedBytes), + }; + + var encResponse = client.Post(encryptedMessage); + + try + { + client.Post(encryptedMessage); + + Assert.Fail("Should throw"); + } + catch (WebServiceException ex) + { + ex.StatusDescription.Print(); + + var errorResponse = (EncryptedMessageResponse)ex.ResponseDto; + + authEncryptedBytes = Convert.FromBase64String(errorResponse.EncryptedBody); + if (!HmacUtils.Verify(authEncryptedBytes, authKey)) + throw new Exception("EncryptedBody is Invalid"); + + var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); + var responseJson = responseBytes.FromUtf8Bytes(); + var response = responseJson.FromJson(); + Assert.That(response.ResponseStatus.Message, Is.EqualTo("Nonce already seen")); + } + } } public class CryptUtilsTests diff --git a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs index 1c606700635..05421e702d1 100644 --- a/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs +++ b/tests/ServiceStack.WebHost.Endpoints.Tests/UseCases/SecureConfig.cs @@ -2,6 +2,7 @@ // License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt using System; +using System.Collections.Generic; using ServiceStack.Auth; namespace ServiceStack.WebHost.Endpoints.Tests.UseCases @@ -39,6 +40,11 @@ public class HelloAuthenticated : IReturn, IHasSessi public int Version { get; set; } } + public class LargeMessage : IReturn + { + public List Messages { get; set; } + } + [Authenticate] public class HelloAuthSecure : IReturn { @@ -100,5 +106,10 @@ public object Any(HelloAuthenticated request) IsAuthenticated = session.IsAuthenticated, }; } + + public object Any(LargeMessage request) + { + return request; + } } } \ No newline at end of file