public void InvalidCertificateInvalidatesSignatures( EndCertificateUse use, X509ChainStatusFlags flags, SignatureDecision ingestionDecision, SignatureDecision gracePeriodDecision, SignatureDecision afterGracePeriodDecision) { // Arrange var certificate = new EndCertificate { Use = use }; var result = new CertificateVerificationResult( status: EndCertificateStatus.Invalid, statusFlags: flags); var signatureAtIngestion = new PackageSignature { Status = PackageSignatureStatus.Unknown }; var signatureAtGracePeriod = new PackageSignature { Status = PackageSignatureStatus.InGracePeriod }; var signatureAfterGracePeriod = new PackageSignature { Status = PackageSignatureStatus.Valid }; // Act & Assert var decider = _target.MakeDeciderForInvalidatedCertificate(certificate, result); Assert.Equal(ingestionDecision, decider(signatureAtIngestion)); Assert.Equal(gracePeriodDecision, decider(signatureAtGracePeriod)); Assert.Equal(afterGracePeriodDecision, decider(signatureAfterGracePeriod)); }
public async Task MessageIsConsumedIfValidationEndsGracefully(CertificateVerificationResult result) { // Arrange _certificateValidationService .Setup(s => s.FindCertificateValidationAsync(It.IsAny <CertificateValidationMessage>())) .ReturnsAsync(new EndCertificateValidation { Status = null, EndCertificate = new EndCertificate { Status = EndCertificateStatus.Unknown, Use = EndCertificateUse.CodeSigning, CertificateChainLinks = new CertificateChainLink[0], } }); _certificateStore .Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new X509Certificate2()); _certificateVerifier .Setup(v => v.VerifyCodeSigningCertificate(It.IsAny <X509Certificate2>(), It.IsAny <X509Certificate2[]>())) .Returns(result); _certificateValidationService .Setup(s => s.TrySaveResultAsync(It.IsAny <EndCertificateValidation>(), It.IsAny <CertificateVerificationResult>())) .ReturnsAsync(true); // Act & Assert Assert.True(await _target.HandleAsync(_message)); _certificateValidationService .Verify(s => s.TrySaveResultAsync(It.IsAny <EndCertificateValidation>(), It.IsAny <CertificateVerificationResult>()), Times.Once); }
public async Task UnknownResultUpdatesCertificateValidation() { // Arrange - Create a signature whose certificate and trusted timestamp depends on "_certificateValidation1". var verificationResult = new CertificateVerificationResult( status: EndCertificateStatus.Unknown, statusFlags: X509ChainStatusFlags.RevocationStatusUnknown); var signature = new PackageSignature { Status = PackageSignatureStatus.Valid, Type = PackageSignatureType.Author, }; var timestamp = new TrustedTimestamp { Value = DateTime.UtcNow }; signature.EndCertificate = _certificate1; signature.TrustedTimestamps = new[] { timestamp }; _certificate1.PackageSignatures = new[] { signature }; _certificate1.TrustedTimestamps = new[] { timestamp }; // Act & Assert - the first Unknown result shouldn't cause any issues. var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult); Assert.True(result); Assert.Null(_certificateValidation1.Status); Assert.Equal(EndCertificateStatus.Unknown, _certificateValidation1.EndCertificate.Status); Assert.Equal(4, _certificateValidation1.EndCertificate.ValidationFailures); Assert.Null(_certificateValidation1.EndCertificate.RevocationTime); _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never); _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Never); _context.Verify(c => c.SaveChangesAsync(), Times.Once); }
public void RevokedCodeSigningCertificateWithoutRevocationDateInvalidatesAllSignatures() { var certificate = new EndCertificate { Use = EndCertificateUse.CodeSigning }; var result = new CertificateVerificationResult( status: EndCertificateStatus.Revoked, statusFlags: X509ChainStatusFlags.Revoked, revocationTime: null); var signatureAtIngestion = new PackageSignature { Status = PackageSignatureStatus.Unknown }; var signatureAtGracePeriod = new PackageSignature { Status = PackageSignatureStatus.InGracePeriod }; var signatureAfterGracePeriod = new PackageSignature { Status = PackageSignatureStatus.Valid }; // Act & Assert var decider = _target.MakeDeciderForRevokedCertificate(certificate, result); Assert.Equal(SignatureDecision.Reject, decider(signatureAtIngestion)); Assert.Equal(SignatureDecision.Reject, decider(signatureAtGracePeriod)); Assert.Equal(SignatureDecision.Reject, decider(signatureAfterGracePeriod)); }
public void RevokedTimestampingCertificateInvalidatesSignatures(bool nullRevocationTime) { // Arrange - only signatures at ingestion should be rejected, all other signatures should // raise a warning. The revocation time should not matter. var revocationTime = nullRevocationTime ? (DateTime?)null : DateTime.Now; var certificate = new EndCertificate { Use = EndCertificateUse.Timestamping }; 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 }; // Act & Assert var decider = _target.MakeDeciderForRevokedCertificate(certificate, result); Assert.Equal(SignatureDecision.Reject, decider(signatureAtIngestion)); Assert.Equal(SignatureDecision.Warn, decider(signatureAtGracePeriod)); Assert.Equal(SignatureDecision.Warn, decider(signatureAfterGracePeriod)); }
public async Task RevokedResultDoesNotInvalidateDependentNonAuthorSignaturesSignatures(PackageSignatureType type) { // Arrange var revocationTime = DateTime.UtcNow; var verificationResult = new CertificateVerificationResult( status: EndCertificateStatus.Revoked, statusFlags: X509ChainStatusFlags.Revoked, revocationTime: revocationTime); var signingState = new PackageSigningState { SigningStatus = PackageSigningStatus.Valid }; var signature2 = new PackageSignature { Key = 12, Status = PackageSignatureStatus.Valid, Type = type }; var timestamp2 = new TrustedTimestamp { Value = revocationTime.AddDays(1), Status = TrustedTimestampStatus.Valid }; signingState.PackageSignatures = new[] { signature2 }; signature2.PackageSigningState = signingState; signature2.EndCertificate = _certificate1; signature2.TrustedTimestamps = new[] { timestamp2 }; timestamp2.PackageSignature = signature2; timestamp2.EndCertificate = _certificate2; _certificate1.Use = EndCertificateUse.CodeSigning; _certificate2.Use = EndCertificateUse.Timestamping; _certificate1.PackageSignatures = new[] { signature2 }; _certificate2.TrustedTimestamps = new[] { timestamp2 }; _context.Mock( packageSigningStates: new[] { signingState }, packageSignatures: new[] { signature2 }, trustedTimestamps: new[] { timestamp2 }, 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, signature2.Status); Assert.Equal(PackageSigningStatus.Valid, signingState.SigningStatus); _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never); _telemetryService.Verify(a => a.TrackPackageSignatureShouldBeInvalidatedEvent(It.IsAny <PackageSignature>()), Times.Never); _telemetryService.Verify(a => a.TrackUnableToValidateCertificateEvent(It.IsAny <EndCertificate>()), Times.Never); _context.Verify(c => c.SaveChangesAsync(), Times.Once); }
private async Task <bool> HandleUnknownResultAsync(int validationFailuresStart) { // Arrange // Return an "Unknown" status for the certificate's verification. The validation service should increment the number // of failures for the validation's certificate. var certificateValidation = new EndCertificateValidation { Status = null, EndCertificate = new EndCertificate { Status = EndCertificateStatus.Unknown, Use = EndCertificateUse.CodeSigning, ValidationFailures = validationFailuresStart, CertificateChainLinks = new CertificateChainLink[0], } }; var certificateVerificationResult = new CertificateVerificationResult( status: EndCertificateStatus.Unknown, statusFlags: X509ChainStatusFlags.RevocationStatusUnknown); _certificateValidationService .Setup(s => s.FindCertificateValidationAsync(It.IsAny <CertificateValidationMessage>())) .ReturnsAsync(certificateValidation); _certificateStore .Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new X509Certificate2()); _certificateVerifier .Setup(v => v.VerifyCodeSigningCertificate(It.IsAny <X509Certificate2>(), It.IsAny <X509Certificate2[]>())) .Returns(certificateVerificationResult); _certificateValidationService .Setup( s => s.TrySaveResultAsync( It.IsAny <EndCertificateValidation>(), It.Is <CertificateVerificationResult>(r => r.Status == EndCertificateStatus.Unknown))) .Callback <EndCertificateValidation, CertificateVerificationResult>((v, r) => v.EndCertificate.ValidationFailures++) .ReturnsAsync(true); // Act & Assert var result = await _target.HandleAsync(_message); Assert.Equal(validationFailuresStart + 1, certificateValidation.EndCertificate.ValidationFailures); _certificateValidationService .Verify( s => s.TrySaveResultAsync( It.IsAny <EndCertificateValidation>(), It.IsAny <CertificateVerificationResult>()), Times.Once); return(result); }
public void RevokedCodeSigningCertificateRejectsAllSignaturesIfTimestampIsAlreadyInvalid() { var certificate = new EndCertificate { Use = EndCertificateUse.CodeSigning }; var result = new CertificateVerificationResult( status: EndCertificateStatus.Revoked, statusFlags: X509ChainStatusFlags.Revoked, revocationTime: DateTime.UtcNow); var signatureAtIngestion = new PackageSignature { Status = PackageSignatureStatus.Unknown, TrustedTimestamps = new TrustedTimestamp[] { new TrustedTimestamp { Status = TrustedTimestampStatus.Invalid } } }; var signatureAtGracePeriod = new PackageSignature { Status = PackageSignatureStatus.InGracePeriod, TrustedTimestamps = new TrustedTimestamp[] { new TrustedTimestamp { Status = TrustedTimestampStatus.Invalid } } }; var signatureAfterGracePeriod = new PackageSignature { Status = PackageSignatureStatus.Valid, TrustedTimestamps = new TrustedTimestamp[] { new TrustedTimestamp { Status = TrustedTimestampStatus.Invalid } } }; // Act & Assert var decider = _target.MakeDeciderForRevokedCertificate(certificate, result); Assert.Equal(SignatureDecision.Reject, decider(signatureAtIngestion)); Assert.Equal(SignatureDecision.Reject, decider(signatureAtGracePeriod)); Assert.Equal(SignatureDecision.Reject, decider(signatureAfterGracePeriod)); }
public void RevokedCodeSigningCertificateThrowsIfThereIsARevocationDateAndMultipleTrustedTimestamps() { var certificate = new EndCertificate { Use = EndCertificateUse.CodeSigning }; var result = new CertificateVerificationResult( status: EndCertificateStatus.Revoked, statusFlags: X509ChainStatusFlags.Revoked, revocationTime: DateTime.UtcNow); var signatureAtIngestion = new PackageSignature { Status = PackageSignatureStatus.Unknown, TrustedTimestamps = new TrustedTimestamp[] { new TrustedTimestamp(), new TrustedTimestamp(), } }; var signatureAtGracePeriod = new PackageSignature { Status = PackageSignatureStatus.InGracePeriod, TrustedTimestamps = new TrustedTimestamp[] { new TrustedTimestamp(), new TrustedTimestamp(), } }; var signatureAfterGracePeriod = new PackageSignature { Status = PackageSignatureStatus.Valid, TrustedTimestamps = new TrustedTimestamp[] { new TrustedTimestamp(), new TrustedTimestamp(), } }; // Act & Assert var decider = _target.MakeDeciderForRevokedCertificate(certificate, result); Assert.Throws <InvalidOperationException>(() => decider(signatureAtIngestion)); Assert.Throws <InvalidOperationException>(() => decider(signatureAtGracePeriod)); Assert.Throws <InvalidOperationException>(() => decider(signatureAfterGracePeriod)); }
public async Task GoodResultUpdatesCertificateValidation() { // Arrange var verificationResult = new CertificateVerificationResult( status: EndCertificateStatus.Good, statusFlags: X509ChainStatusFlags.NoError); // Act & Assert var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult); Assert.True(result); Assert.Equal(EndCertificateStatus.Good, _certificateValidation1.Status); Assert.Equal(EndCertificateStatus.Good, _certificateValidation1.EndCertificate.Status); Assert.Equal(0, _certificateValidation1.EndCertificate.ValidationFailures); Assert.Null(_certificateValidation1.EndCertificate.RevocationTime); }
public async Task DoesNotSendCheckValidatorIfFeatureFlagIsDisabled() { // Arrange var result = new CertificateVerificationResult( status: EndCertificateStatus.Good, statusFlags: X509ChainStatusFlags.NoError); _message = new CertificateValidationMessage( CertificateKey, ValidationId, revalidateRevokedCertificate: false, sendCheckValidator: true); _certificateValidationService .Setup(s => s.FindCertificateValidationAsync(It.IsAny <CertificateValidationMessage>())) .ReturnsAsync(new EndCertificateValidation { Status = null, EndCertificate = new EndCertificate { Status = EndCertificateStatus.Unknown, Use = EndCertificateUse.CodeSigning, CertificateChainLinks = new CertificateChainLink[0], } }); _featureFlagService.Setup(x => x.IsQueueBackEnabled()).Returns(false); _certificateStore .Setup(s => s.LoadAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new X509Certificate2()); _certificateVerifier .Setup(v => v.VerifyCodeSigningCertificate(It.IsAny <X509Certificate2>(), It.IsAny <X509Certificate2[]>())) .Returns(result); _certificateValidationService .Setup(s => s.TrySaveResultAsync(It.IsAny <EndCertificateValidation>(), It.IsAny <CertificateVerificationResult>())) .ReturnsAsync(true); // Act & Assert Assert.True(await _target.HandleAsync(_message)); _certificateValidationService .Verify(s => s.TrySaveResultAsync(It.IsAny <EndCertificateValidation>(), It.IsAny <CertificateVerificationResult>()), Times.Once); _validationEnqueuer.Verify( x => x.SendMessageAsync(It.IsAny <PackageValidationMessageData>()), Times.Never); }
public async Task RevokedResultInvalidatesDependentTimestamps() { // Arrange - "signature1" is a signature that whose timestamp depends on the certificate that will be revoked. var verificationResult = new CertificateVerificationResult( status: EndCertificateStatus.Revoked, statusFlags: X509ChainStatusFlags.Revoked, revocationTime: DateTime.UtcNow); var signingState = new PackageSigningState { SigningStatus = PackageSigningStatus.Valid }; var signature1 = new PackageSignature { Key = 12, Status = PackageSignatureStatus.Valid, Type = PackageSignatureType.Author, }; var timestamp1 = new TrustedTimestamp { Value = DateTime.UtcNow, Status = TrustedTimestampStatus.Valid }; signingState.PackageSignatures = new[] { signature1 }; signature1.PackageSigningState = signingState; signature1.EndCertificate = _certificate1; signature1.TrustedTimestamps = new[] { timestamp1 }; timestamp1.PackageSignature = signature1; timestamp1.EndCertificate = _certificate1; _certificate1.Use = EndCertificateUse.Timestamping; _certificate1.PackageSignatures = new[] { signature1 }; _context.Mock( packageSigningStates: new[] { signingState }, packageSignatures: new[] { signature1 }, trustedTimestamps: new[] { timestamp1 }, endCertificates: new[] { _certificate1 }); var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult); Assert.True(result); Assert.Equal(EndCertificateStatus.Revoked, _certificateValidation1.Status); Assert.Equal(TrustedTimestampStatus.Invalid, timestamp1.Status); Assert.Equal(EndCertificateStatus.Revoked, _certificate1.Status); Assert.Equal(PackageSignatureStatus.Invalid, signature1.Status); Assert.Equal(PackageSigningStatus.Invalid, signingState.SigningStatus); }
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)); }
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 ProcessesSignaturesInBatchesOf500() { // Arrange - Invalidate a certificate that is depended on by 501 signatures. // This should invalidate all signatures in batches of 500 signatures. var verificationResult = new CertificateVerificationResult( status: EndCertificateStatus.Invalid, statusFlags: X509ChainStatusFlags.ExplicitDistrust); var signatures = new List <PackageSignature>(); for (var i = 0; i < 501; i++) { var state = new PackageSigningState { SigningStatus = PackageSigningStatus.Valid }; var signature = new PackageSignature { Key = i, Status = PackageSignatureStatus.Valid, Type = PackageSignatureType.Author }; state.PackageSignatures = new[] { signature }; signature.PackageSigningState = state; signature.EndCertificate = _certificate1; signature.TrustedTimestamps = new TrustedTimestamp[0]; signatures.Add(signature); } _certificate1.PackageSignatures = signatures; _certificate1.TrustedTimestamps = new TrustedTimestamp[0]; _certificate1.Use = EndCertificateUse.CodeSigning; _context.Mock(packageSignatures: signatures); var hasSaved = false; var invalidationsBeforeSave = 0; var invalidationsAfterSave = 0; _context.Setup(c => c.SaveChangesAsync()) .Returns(Task.FromResult(0)) .Callback(() => hasSaved = true); _telemetryService .Setup(t => t.TrackPackageSignatureMayBeInvalidatedEvent(It.IsAny <PackageSignature>())) .Callback((PackageSignature s) => { if (!hasSaved) { invalidationsBeforeSave++; } else { invalidationsAfterSave++; } }); // Act var result = await _target.TrySaveResultAsync(_certificateValidation1, verificationResult); // Assert - two batches should be saved. The first batch should invalidate 500 signatures, // the second batch should invalidate 1 signature. _context.Verify(c => c.SaveChangesAsync(), Times.Exactly(2)); Assert.Equal(500, invalidationsBeforeSave); Assert.Equal(1, invalidationsAfterSave); }
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); }