Overview
Validation.PackageSigning.ValidateCertificate is a console executable (net472) that runs as a
continuously-polling Azure Service Bus subscription processor. Its sole responsibility is to receive
CertificateValidationMessage requests, download the target X.509 certificate and its ancestor chain
from Azure Blob Storage, execute an online revocation check against the issuing Certificate
Authority, and persist the result back to the validation database.
When a certificate is found to be revoked or invalid the job also evaluates every dependent
PackageSignature and either ignores, warns, or rejects it according to a set of time-based and
flag-based rules. This cascade is what ultimately marks NuGet packages as having invalid signatures.
The online revocation check is performed via Windows’ native CryptoAPI (
X509Chain + raw
CERT_CHAIN_CONTEXT pointer inspection). The executable therefore only runs on Windows and
requires <AllowUnsafeBlocks>true</AllowUnsafeBlocks> in the project file.Role in the NuGetGallery Ecosystem
Upstream trigger
Produced by the package-signing orchestrator when a new certificate requires validation or a
periodic re-check is scheduled via
CertificateValidationMessage.Downstream effects
Writes
EndCertificateStatus and PackageSignatureStatus changes to the shared
IValidationEntitiesContext SQL database, which the gallery reads to decide whether to serve a
package.Queue-back integration
Optionally sends a
CheckValidator message to the package validation queue after a successful
validation so the orchestrator can advance the overall validation state machine.Telemetry
Emits Application Insights metrics for message lag, handler duration, lock-lost events, and
per-signature invalidation alerts under the
ValidateCertificate.* prefix.Key Files and Classes
| File | Class / Type | Purpose |
|---|---|---|
Program.cs | Program | Entry point; bootstraps Job via JobRunner.RunOnce. |
Job.cs | Job : SubscriptionProcessorJob<CertificateValidationMessage> | DI wiring: registers all services, configures Azure Storage (MSI or connection-string), sets up the Service Bus subscription processor. |
CertificateValidationMessageHandler.cs | CertificateValidationMessageHandler | Core message handler — loads certs from blob storage, dispatches to verifier, saves result, optionally sends queue-back message. |
ICertificateValidationService.cs | ICertificateValidationService | Interface: FindCertificateValidationAsync and TrySaveResultAsync. |
CertificateValidationService.cs | CertificateValidationService | EF-backed implementation; handles all four status outcomes and fans out signature invalidation in batches of 500. |
ICertificateVerifier.cs | ICertificateVerifier | Interface for code-signing and timestamping certificate verification. |
OnlineCertificateVerifier.cs | OnlineCertificateVerifier | Windows CryptoAPI implementation; builds X509Chain with RevocationMode.Online and reads raw CERT_REVOCATION_INFO* for precise revocation/status-update timestamps. |
CertificateVerificationResult.cs | CertificateVerificationResult | Immutable value type capturing EndCertificateStatus, X509ChainStatusFlags, optional RevocationTime and StatusUpdateTime; includes a fluent Builder. |
SignatureDeciderFactory.cs | SignatureDeciderFactory | Produces SignatureDecider delegates encoding the policy for how revoked/invalid certificates affect dependent signatures. |
SignatureDecision.cs | SignatureDecision (enum) | Ignore, Warn, or Reject — the three outcomes for a dependent signature. |
TelemetryService.cs | TelemetryService | Application Insights wrapper; implements both ITelemetryService and ISubscriptionProcessorTelemetryService. |
Primitives.cs | Various unsafe structs | P/Invoke-style structs mirroring Windows CryptoAPI types (CERT_CHAIN_CONTEXT, CERT_REVOCATION_INFO, CRL_ENTRY, FILETIME, etc.). Based on .NET CoreFX with custom additions for revocation info. |
Dependencies
Internal Project References
| Project | Role |
|---|---|
Validation.Common.Job | Base SubscriptionProcessorJob<T>, JobRunner, Service Bus plumbing, IFeatureFlagService, IPackageValidationEnqueuer. |
Validation.PackageSigning.Core | ICertificateStore, CertificateStore, CertificateValidationMessage serializer, CertificateStoreConfiguration, EF entity types (EndCertificate, PackageSignature, TrustedTimestamp, IValidationEntitiesContext, etc.). |
NuGet Packages (resolved transitively)
| Package | Usage |
|---|---|
Microsoft.Extensions.DependencyInjection | DI container setup in Job.ConfigureJobServices. |
Microsoft.Extensions.Configuration | IConfigurationRoot binding for CertificateStoreConfiguration. |
Microsoft.Extensions.Logging | Structured logging throughout all services. |
Microsoft.ApplicationInsights | TelemetryClient consumed by TelemetryService. |
Azure.Storage.Blobs | BlobServiceClientFactory for certificate blob storage access. |
Azure.Identity | ManagedIdentityCredential for MSI-based storage authentication. |
Autofac | ContainerBuilder used in ConfigureAutofacServices. |
NuGet.Services.ServiceBus | IMessageHandler<T>, IBrokeredMessageSerializer<T>, ISubscriptionProcessorTelemetryService. |
NuGet.Jobs | JobRunner, SubscriptionProcessorJob<T> base class. |
Message Flow
Notable Patterns and Implementation Details
Batch signature updates. When a certificate is revoked or invalidated,
CertificateValidationService.ProcessDependentSignaturesAsync updates dependent PackageSignature
rows in pages of 500 (MaxSignatureUpdatesPerTransaction) to avoid oversized EF change-tracker
transactions. Each page is committed before the next is fetched.Unknown-status retry loop. If the CA’s revocation endpoint is offline or returns an ambiguous
result, the certificate status is set to
Unknown and HandleAsync returns false, leaving the
Service Bus message unacknowledged for automatic redelivery. After DefaultMaximumValidationFailures
(10) consecutive failures the certificate is promoted to Invalid and a telemetry alert fires,
requiring manual NuGet Admin investigation.Signature decision policy nuances.
SignatureDeciderFactory encodes several non-obvious rules:- A revoked code-signing cert invalidates only signatures whose trusted timestamp post-dates the
revocation time. Signatures timestamped before revocation survive (
Ignore). If revocation time is unknown, all dependent signatures are rejected. - A revoked timestamping cert triggers
Warnon already-accepted signatures andRejecton signatures still at ingestion (Unknownstatus). NotTimeNestedalone is a no-op (Ignore) to avoid false positives from minor clock skew.HasWeakSignature | NotSignatureValidonly rejects signatures at ingestion; existing valid signatures are left intact.