Example #1
0
        public async Task GetActiveSigningKeyPair_GivenRotationAndMasterKeyCert_ReturnsAKeyPairUsableForTokenSigning()
        {
            //Arrange
            var automocker = new AutoMocker();

            var masterKey = new byte[256];

            object cachedResult = null;

            automocker
            .SetupOptions(new AnonymousTokensConfig
            {
                KeyRotationEnabled  = true,
                CurveName           = "P-256",
                MasterKeyCertId     = "master-key-cert",
                KeyRotationInterval = TimeSpan.FromDays(3),
                KeyRotationRollover = TimeSpan.FromDays(4)
            });

            automocker
            .Setup <IMemoryCache, bool>(x => x.TryGetValue(It.IsAny <string>(), out cachedResult))
            .Returns(false);

            automocker
            .Setup <IMemoryCache, ICacheEntry>(x => x.CreateEntry(It.IsAny <string>()))
            .Returns(Mock.Of <ICacheEntry>());

            automocker
            .Setup <IAnonymousTokenMasterKeyLoader, Task <byte[]> >(x => x.LoadMasterKeyBytes())
            .ReturnsAsync(masterKey);

            var target = automocker.CreateInstance <AnonymousTokenKeyStore>();

            //Act
            var result = await target.GetActiveSigningKeyPair();

            //Assert
            var ecParameters = CustomNamedCurves.GetByOid(X9ObjectIdentifiers.Prime256v1);
            var initiator    = new Initiator();
            var init         = initiator.Initiate(ecParameters.Curve);
            var t            = init.t;
            var r            = init.r;
            var P            = init.P;

            var tokenGenerator = new TokenGenerator();

            var(Q, c, z) = tokenGenerator.GenerateToken(result.PrivateKey, result.PublicKey, ecParameters, P);

            var keyDto = result.AsValidationKey().AsKeyDto();

            var clientSideEcParameters   = CustomNamedCurves.GetByName(keyDto.Crv); // Matches keyDto.Crv == "P-256"
            var clientSidePublicKeyPoint = clientSideEcParameters.Curve.CreatePoint(new BigInteger(Convert.FromBase64String(keyDto.X)), new BigInteger(Convert.FromBase64String(keyDto.Y)));

            var W = initiator.RandomiseToken(clientSideEcParameters, clientSidePublicKeyPoint, P, Q, c, z, r);

            var tokenVerifier = new TokenVerifier(new InMemorySeedStore());
            var isVerified    = await tokenVerifier.VerifyTokenAsync(result.PrivateKey, ecParameters.Curve, t, W);

            isVerified.Should().BeTrue();
        }
        public async void VerifyToken_InvalidW_ThrowsException()
        {
            // Arrange
            var seedStoreMock = new Mock <ISeedStore>();

            seedStoreMock.Setup(x => x.ExistsAsync(It.IsAny <byte[]>())).Returns(Task.FromResult(false));
            seedStoreMock.Setup(x => x.SaveAsync(It.IsAny <byte[]>())).Returns(Task.FromResult(true));

            var tokenVerifier = new TokenVerifier(seedStoreMock.Object);

            var privateKey = new BigInteger(Hex.Decode("01301abfe491c0aff380269c966254ac43fdd97469234c7739ada975368181fe"));

            byte[] t = Hex.Decode("4391837b1e50cb0b075fc91ea9a85a4a795195557f4fb9a971e10b94370dee2b");
            var    W = _ecParameters.Curve.DecodePoint(Hex.Decode("04ce1e55cff15c5f5fbd0abca2a2849cf04ccda1c601a849ab28eb6161a0c32e96b6346728d8d3464754361977ee1a1c68120cb0575506cafe6e24d595de92069d"));

            // Create a new point with invalid coordinates
            var invalidW = _ecParameters.Curve.CreatePoint(W.XCoord.ToBigInteger().Add(BigInteger.One), W.YCoord.ToBigInteger());

            try
            {
                // Act
                await tokenVerifier.VerifyTokenAsync(privateKey, _ecParameters.Curve, t, invalidW);
            }
            catch (AnonymousTokensException)
            {
                Assert.True(true, "an invalid point should raise an exception");
            }
        }
        public async void Run()
        {
            // 1. Initiate communication with a masked point P = r*T = r*Hash(t)
            var init = _initiator.Initiate(_ecParameters.Curve);
            var t    = init.t;
            var r    = init.r;
            var P    = init.P;

            // 2. Generate token Q = k*P and proof (c,z) of correctness
            var(Q, proofC, proofZ) = _tokenGenerator.GenerateToken(_privateKey, _publicKey.Q, _ecParameters, P);

            // 3. Randomise the token Q, by removing the mask r: W = (1/r)*Q = k*T. Also checks that proof (c,z) is correct.
            var W = _initiator.RandomiseToken(_ecParameters, _publicKey.Q, P, Q, proofC, proofZ, r);

            // 4. Verify that the token (t,W) is correct.
            var isVerified = await _tokenVerifier.VerifyTokenAsync(_privateKey, _ecParameters.Curve, t, W);

            if (isVerified == false)
            {
                Assert.True(false, "token was expected to be valid");
            }
        }
        public async void VerifyToken_tExistsInSeedStore_ReturnsFalse()
        {
            // Arrange
            var seedStoreMock = new Mock <ISeedStore>();

            seedStoreMock.Setup(x => x.ExistsAsync(It.IsAny <byte[]>())).Returns(Task.FromResult(true));

            var privateKey = new BigInteger(Hex.Decode("01301abfe491c0aff380269c966254ac43fdd97469234c7739ada975368181fe"));

            byte[] t = Hex.Decode("4391837b1e50cb0b075fc91ea9a85a4a795195557f4fb9a971e10b94370dee2b");
            var    W = _ecParameters.Curve.DecodePoint(Hex.Decode("04ce1e55cff15c5f5fbd0abca2a2849cf04ccda1c601a849ab28eb6161a0c32e96b6346728d8d3464754361977ee1a1c68120cb0575506cafe6e24d595de92069d"));

            var tokenVerifier = new TokenVerifier(seedStoreMock.Object);

            // Act
            var actual = await tokenVerifier.VerifyTokenAsync(privateKey, _ecParameters.Curve, t, W);

            // Assert
            Assert.False(actual);
        }
        public async Task Handle_GivenRequestForNewToken_ReturnsAnonymousTokenResponse()
        {
            //Arrange
            var automocker = new AutoMocker();

            var curveName    = "P-256";
            var ecParameters = CustomNamedCurves.GetByName(curveName);

            var initiator = new Initiator();
            var init      = initiator.Initiate(ecParameters.Curve);
            var t         = init.t;
            var r         = init.r;
            var P         = init.P;

            var privateKey     = await new InMemoryPrivateKeyStore().GetAsync();
            var publicKey      = (await new InMemoryPublicKeyStore().GetAsync()).Q;
            var signingKeyPair = new AnonymousTokenSigningKeypair("some-kid-123", curveName, privateKey, publicKey);

            var tokenGenerator = new TokenGenerator();

            var(expectedSignedPoint, expectedProofChallenge, expectedProofResponse) = tokenGenerator.GenerateToken(privateKey, publicKey, ecParameters, P);

            var tokenVerifier = new TokenVerifier(new InMemorySeedStore());

            var tokenRequest = new IssueAnonymousToken.Command
            {
                JwtTokenId     = "token-a",
                JwtTokenExpiry = DateTime.Now.AddMinutes(10),
                RequestData    = new AnonymousTokenRequest
                {
                    MaskedPoint = Convert.ToBase64String(P.GetEncoded())
                }
            };

            automocker
            .SetupOptions(new AnonymousTokensConfig
            {
                Enabled = true
            });

            automocker
            .Setup <IAnonymousTokenIssueRecordRepository, Task <IEnumerable <AnonymousTokenIssueRecord> > >(x => x.RetrieveRecordsJwtToken(It.IsAny <string>()))
            .Returns <string>(x => Task.FromResult(Enumerable.Empty <AnonymousTokenIssueRecord>()));

            automocker
            .Setup <IAnonymousTokensKeyStore, Task <AnonymousTokenSigningKeypair> >(x => x.GetActiveSigningKeyPair())
            .ReturnsAsync(signingKeyPair);

            automocker
            .Setup <ITokenGenerator, (ECPoint, BigInteger, BigInteger)>(x => x.GenerateToken(privateKey, publicKey, ecParameters, It.Is <ECPoint>(y => y.Equals(P))))
            .Returns((expectedSignedPoint, expectedProofChallenge, expectedProofResponse));

            var target = automocker.CreateInstance <IssueAnonymousToken.Handler>();

            //Act
            var result = await target.Handle(tokenRequest, new CancellationToken());

            //Assert
            using (new AssertionScope())
            {
                result.HasValue.Should().BeTrue();
                var anonymousTokenResponse = result.ValueOrFailure();

                anonymousTokenResponse.Kid.Should().Be("some-kid-123");

                var Q = ecParameters.Curve.DecodePoint(Convert.FromBase64String(anonymousTokenResponse.SignedPoint));
                var c = new BigInteger(Convert.FromBase64String(anonymousTokenResponse.ProofChallenge));
                var z = new BigInteger(Convert.FromBase64String(anonymousTokenResponse.ProofResponse));

                Q.Should().Be(expectedSignedPoint);
                c.Should().Be(expectedProofChallenge);
                z.Should().Be(expectedProofResponse);

                var W          = initiator.RandomiseToken(ecParameters, publicKey, P, Q, c, z, r);
                var isVerified = await tokenVerifier.VerifyTokenAsync(privateKey, ecParameters.Curve, t, W);

                isVerified.Should().BeTrue();
            }
        }