public void RevokedCodeSigningCertificateWithRevocationDateInvalidatesSignatures(
                TimeSpan signatureTimeDeltaToRevocationTime,
                SignatureDecision ingestionDecision,
                SignatureDecision gracePeriodDecision,
                SignatureDecision afterGracePeriodDecision)
            {
                // Arrange - only signatures that were created after the revocation date should
                // be rejected.
                var revocationTime = DateTime.UtcNow;
                var certificate    = new EndCertificate {
                    Use = EndCertificateUse.CodeSigning
                };
                var timestamp = new TrustedTimestamp {
                    Value = revocationTime + signatureTimeDeltaToRevocationTime, Status = TrustedTimestampStatus.Valid
                };

                var result = new CertificateVerificationResult(
                    status: EndCertificateStatus.Revoked,
                    statusFlags: X509ChainStatusFlags.Revoked,
                    revocationTime: revocationTime);

                var signatureAtIngestion = new PackageSignature {
                    Status = PackageSignatureStatus.Unknown
                };
                var signatureAtGracePeriod = new PackageSignature {
                    Status = PackageSignatureStatus.InGracePeriod
                };
                var signatureAfterGracePeriod = new PackageSignature {
                    Status = PackageSignatureStatus.Valid
                };

                signatureAtIngestion.TrustedTimestamps      = new[] { timestamp };
                signatureAtGracePeriod.TrustedTimestamps    = new[] { timestamp };
                signatureAfterGracePeriod.TrustedTimestamps = new[] { timestamp };

                // Act & Assert
                var decider = _target.MakeDeciderForRevokedCertificate(certificate, result);

                Assert.Equal(ingestionDecision, decider(signatureAtIngestion));
                Assert.Equal(gracePeriodDecision, decider(signatureAtGracePeriod));
                Assert.Equal(afterGracePeriodDecision, decider(signatureAfterGracePeriod));
            }
        private void InitializeTrustedTimestamp(
            PackageSignature packageSignature,
            Signature signature,
            HashedCertificate timestampEndCertificate,
            IReadOnlyDictionary <string, EndCertificate> thumbprintToEndCertificate)
        {
            if (packageSignature.TrustedTimestamps.Count > 1)
            {
                _logger.LogError(
                    "There are {Count} trusted timestamps for the {SignatureType} signature on package {PackageKey}. There should be either zero or one.",
                    packageSignature.TrustedTimestamps.Count,
                    signature.Type,
                    packageSignature.PackageKey);

                throw new InvalidOperationException("There should never be more than one trusted timestamp per package signature.");
            }

            // Determine the value of the timestamp.
            var value = signature.Timestamps.Single().UpperLimit.UtcDateTime;

            TrustedTimestamp trustedTimestamp;

            if (packageSignature.TrustedTimestamps.Count == 0)
            {
                trustedTimestamp = new TrustedTimestamp
                {
                    PackageSignature    = packageSignature,
                    PackageSignatureKey = packageSignature.Key,
                    EndCertificate      = thumbprintToEndCertificate[timestampEndCertificate.Thumbprint],
                    Value  = value,
                    Status = TrustedTimestampStatus.Valid,
                };
                trustedTimestamp.EndCertificateKey = trustedTimestamp.EndCertificate.Key;
                packageSignature.TrustedTimestamps.Add(trustedTimestamp);
                _entitiesContext.TrustedTimestamps.Add(trustedTimestamp);
            }
            else
            {
                trustedTimestamp = packageSignature.TrustedTimestamps.Single();

                if (trustedTimestamp.EndCertificate.Thumbprint != timestampEndCertificate.Thumbprint)
                {
                    _logger.LogError(
                        "The timestamp end certificate thumbprint cannot change for the {SignatureType} signature " +
                        "on package {PackageKey}. The existing timestamp end certificate is {ExistingThumbprint}. " +
                        "The new thumprint is {NewThumbprint}.",
                        signature.Type,
                        packageSignature.PackageKey,
                        packageSignature.EndCertificate.Thumbprint,
                        timestampEndCertificate.Thumbprint);

                    throw new InvalidOperationException("The thumbprint of the timestamp end certificate cannot change.");
                }

                if (trustedTimestamp.Value != value)
                {
                    _logger.LogError(
                        "The trusted timestamp value cannot change for the {SignatureType} signature on package " +
                        "{PackageKey}. The existing timestamp value is {ExistingValue}. The new value is {NewValue}.",
                        signature.Type,
                        packageSignature.PackageKey,
                        trustedTimestamp.Value,
                        value);

                    throw new InvalidOperationException("The value of the trusted timestamp cannot change.");
                }
            }
        }
