1919using NuGet . Services . Validation ;
2020using NuGet . Services . Validation . Issues ;
2121using NuGetGallery ;
22+ using NuGetGallery . Extensions ;
2223
2324namespace NuGet . Jobs . Validation . PackageSigning . ProcessSignature
2425{
@@ -32,7 +33,7 @@ public class SignatureValidator : ISignatureValidator
3233 private readonly IPackageSignatureVerifier _fullPackageSignatureVerifier ;
3334 private readonly ISignaturePartsExtractor _signaturePartsExtractor ;
3435 private readonly IProcessorPackageFileService _packageFileService ;
35- private readonly IEntityRepository < Certificate > _certificates ;
36+ private readonly ICorePackageService _corePackageService ;
3637 private readonly ITelemetryService _telemetryService ;
3738 private readonly ILogger < SignatureValidator > _logger ;
3839
@@ -42,7 +43,7 @@ public SignatureValidator(
4243 IPackageSignatureVerifier fullPackageSignatureVerifier ,
4344 ISignaturePartsExtractor signaturePartsExtractor ,
4445 IProcessorPackageFileService packageFileService ,
45- IEntityRepository < Certificate > certificates ,
46+ ICorePackageService corePackageService ,
4647 ITelemetryService telemetryService ,
4748 ILogger < SignatureValidator > logger )
4849 {
@@ -51,7 +52,7 @@ public SignatureValidator(
5152 _fullPackageSignatureVerifier = fullPackageSignatureVerifier ?? throw new ArgumentNullException ( nameof ( fullPackageSignatureVerifier ) ) ;
5253 _signaturePartsExtractor = signaturePartsExtractor ?? throw new ArgumentNullException ( nameof ( signaturePartsExtractor ) ) ;
5354 _packageFileService = packageFileService ?? throw new ArgumentNullException ( nameof ( packageFileService ) ) ;
54- _certificates = certificates ?? throw new ArgumentNullException ( nameof ( certificates ) ) ;
55+ _corePackageService = corePackageService ?? throw new ArgumentNullException ( nameof ( corePackageService ) ) ;
5556 _telemetryService = telemetryService ?? throw new ArgumentNullException ( nameof ( telemetryService ) ) ;
5657 _logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
5758 }
@@ -71,20 +72,30 @@ public async Task<SignatureValidatorResult> ValidateAsync(
7172 return await RejectAsync ( context , ValidationIssue . PackageIsZip64 ) ;
7273 }
7374
74- // Validate signed packages and accept unsigned packages.
7575 if ( await context . PackageReader . IsSignedAsync ( cancellationToken ) )
7676 {
7777 return await HandleSignedPackageAsync ( context ) ;
7878 }
79- else
80- {
81- return await HandleUnsignedPackageAsync ( context ) ;
82- }
79+
80+ return await HandleUnsignedPackageAsync ( context ) ;
8381 }
8482 }
85-
83+
8684 private async Task < SignatureValidatorResult > HandleUnsignedPackageAsync ( Context context )
8785 {
86+ var packageRegistration = _corePackageService . FindPackageRegistrationById ( context . Message . PackageId ) ;
87+
88+ if ( packageRegistration . IsSigningRequired ( ) )
89+ {
90+ _logger . LogWarning (
91+ "Package {PackageId} {PackageVersion} for validation {ValidationId} must be signed but is unsigned." ,
92+ context . Message . PackageId ,
93+ context . Message . PackageVersion ,
94+ context . Message . ValidationId ) ;
95+
96+ return await RejectAsync ( context , ValidationIssue . PackageIsNotSigned ) ;
97+ }
98+
8899 _logger . LogInformation (
89100 "Package {PackageId} {PackageVersion} is unsigned, no additional validations necessary for {ValidationId}." ,
90101 context . Message . PackageId ,
@@ -178,7 +189,7 @@ private async Task<SignatureValidatorResult> PerformInitialValidationsAsync(Cont
178189
179190 // We now know we can safely read the signature.
180191 context . Signature = await context . PackageReader . GetPrimarySignatureAsync ( context . CancellationToken ) ;
181-
192+
182193 // Only reject counter signatures that have the author commitment type. Repository counter signatures
183194 // are removed and replaced if they are invalid and valid ones are left as-is. Counter signatures
184195 // without author or repository signature commitment type are not produced by the client but
@@ -319,16 +330,16 @@ private async Task<SignatureValidatorResult> PerformFinalValidationAsync(Context
319330 }
320331
321332 // Block packages with any unknown signing certificates.
322- var signingFingerprint = context . Signature
333+ var signingCertificate = context . Signature
323334 . SignerInfo
324- . Certificate
325- . ComputeSHA256Thumbprint ( ) ;
326- var isKnownCertificate = _certificates
327- . GetAll ( )
328- . Any ( c => signingFingerprint == c . Thumbprint ) ;
329- if ( ! isKnownCertificate )
335+ . Certificate ;
336+ var signingFingerprint = signingCertificate . ComputeSHA256Thumbprint ( ) ;
337+
338+ var packageRegistration = _corePackageService . FindPackageRegistrationById ( context . Message . PackageId ) ;
339+
340+ if ( ! packageRegistration . IsAcceptableSigningCertificate ( signingFingerprint ) )
330341 {
331- _logger . LogInformation (
342+ _logger . LogWarning (
332343 "Signed package {PackageId} {PackageVersion} is blocked for validation {ValidationId} since it has an unknown certificate fingerprint: {UnknownFingerprint}" ,
333344 context . Message . PackageId ,
334345 context . Message . PackageVersion ,
@@ -337,7 +348,7 @@ private async Task<SignatureValidatorResult> PerformFinalValidationAsync(Context
337348
338349 return await RejectAsync (
339350 context ,
340- ValidationIssue . PackageIsSigned ) ;
351+ new UnauthorizedCertificateFailure ( signingCertificate . Thumbprint . ToLowerInvariant ( ) ) ) ;
341352 }
342353
343354 // Call the "verify" API, which does the main logic of signature validation.
@@ -357,6 +368,11 @@ private async Task<SignatureValidatorResult> PerformFinalValidationAsync(Context
357368 context . Message . ValidationId ,
358369 signingFingerprint ) ;
359370
371+ await _corePackageService . UpdatePackageSigningCertificateAsync (
372+ context . Message . PackageId ,
373+ context . Message . PackageVersion ,
374+ signingFingerprint ) ;
375+
360376 return null ;
361377 }
362378
0 commit comments