private bool IsValidPenny(Penny penny)
        {
            bool result = true;

            //start by testing the cache

            if (((BalloonStore)Process).CachedPennies.Any(p => penny.Id == p.Id))
            {
                reply.Note = "Invalid Penny, I've seen this one before";
                result = false;
            }
            else
            {
                //now verify the signature is valid

                RSAParameters receiverRSAKeyInfo = new RSAParameters();
                receiverRSAKeyInfo.Modulus = ((BalloonStore)Process).PennyBankPublicKey.Modulus;
                receiverRSAKeyInfo.Exponent = ((BalloonStore)Process).PennyBankPublicKey.Exponent;

                RSACryptoServiceProvider receiverRSA = new RSACryptoServiceProvider();
                receiverRSA.ImportParameters(receiverRSAKeyInfo);

                SHA1Managed hasher = new SHA1Managed();
                byte[] bytes = penny.DataBytes();
                byte[] hash = hasher.ComputeHash(bytes);

                RSAPKCS1SignatureDeformatter rsaSignComparer = new RSAPKCS1SignatureDeformatter(receiverRSA);
                rsaSignComparer.SetHashAlgorithm("SHA1");

                bool verified = rsaSignComparer.VerifySignature(hash, penny.DigitalSignature);

                if (!verified)
                {
                    reply.Note = "Invalid Penny, the signature doesn't check out";
                    result = false;
                }
                else
                {
                    //finally ask the PennyBank to do the final validation

                    ValidatePennyConversation conv = ((BalloonStore)Process).CommSubsystem.ConversationFactory.CreateFromConversationType<ValidatePennyConversation>();
                    conv.TargetEndPoint = ((BalloonStore)Process).PennyBankEndPoint;
                    conv.Parent = this;
                    conv.Pennies = new Penny[] { penny };

                    conv.Execute();

                    if (!ValidatedByPennyBank)
                    {
                        reply.Note = "Invalid Penny, PennyBank said no";
                        result = false;
                    }
                }
            }

            return result;
        }