Esempio n. 3
0
        public async Task ValidateSigningCertificate(
            Func <CertificateIntegrationTestFixture, Task <X509Certificate2> > createCertificateFunc,
            DateTime signatureTime,
            EndCertificateStatus expectedCertificateStatus,
            PackageSignatureStatus expectedStatusForSignatureAtIngestion,
            PackageSignatureStatus expectedStatusForSignatureInGracePeriod,
            PackageSignatureStatus expectedStatusForSignatureAfterGracePeriod)
        {
            // Arrange
            var certificate = await createCertificateFunc(_fixture);

            var endCertificateKey = 123;
            var validationId      = Guid.NewGuid();

            var packageSigningState1 = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };
            var packageSigningState2 = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };
            var packageSigningState3 = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };

            var signatureAtIngestion = new PackageSignature
            {
                Status = PackageSignatureStatus.Unknown,
                Type   = PackageSignatureType.Author,
            };
            var signatureInGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.InGracePeriod,
                Type   = PackageSignatureType.Author,
            };
            var signatureAfterGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.Valid,
                Type   = PackageSignatureType.Author,
            };

            var trustedTimestamp1 = new TrustedTimestamp {
                Status = TrustedTimestampStatus.Valid, Value = signatureTime
            };
            var trustedTimestamp2 = new TrustedTimestamp {
                Status = TrustedTimestampStatus.Valid, Value = signatureTime
            };
            var trustedTimestamp3 = new TrustedTimestamp {
                Status = TrustedTimestampStatus.Valid, Value = signatureTime
            };

            var endCertificate = new EndCertificate
            {
                Key    = endCertificateKey,
                Status = EndCertificateStatus.Unknown,
                Use    = EndCertificateUse.CodeSigning,
                CertificateChainLinks = new CertificateChainLink[0],
            };

            var validation = new EndCertificateValidation
            {
                EndCertificateKey = endCertificateKey,
                ValidationId      = validationId,
                Status            = null,
                EndCertificate    = endCertificate
            };

            signatureAtIngestion.PackageSigningState      = packageSigningState1;
            signatureAtIngestion.EndCertificate           = endCertificate;
            signatureAtIngestion.TrustedTimestamps        = new[] { trustedTimestamp1 };
            signatureInGracePeriod.PackageSigningState    = packageSigningState2;
            signatureInGracePeriod.EndCertificate         = endCertificate;
            signatureInGracePeriod.TrustedTimestamps      = new[] { trustedTimestamp2 };
            signatureAfterGracePeriod.PackageSigningState = packageSigningState3;
            signatureAfterGracePeriod.EndCertificate      = endCertificate;
            signatureAfterGracePeriod.TrustedTimestamps   = new[] { trustedTimestamp3 };

            _context.Mock(
                packageSignatures: new[] { signatureAtIngestion, signatureInGracePeriod, signatureAfterGracePeriod },
                endCertificates: new[] { endCertificate },
                certificateValidations: new EndCertificateValidation[] { validation });

            _certificateStore.Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(certificate));

            // Act
            await _target.HandleAsync(new CertificateValidationMessage(certificateKey : endCertificateKey, validationId : validationId));

            // Assert
            Assert.Equal(expectedCertificateStatus, validation.Status);
            Assert.Equal(expectedCertificateStatus, endCertificate.Status);
            Assert.Equal(expectedStatusForSignatureAtIngestion, signatureAtIngestion.Status);
            Assert.Equal(expectedStatusForSignatureInGracePeriod, signatureInGracePeriod.Status);
            Assert.Equal(expectedStatusForSignatureAfterGracePeriod, signatureAfterGracePeriod.Status);

            _context.Verify(c => c.SaveChangesAsync(), Times.Once);
        }
