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."); } } }
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); }
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); }