Beispiel #2
0
        public void BalloonStore_TestBuyBalloonConversation()
        {
            Communicator mockRegistry = new Communicator() { MinPort = 13000, MaxPort = 13050 };

            mockRegistry.Start();
            PublicEndPoint mockEp = new PublicEndPoint(String.Format("127.0.0.1:{0}", mockRegistry.Port));

            balloonStore.MyProcessInfo.Status = ProcessInfo.StatusCode.Initializing;
            balloonStore.RegistryEndPoint = mockEp;
            balloonStore.GetConversation().Launch(); // launch a bogus conversation in order to get the balloon store endpoint

            Envelope env = mockRegistry.Receive(1000);

            IPEndPoint balloonStoreEp = env.IPEndPoint;

            Penny penny = new Penny() { Id = 1 };

           // test not in game
            balloonStore.MyProcessInfo.Status = ProcessInfo.StatusCode.PlayingGame;
            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new BuyBalloonRequest()
                {
                    ConvId = new MessageNumber() { Pid = 1, Seq = 1 },
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Penny = penny
                }
            };

            mockRegistry.Send(env);

            BalloonReply reply = mockRegistry.Receive(2000).ActualMessage as BalloonReply;

            Assert.That(reply.Balloon, Is.Null);
            Assert.That(reply.Success, Is.False);
            Assert.That(reply.Note, Is.StringContaining("You are not in the Game"));

            // test no balloons
            balloonStore.Players.Add(new GameProcessData() { ProcessId = 1 });
            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new BuyBalloonRequest()
                {
                    ConvId = new MessageNumber() { Pid = 1, Seq = 1 },
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Penny = penny
                }
            };

            mockRegistry.Send(env);

            reply = mockRegistry.Receive(2000).ActualMessage as BalloonReply;

            Assert.That(reply.Balloon, Is.Null);
            Assert.That(reply.Success, Is.False);
            Assert.That(reply.Note, Is.StringContaining("No balloons left in inventory"));

            // test cached penny
            balloonStore.CachedPennies.Add(penny);
            balloonStore.CreateBalloons();
            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new BuyBalloonRequest()
                {
                    ConvId = new MessageNumber() { Pid = 1, Seq = 1 },
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Penny = penny
                }
            };

            mockRegistry.Send(env);

            reply = mockRegistry.Receive(2000).ActualMessage as BalloonReply;

            Assert.That(reply.Balloon, Is.Null);
            Assert.That(reply.Success, Is.False);
            Assert.That(reply.Note, Is.StringContaining("Invalid Penny, I've seen this one before"));

            balloonStore.CachedPennies.Remove(penny);

            // test invalid signature
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            RSAParameters parameters = rsa.ExportParameters(false);
            balloonStore.PennyBankPublicKey = new PublicKey()
            {
                Exponent = parameters.Exponent,
                Modulus = parameters.Modulus
            };

            penny.DigitalSignature = new byte[] { 1, 2, 3 };

            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new BuyBalloonRequest()
                {
                    ConvId = new MessageNumber() { Pid = 1, Seq = 1 },
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Penny = penny
                }
            };

            mockRegistry.Send(env);

            reply = mockRegistry.Receive(2000).ActualMessage as BalloonReply;

            Assert.That(reply.Balloon, Is.Null);
            Assert.That(reply.Success, Is.False);
            Assert.That(reply.Note, Is.StringContaining("Invalid Penny, the signature doesn't check out"));

            // test valid signature, but failed ValidatePennyConversation
            balloonStore.PennyBankEndPoint = balloonStore.RegistryEndPoint;
            RSAPKCS1SignatureFormatter rsaSigner = new RSAPKCS1SignatureFormatter(rsa);
            rsaSigner.SetHashAlgorithm("SHA1");
            SHA1Managed hasher = new SHA1Managed();
            byte[] bytes = penny.DataBytes();
            byte[] hash = hasher.ComputeHash(bytes);

            penny.DigitalSignature = rsaSigner.CreateSignature(hash);

            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new BuyBalloonRequest()
                {
                    ConvId = new MessageNumber() { Pid = 1, Seq = 1 },
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Penny = penny
                }
            };

            mockRegistry.Send(env);


            // balloon store would have started a PennyValidation conversation
            PennyValidation request = mockRegistry.Receive(2000).ActualMessage as PennyValidation;

            Assert.That(request.MarkAsUsedIfValid, Is.True);
            Assert.That(request.Pennies[0].Id, Is.EqualTo(penny.Id));

            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new Reply()
                {
                    ConvId = request.ConvId,
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Success = false
                }
            };

            reply = mockRegistry.Receive(2000).ActualMessage as BalloonReply;

            Assert.That(reply.Balloon, Is.Null);
            Assert.That(reply.Success, Is.False);
            Assert.That(reply.Note, Is.StringContaining("Invalid Penny, PennyBank said no"));

            // test successful conversation

            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new BuyBalloonRequest()
                {
                    ConvId = new MessageNumber() { Pid = 1, Seq = 1 },
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Penny = penny
                }
            };

            mockRegistry.Send(env);


            // balloon store would have started a PennyValidation conversation
            request = mockRegistry.Receive(500).ActualMessage as PennyValidation;

            Assert.That(request.MarkAsUsedIfValid, Is.True);
            Assert.That(request.Pennies[0].Id, Is.EqualTo(penny.Id));

            env = new Envelope()
            {
                IPEndPoint = balloonStoreEp,
                Message = new Reply()
                {
                    ConvId = request.ConvId,
                    MsgId = new MessageNumber() { Pid = 1, Seq = 1 },
                    Success = true
                }
            };

            mockRegistry.Send(env);

            reply = mockRegistry.Receive(2000).ActualMessage as BalloonReply;

            Assert.That(reply.Balloon, Is.Not.Null);
            Assert.That(reply.Success, Is.True);
            Assert.That(reply.Note, Is.StringContaining("Nice doing business"));
            Assert.That(balloonStore.CachedPennies.Any(p => p.Id == penny.Id), Is.True);

            mockRegistry.Stop();
        }