Esempio n. 4
0
        public async Task ValidateTimestampingCertificate()
        {
            // Arrange
            var certificate = await _fixture.GetRevokedTimestampingCertificateAsync(RevocationTime);

            var endCertificateKey = 123;
            var validationId      = Guid.NewGuid();

            var packageSigningState = new PackageSigningState {
                SigningStatus = PackageSigningStatus.Valid
            };

            var signatureAtIngestion = new PackageSignature
            {
                Status = PackageSignatureStatus.Unknown,
                Type   = PackageSignatureType.Author,
            };
            var signatureInGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.InGracePeriod,
                Type   = PackageSignatureType.Author,
            };
            var signatureAfterGracePeriod = new PackageSignature
            {
                Status = PackageSignatureStatus.Valid,
                Type   = PackageSignatureType.Author,
            };

            var endCertificate = new EndCertificate
            {
                Key    = endCertificateKey,
                Status = EndCertificateStatus.Unknown,
                Use    = EndCertificateUse.Timestamping,
                CertificateChainLinks = new CertificateChainLink[0],
            };

            var trustedTimestamp = new TrustedTimestamp
            {
                EndCertificate = endCertificate,
                Status         = TrustedTimestampStatus.Valid
            };

            var validation = new EndCertificateValidation
            {
                EndCertificateKey = endCertificateKey,
                ValidationId      = validationId,
                Status            = null,
                EndCertificate    = endCertificate
            };

            signatureAtIngestion.PackageSigningState      = packageSigningState;
            signatureAtIngestion.TrustedTimestamps        = new[] { trustedTimestamp };
            signatureInGracePeriod.PackageSigningState    = packageSigningState;
            signatureInGracePeriod.TrustedTimestamps      = new[] { trustedTimestamp };
            signatureAfterGracePeriod.PackageSigningState = packageSigningState;
            signatureAfterGracePeriod.TrustedTimestamps   = new[] { trustedTimestamp };

            _context.Mock(
                packageSignatures: new[] { signatureAtIngestion, signatureInGracePeriod, signatureAfterGracePeriod },
                endCertificates: new[] { endCertificate },
                certificateValidations: new EndCertificateValidation[] { validation });

            _certificateStore.Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(certificate));

            // Act
            await _target.HandleAsync(new CertificateValidationMessage(certificateKey : endCertificateKey, validationId : validationId));

            // Assert
            Assert.Equal(EndCertificateStatus.Revoked, validation.Status);
            Assert.Equal(EndCertificateStatus.Revoked, endCertificate.Status);
            Assert.Equal(PackageSignatureStatus.Invalid, signatureAtIngestion.Status);
            Assert.Equal(PackageSignatureStatus.Invalid, signatureInGracePeriod.Status);
            Assert.Equal(PackageSignatureStatus.Invalid, signatureAfterGracePeriod.Status);

            _context.Verify(c => c.SaveChangesAsync(), Times.Once);
        }
            public async Task InvalidResultInvalidatesDependentSignatures()
            {
                // Arrange - Invalidate a certificate that is depended on by "signature1"'s certificate.
                // This should result in "signature1" being invalidated.
                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Invalid,
                    statusFlags: X509ChainStatusFlags.ExplicitDistrust);

                var signingState = new PackageSigningState {
                    SigningStatus = PackageSigningStatus.Valid
                };
                var signature1 = new PackageSignature
                {
                    Key    = 123,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var signature2 = new PackageSignature
                {
                    Key    = 456,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var timestamp = new TrustedTimestamp {
                    Value = DateTime.UtcNow
                };

                signingState.PackageSignatures  = new[] { signature1, signature2 };
                signature1.PackageSigningState  = signingState;
                signature2.PackageSigningState  = signingState;
                signature1.EndCertificate       = _certificate1;
                signature2.EndCertificate       = _certificate2;
                signature1.TrustedTimestamps    = new TrustedTimestamp[0];
                signature2.TrustedTimestamps    = new[] { timestamp };
                timestamp.PackageSignature      = signature2;
                timestamp.EndCertificate        = _certificate1;
                _certificate1.PackageSignatures = new[] { signature1 };
                _certificate1.TrustedTimestamps = new[] { timestamp };
                _certificate1.Use = EndCertificateUse.CodeSigning;

                _context.Mock(
                    packageSignatures: new[] { signature1, signature2 },
                    trustedTimestamps: new[] { timestamp });

                // Act
                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                Assert.True(result);

                Assert.Equal(EndCertificateStatus.Invalid, _certificateValidation1.Status);

                Assert.Equal(EndCertificateStatus.Invalid, _certificate1.Status);
                Assert.Equal(0, _certificate1.ValidationFailures);
                Assert.Null(_certificate1.RevocationTime);

                Assert.Equal(PackageSignatureStatus.Invalid, signature1.Status);
                Assert.Equal(PackageSignatureStatus.Valid, signature2.Status);

                Assert.Equal(PackageSigningStatus.Invalid, signingState.SigningStatus);

                // The package's signing state is "Valid", a MayBeInvalidated (warn) event should be raised.
                _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never);
                _telemetryService.Verify(a => a.TrackPackageSignatureMayBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Exactly(1));
                _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Exactly(0));
                _context.Verify(c => c.SaveChangesAsync(), Times.Once);
            }
            public async Task RevokedResultInvalidatesDependentSignatures()
            {
                // Arrange - "signature1" is a signature that uses the certificate before the revocation date,
                // "signature2" is a signature that uses the certificate after the revocation date, "signature3"
                // is a signature that doesn't depend on the certificate.
                var revocationTime = DateTime.UtcNow;

                var verificationResult = new CertificateVerificationResult(
                    status: EndCertificateStatus.Revoked,
                    statusFlags: X509ChainStatusFlags.Revoked,
                    revocationTime: revocationTime);

                var signingState = new PackageSigningState {
                    SigningStatus = PackageSigningStatus.Valid
                };
                var signature1 = new PackageSignature
                {
                    Key    = 12,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var signature2 = new PackageSignature
                {
                    Key    = 23,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var signature3 = new PackageSignature
                {
                    Key    = 34,
                    Status = PackageSignatureStatus.Valid,
                    Type   = PackageSignatureType.Author,
                };
                var timestamp1 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(-1), Status = TrustedTimestampStatus.Valid
                };
                var timestamp2 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(1), Status = TrustedTimestampStatus.Valid
                };
                var timestamp3 = new TrustedTimestamp {
                    Value = revocationTime.AddDays(-1), Status = TrustedTimestampStatus.Valid
                };

                signingState.PackageSignatures = new[] { signature1, signature2, signature3 };
                signature1.PackageSigningState = signingState;
                signature2.PackageSigningState = signingState;
                signature3.PackageSigningState = signingState;
                signature1.EndCertificate      = _certificate1;
                signature2.EndCertificate      = _certificate1;
                signature3.EndCertificate      = _certificate2;
                signature1.TrustedTimestamps   = new[] { timestamp1 };
                signature2.TrustedTimestamps   = new[] { timestamp2 };
                signature3.TrustedTimestamps   = new[] { timestamp3 };
                timestamp1.PackageSignature    = signature1;
                timestamp2.PackageSignature    = signature2;
                timestamp3.PackageSignature    = signature3;
                timestamp1.EndCertificate      = _certificate2;
                timestamp2.EndCertificate      = _certificate2;
                timestamp3.EndCertificate      = _certificate2;
                _certificate1.Use = EndCertificateUse.CodeSigning;
                _certificate2.Use = EndCertificateUse.Timestamping;
                _certificate1.PackageSignatures = new[] { signature1, signature2 };
                _certificate2.TrustedTimestamps = new[] { timestamp1, timestamp2, timestamp3 };

                _context.Mock(
                    packageSigningStates: new[] { signingState },
                    packageSignatures: new[] { signature1, signature2, signature3 },
                    trustedTimestamps: new[] { timestamp1, timestamp2, timestamp3 },
                    endCertificates: new[] { _certificate1, _certificate2 });

                var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult);

                Assert.True(result);

                Assert.Equal(EndCertificateStatus.Revoked, _certificateValidation1.Status);

                Assert.Equal(EndCertificateStatus.Revoked, _certificate1.Status);
                Assert.Equal(0, _certificate1.ValidationFailures);
                Assert.Equal(revocationTime, _certificate1.RevocationTime);

                Assert.Equal(PackageSignatureStatus.Valid, signature1.Status);
                Assert.Equal(PackageSignatureStatus.Invalid, signature2.Status);
                Assert.Equal(PackageSignatureStatus.Valid, signature3.Status);

                Assert.Equal(PackageSigningStatus.Invalid, signingState.SigningStatus);

                _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never);
                _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Exactly(1));
                _context.Verify(c => c.SaveChangesAsync(), Times.Once);
            }