public async Task EnqueueVerificationAsync(IValidationRequest request, EndCertificate certificate) { var message = new CertificateValidationMessage(certificate.Key, request.ValidationId); var brokeredMessage = _serializer.Serialize(message); await _topicClient.SendAsync(brokeredMessage); }
private bool HasOwnerWithInvalidUsername(IValidationRequest request) { var registration = _packages.FindPackageRegistrationById(request.PackageId); if (registration == null) { _logger.LogError("Attempted to validate package that has no package registration"); throw new InvalidOperationException($"Registration for package id {request.PackageId} does not exist"); } var owners = registration.Owners.Select(o => o.Username).ToList(); if (owners.Any(UsernameHelper.IsInvalid)) { _logger.LogWarning( "Package {PackageId} {PackageVersion} has an owner with an invalid username. {Owners}", request.PackageId, request.PackageVersion, owners); return(true); } return(false); }
public async Task <ValidatorStatus> TryAddValidatorStatusAsync(IValidationRequest request, ValidatorStatus status, ValidationStatus desiredState) { status.State = desiredState; var result = await AddStatusAsync(status); if (result == AddStatusResult.StatusAlreadyExists) { // The add operation fails if another instance of this service has already created the status. // This may happen due to repeated operations kicked off by the Orchestrator. Return the result from // the other add operation. _logger.LogWarning( Error.ValidatorStateServiceFailedToAddStatus, "Failed to add validation status for {ValidationId} ({PackageId} {PackageVersion}) as a record already exists", request.PackageId, request.PackageVersion); return(await GetStatusAsync(request)); } else if (result != AddStatusResult.Success) { throw new NotSupportedException($"Unknown {nameof(AddStatusResult)}: {result}"); } return(status); }
public async Task <ValidationStatus> GetStatusAsync(IValidationRequest request) { if (ShouldSkip(request)) { return(ValidationStatus.Succeeded); } var audit = await _validationAuditor.ReadAuditAsync( request.ValidationId, NormalizePackageId(request.PackageId), NormalizePackageVersion(request.PackageVersion)); if (audit == null) { return(ValidationStatus.NotStarted); } var validationStatusList = audit .Entries .Where(x => x.ValidatorName == ValidatorName) .Select(x => GetValidationStatus(request, x.EventId)) .ToList(); return(validationStatusList.FirstOrDefault(x => x == ValidationStatus.Failed) ?? validationStatusList.FirstOrDefault(x => x == ValidationStatus.Succeeded) ?? ValidationStatus.Incomplete); }
public async Task <ValidatorStatus> TryUpdateValidationStatusAsync(IValidationRequest request, ValidatorStatus validatorStatus, ValidationStatus desiredState) { validatorStatus.State = desiredState; var result = await SaveStatusAsync(validatorStatus); if (result == SaveStatusResult.StaleStatus) { // The save operation fails if another instance of this service has already modified the status. // This may happen due to repeated operations kicked off by the Orchestrator. Return the result // from the other update. _logger.LogWarning( Error.ValidatorStateServiceFailedToUpdateStatus, "Failed to save validation status for {ValidationId} ({PackageId} {PackageVersion}) as the current status is stale", request.PackageId, request.PackageVersion); return(await GetStatusAsync(request)); } else if (result != SaveStatusResult.Success) { throw new NotSupportedException($"Unknown {nameof(SaveStatusResult)}: {result}"); } return(validatorStatus); }
public async Task <IValidationResult> StartAsync(IValidationRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var validatorStatus = await _validatorStateService.GetStatusAsync(request); if (validatorStatus.State != ValidationStatus.NotStarted) { _logger.LogWarning( "Scan only validation with validation Id {ValidationId} ({PackageId} {PackageVersion}) has already started.", request.ValidationId, request.PackageId, request.PackageVersion); return(validatorStatus.ToValidationResult()); } if (ShouldSkipScan(request)) { return(ValidationResult.Succeeded); } await _scanAndSignEnqueuer.EnqueueScanAsync(request.ValidationId, request.NupkgUrl); var result = await _validatorStateService.TryAddValidatorStatusAsync(request, validatorStatus, ValidationStatus.Incomplete); return(result.ToValidationResult()); }
public async Task <ValidatorStatus> GetStatusAsync(IValidationRequest request) { var status = await GetStatusAsync(request.ValidationId); if (status == null) { return(new ValidatorStatus { ValidationId = request.ValidationId, PackageKey = request.PackageKey, ValidatorName = _validatorName, State = ValidationStatus.NotStarted, ValidatorIssues = new List <ValidatorIssue>(), }); } else if (status.PackageKey != request.PackageKey) { throw new ArgumentException( $"Validation expected package key {status.PackageKey}, actual {request.PackageKey}", nameof(request)); } else if (status.ValidatorName != _validatorName) { throw new ArgumentException( $"Validation expected validator {status.ValidatorName}, actual {_validatorName}", nameof(request)); } return(status); }
public async Task <ValidatorStatus> GetStatusAsync(IValidationRequest request) { var status = await _validationContext .ValidatorStatuses .Where(s => s.ValidationId == request.ValidationId) .FirstOrDefaultAsync(); if (status == null) { return(new ValidatorStatus { ValidationId = request.ValidationId, PackageKey = request.PackageKey, ValidatorName = _validatorName, State = ValidationStatus.NotStarted, }); } else if (status.PackageKey != request.PackageKey) { throw new ArgumentException( $"Validation expected package key {status.PackageKey}, actual {request.PackageKey}", nameof(request)); } else if (status.ValidatorName != _validatorName) { throw new ArgumentException( $"Validation expected validator {status.ValidatorName}, actual {_validatorName}", nameof(request)); } return(status); }
/// <summary> /// Kicks off the package verification process for the given request. Verification will begin when the /// <see cref="ValidationEntitiesContext"/> has a <see cref="ValidatorStatus"/> that matches the /// <see cref="IValidationRequest"/>'s validationId. Once verification completes, the <see cref="ValidatorStatus"/>'s /// State will be updated to "Succeeded" or "Failed". /// </summary> /// <param name="request">The request that details the package to be verified.</param> /// <returns>A task that will complete when the verification process has been queued.</returns> public Task EnqueueVerificationAsync(IValidationRequest request) { var brokeredMessage = _signatureValidationSerializer.Serialize( new SignatureValidationMessage(request.PackageId, request.PackageVersion, new Uri(request.NupkgUrl), request.ValidationId)); return(_topicClient.SendAsync(brokeredMessage)); }
public ScanAndSignEnqueuerFactsBase() { _topicClientMock = new Mock <ITopicClient>(); _serializerMock = new Mock <IBrokeredMessageSerializer <ScanAndSignMessage> >(); _logger = Mock.Of <ILogger <ScanAndSignEnqueuer> >(); _configurationAccessorMock = new Mock <IOptionsSnapshot <ScanAndSignEnqueuerConfiguration> >(); _configuration = new ScanAndSignEnqueuerConfiguration(); _configurationAccessorMock .SetupGet(ca => ca.Value) .Returns(_configuration); _target = new ScanAndSignEnqueuer( _topicClientMock.Object, _serializerMock.Object, _configurationAccessorMock.Object, _logger); _validationRequest = new ValidationRequest(Guid.NewGuid(), 42, "somepackage", "someversion", "https://example.com/testpackage.nupkg"); _owners = new List <string> { "Billy", "Bob" }; _serializedMessage = new BrokeredMessageWrapper("somedata"); _serializerMock .Setup(s => s.Serialize(It.IsAny <ScanAndSignMessage>())) .Callback <ScanAndSignMessage>(m => _capturedMessage = m) .Returns(_serializedMessage); _topicClientMock .Setup(tc => tc.SendAsync(It.IsAny <IBrokeredMessage>())) .Callback <IBrokeredMessage>(m => _capturedBrokeredMessage = m) .Returns(Task.CompletedTask); }
/// <summary> /// The pattern used for the StartAsync: /// 1. Check if a validation was already started /// 2. Only if a validation was not started queue the message to be processed. /// 3. After the message is queued, update the ValidatorStatus for the <paramref name="request"/>. /// </summary> /// <param name="request">The request to be send to the validator job queue.</param> /// <returns>The validation status.</returns> public async Task <IValidationResult> StartAsync(IValidationRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var validatorStatus = await _validatorStateService.GetStatusAsync(request); // See issue https://github.com/NuGet/NuGetGallery/issues/6249 validatorStatus.ValidatingType = ValidatingType.SymbolPackage; if (validatorStatus.State != ValidationStatus.NotStarted) { _logger.LogWarning( "Symbol validation for {PackageId} {PackageNormalizedVersion} has already started.", request.PackageId, request.PackageVersion); return(validatorStatus.ToValidationResult()); } // Due to race conditions or failure of method TryAddValidatorStatusAsync the same message can be enqueued multiple times // Log this information to postmortem evaluate this behavior _telemetryService.TrackSymbolsMessageEnqueued(ValidatorName.SymbolsValidator, request.ValidationId); await _symbolMessageEnqueuer.EnqueueSymbolsValidationMessageAsync(request); var result = await _validatorStateService.TryAddValidatorStatusAsync(request, validatorStatus, ValidationStatus.Incomplete); return(result.ToValidationResult()); }
public async Task CleanUpAsync(IValidationRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var validatorStatus = await _validatorStateService.GetStatusAsync(request); if (validatorStatus.NupkgUrl == null) { return; } if (!_configuration.RepositorySigningEnabled) { _logger.LogWarning( "Skipping cleanup of .nupkg for validation ID {ValidationId} ({PackageId} {PackageVersion})", request.ValidationId, request.PackageId, request.PackageVersion); return; } _logger.LogInformation( "Cleaning up the .nupkg URL for validation ID {ValidationId} ({PackageId} {PackageVersion}).", request.ValidationId, request.PackageId, request.PackageVersion); var blob = _blobProvider.GetBlobFromUrl(validatorStatus.NupkgUrl); await blob.DeleteIfExistsAsync(); }
private async Task <bool> ShouldRepositorySignAsync(IValidationRequest request, List <string> owners) { var hasRepositorySignature = await _validationContext .PackageSignatures .Where(s => s.PackageKey == request.PackageKey) .Where(s => s.Type == PackageSignatureType.Repository) .AnyAsync(); if (hasRepositorySignature) { _logger.LogInformation( "Package {PackageId} {PackageVersion} already has a repository signature. Scanning instead of signing package", request.PackageId, request.PackageVersion); return(false); } // TODO: Remove this check. // See: https://github.com/NuGet/Engineering/issues/1582 if (owners.Any(UsernameHelper.IsInvalid)) { _logger.LogWarning( "Package {PackageId} {PackageVersion} has an owner with an invalid username. Scanning instead of signing. {Owners}", request.PackageId, request.PackageVersion, owners); return(false); } return(true); }
private async Task <ValidatorStatus> StartInternalAsync(IValidationRequest request) { // Check that this is the first validation for this specific request. var validatorStatus = await _validatorStateService.GetStatusAsync(request); if (validatorStatus.State != ValidationStatus.NotStarted) { _logger.LogWarning( "Package Signing validation with validationId {ValidationId} ({PackageId} {PackageVersion}) has already started.", request.ValidationId, request.PackageId, request.PackageVersion); return(validatorStatus); } // Kick off the verification process. Note that the jobs will not verify the package until the // state of this validator has been persisted to the database. var stopwatch = Stopwatch.StartNew(); await _signatureVerificationEnqueuer.EnqueueVerificationAsync(request); var result = await _validatorStateService.TryAddValidatorStatusAsync(request, validatorStatus, ValidationStatus.Incomplete); _telemetryService.TrackDurationToStartPackageSigningValidator(stopwatch.Elapsed); return(result); }
public async Task UsesProperNupkgUrl(bool existsInPublicContainer, bool existsInValidationContainer, string expectedUrlSubstring) { UseDefaultValidatorProvider(); var validator = AddValidation("validation1", TimeSpan.FromDays(1)); PackageFileServiceMock .Setup(pfs => pfs.DoesPackageFileExistAsync(Package)) .ReturnsAsync(existsInPublicContainer); PackageFileServiceMock .Setup(pfs => pfs.DoesValidationPackageFileExistAsync(Package)) .ReturnsAsync(existsInValidationContainer); IValidationRequest validationRequest = null; validator .Setup(v => v.GetStatusAsync(It.IsAny <IValidationRequest>())) .ReturnsAsync(ValidationStatus.NotStarted) .Callback <IValidationRequest>(vr => validationRequest = vr); var processor = CreateProcessor(); await processor.ProcessValidationsAsync(ValidationSet, Package); validator .Verify(v => v.GetStatusAsync(It.IsAny <IValidationRequest>()), Times.AtLeastOnce()); Assert.NotNull(validationRequest); Assert.Contains(expectedUrlSubstring, validationRequest.NupkgUrl); Assert.Equal(Package.PackageRegistration.Id, validationRequest.PackageId); Assert.Equal(Package.NormalizedVersion, validationRequest.PackageVersion); }
/// <summary> /// Find the state of a package's signing. /// </summary> /// <param name="request">The validation request containing the package whose signing state should be fetched.</param> /// <returns>The package's signing state.</returns> private Task <PackageSigningState> FindPackageSigningStateAsync(IValidationRequest request) { return(_validationContext .PackageSigningStates .Where(p => p.PackageKey == request.PackageKey) .FirstAsync()); }
private async Task <ValidatorStatus> GetStatusAsync(IValidationRequest request) { // Look up this validator's state in the database. var status = await _validatorStateService.GetStatusAsync(request); if (status.State != ValidationStatus.Incomplete) { return(status); } // Wait until ALL certificate validations kicked off by this validation request have finished. if (!await AllCertificateValidationsAreFinishedAsync(request)) { // We know this status is incomplete. return(status); } // All of the requested certificate validations have finished. At this point, the signature // may have a status of "Unknown" if the package is at ingestion and its signature has passed // all validations, "Invalid" if one or more of the signature's certificates has failed validations, // or "InGracePeriod" or "Valid" if this is a revalidation request. var signature = await FindAuthorSignatureAsync(request); if (signature == null) { _logger.LogError( "Could not find author signature for {PackageKey} {PackageId} {PackageVersion} {ValidationId}", request.PackageKey, request.PackageId, request.PackageVersion, request.ValidationId); throw new InvalidOperationException($"Package with key {request.PackageKey} does not have an author signature"); } if (signature.Status == PackageSignatureStatus.Invalid) { _logger.LogWarning( "Failing validation {ValidationId} ({PackageId} {PackageVersion}) due to invalidated signature: {SignatureKey}", request.ValidationId, request.PackageId, request.PackageVersion, signature.Key); return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Failed)); } else { _logger.LogInformation( "Successful validation {ValidationId} ({PackageId} {PackageVersion})", request.ValidationId, request.PackageId, request.PackageVersion); PromoteSignature(request, signature); return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Succeeded)); } }
/// <summary> /// Check whether all certificate validations for the given validation request are finished. /// </summary> /// <param name="request">The validation request that started the certificate validations.</param> /// <returns>Whether the certificate validations are ALL finished.</returns> private Task <bool> AllCertificateValidationsAreFinishedAsync(IValidationRequest request) { // Incomplete CertificateValidation have a Status of NULL. return(_validationContext .CertificateValidations .Where(v => v.ValidationId == request.ValidationId) .AllAsync(v => v.Status.HasValue)); }
private IValidationResult Validate(IValidationRequest request, IValidationResult result) { /// The package signature validator runs after the <see cref="PackageSignatureProcessor" />. /// All signature validation issues should be caught and handled by the processor. if (result.Status == ValidationStatus.Failed || result.NupkgUrl != null) { if (!_config.RepositorySigningEnabled) { _logger.LogInformation( "Ignoring invalid validation result in package signature validator as repository signing is disabled. " + "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}", result.Status, result.NupkgUrl, result.Issues.Select(i => i.IssueCode)); return(ValidationResult.Succeeded); } // TODO: Remove this. // See: https://github.com/NuGet/Engineering/issues/1592 if (HasOwnerWithInvalidUsername(request)) { _logger.LogWarning( "Ignoring invalid validation result in package signature validator as the package has an owner with an invalid username. " + "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}", result.Status, result.NupkgUrl, result.Issues.Select(i => i.IssueCode)); return(ValidationResult.Succeeded); } _logger.LogCritical( "Unexpected validation result in package signature validator. This may be caused by an invalid repository " + "signature. Throwing an exception to force this validation to dead-letter. " + "Status = {ValidationStatus}, Nupkg URL = {NupkgUrl}, validation issues = {Issues}", result.Status, result.NupkgUrl, result.Issues.Select(i => i.IssueCode)); throw new InvalidOperationException("Package signature validator has an unexpected validation result"); } /// Suppress all validation issues. The <see cref="PackageSignatureProcessor"/> should /// have already reported any issues related to the author signature. Customers should /// not be notified of validation issues due to the repository signature. if (result.Issues.Count != 0) { _logger.LogWarning( "Ignoring {ValidationIssueCount} validation issues from result. Issues: {Issues}", result.Issues.Count, result.Issues.Select(i => i.IssueCode)); return(new ValidationResult(result.Status)); } return(result); }
/// <summary> /// Find all of the signatures and their certificates for the given validation request's package. /// </summary> /// <param name="request">The validation request containing the package whose signatures should be fetched.</param> /// <returns>The package's signatures with their certificates.</returns> private Task <List <PackageSignature> > FindSignaturesAsync(IValidationRequest request) { return(_validationContext .PackageSignatures .Where(s => s.PackageKey == request.PackageKey) .Include(s => s.TrustedTimestamps) .Include(s => s.EndCertificate) .ToListAsync()); }
public ValidationHandler( IValidationRequest request, ValidationTypes validationType, IHandler handler) { this.request = request; this.next = handler; this.validationType = validationType; }
/// <summary> /// Find all of the signatures and their certificates for the given validation request's package. /// </summary> /// <param name="request">The validation request containing the package whose signatures should be fetched.</param> /// <returns>The package's signatures with their certificates.</returns> private Task <PackageSignature> FindSignatureAsync(IValidationRequest request) { return(_validationContext .PackageSignatures .Include(s => s.EndCertificate) .Include(s => s.TrustedTimestamps.Select(t => t.EndCertificate)) .Where(s => s.Type == PackageSignatureType.Author) .SingleAsync(s => s.PackageKey == request.PackageKey)); }
public SecurityValidationHandler( IValidationRequest request, IValidation validation, IHandler handler) { this.request = request; this.next = handler; this.validation = validation; }
public async Task <ValidationStatus> GetStatusAsync(IValidationRequest request) { // Look up this validator's state in the database. var status = await _validatorStateService.GetStatusAsync(request); if (status.State != ValidationStatus.Incomplete) { return(status.State); } // Wait until ALL certificate validations kicked off by this validation request have finished. if (!await AllCertificateValidationsAreFinishedAsync(request)) { return(ValidationStatus.Incomplete); } // All of the requested certificate validations have finished. Fail the validation if any // signatures have been invalidated. var signatures = await FindSignaturesAsync(request); foreach (var signature in signatures) { // Signatures at this point MUST have a state of either "Unknown" or "Invalid" at this point as the // PackageSigningValidator will set all signatures to an "Unknown" status, and the ValidateCertificate // job may set signatures to the "Invalid" state. if (signature.Status == PackageSignatureStatus.Invalid) { _logger.LogWarning( "Failing validation {ValidationId} ({PackageId} {PackageVersion}) due to invalidated signature: {SignatureKey}", request.ValidationId, request.PackageId, request.PackageVersion, signature.Key); return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Failed)); } if (signature.Status != PackageSignatureStatus.Unknown) { _logger.LogError( Error.PackageCertificateValidationInvalidSignatureState, "Failing validation {ValidationId} ({PackageId} {PackageVersion}) due to invalid signature status: {SignatureStatus}", request.ValidationId, request.PackageId, request.PackageVersion, signature.Status); return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Failed)); } } // All signatures are valid. Promote signatures out of the "Unknown" state to either "Valid" or "InGracePeriod". PromoteSignatures(signatures); return(await _validatorStateService.TryUpdateValidationStatusAsync(request, status, ValidationStatus.Succeeded)); }
/// <summary> /// Mark a package's signing state and its revoked signatures as invalid. This method does NOT /// persist entity changes to the database. /// </summary> /// <param name="request">The request to validate a package.</param> /// <param name="package">The package's overall signing state that should be invalidated.</param> /// <param name="signature">The package's signatures that should be invalidated.</param> /// <returns>A task that completes when the entities have been updated.</returns> private void InvalidatePackageSignature(IValidationRequest request, PackageSigningState package, PackageSignature signature) { _logger.LogWarning( "Invalidating package {PackageId} {PackageVersion} due to revoked signatures.", request.PackageId, request.PackageVersion); package.SigningStatus = PackageSigningStatus.Invalid; signature.Status = PackageSignatureStatus.Invalid; }
public async Task <IValidationResult> GetResultAsync(IValidationRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var result = await GetProcessorStatusAsync(request); return(result.ToValidationResult()); }
/// <summary> /// Creates a <see cref="SymbolsServerRequest"/> from a <see cref="IValidationRequest"/> /// </summary> /// <param name="validationRequest">The <see cref="IValidationRequest"/>.</param> /// <param name="status">The <see cref="SymbolsPackageIngestRequestStatus"/>.</param> /// <returns></returns> public static SymbolsServerRequest CreateFromValidationRequest(IValidationRequest validationRequest, SymbolsPackageIngestRequestStatus status, string requestName) { return(new SymbolsServerRequest() { Created = DateTime.UtcNow, LastUpdated = DateTime.UtcNow, RequestName = requestName, RequestStatusKey = status, SymbolsKey = validationRequest.PackageKey }); }
public async Task <IValidationResult> GetResultAsync(IValidationRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var validatorStatus = await _validatorStateService.GetStatusAsync(request); return(validatorStatus.ToValidationResult()); }
public async Task EnqueueVerificationAsync(IValidationRequest request, EndCertificate certificate) { var message = new CertificateValidationMessage(certificate.Key, request.ValidationId); var brokeredMessage = _serializer.Serialize(message); var visibleAt = DateTimeOffset.UtcNow + (_configuration.Value.MessageDelay ?? TimeSpan.Zero); brokeredMessage.ScheduledEnqueueTimeUtc = visibleAt; await _topicClient.SendAsync(brokeredMessage); }
/// <summary> /// Decide whether the valid signature should be considered "Valid" or "InGracePeriod". /// </summary> /// <param name="request">The validation request for the package whose signature should be inspected.</param> /// <param name="signature">The valid signature whose status should be decided.</param> /// <returns>True if the signature should be "Valid", false if it should be "InGracePeriod".</returns> private bool IsValidSignatureOutOfGracePeriod(IValidationRequest request, PackageSignature signature) { bool IsCertificateStatusPastTime(EndCertificate certificate, DateTime time) { return(certificate.StatusUpdateTime.HasValue && certificate.StatusUpdateTime > time); } var signingTime = signature.TrustedTimestamps.Max(t => t.Value); // Ensure the timestamps' certificate statuses are fresher than the signature. foreach (var timestamp in signature.TrustedTimestamps) { // A valid signature should NEVER have a timestamp whose end certificate is revoked. // Note that it is possible for a valid signature to have an invalid certificate as // certain certificate statuses, like "NotTimeNested", do not affect signatures. if (timestamp.EndCertificate.Status == EndCertificateStatus.Revoked) { _logger.LogError( Error.PackageCertificateValidationInvalidSignatureState, "Valid signature cannot have a timestamp whose end certificate is revoked ({ValidationId}, {PackageId} {PackageVersion})", request.ValidationId, request.PackageId, request.PackageVersion, signature.Status); throw new InvalidOperationException( $"ValidationId {request.ValidationId} has valid signature with a timestamp whose end certificate is revoked"); } if (!IsCertificateStatusPastTime(timestamp.EndCertificate, signingTime)) { return(false); } } // A signature can be valid even if its certificate is revoked as long as the certificate // revocation date begins after the signature was created. The validation pipeline does // not revalidate revoked certificates, thus, a valid package signature with a revoked // certificate is considered out of the grace period regardless of the certificate's // status update time. if (signature.EndCertificate.Status != EndCertificateStatus.Revoked) { // Ensure the signature's certificate status is fresher than the signature. if (!IsCertificateStatusPastTime(signature.EndCertificate, signingTime)) { return(false); } } return(true); }