diff --git a/src/NuGet.Services.Validation.Orchestrator/NuGet.Services.Validation.Orchestrator.csproj b/src/NuGet.Services.Validation.Orchestrator/NuGet.Services.Validation.Orchestrator.csproj
index 047d7f454..0e7df2ef7 100644
--- a/src/NuGet.Services.Validation.Orchestrator/NuGet.Services.Validation.Orchestrator.csproj
+++ b/src/NuGet.Services.Validation.Orchestrator/NuGet.Services.Validation.Orchestrator.csproj
@@ -107,7 +107,7 @@
- 2.23.0
+ 2.25.0-master-29664
diff --git a/src/Validation.Common.Job/Validation.Common.Job.csproj b/src/Validation.Common.Job/Validation.Common.Job.csproj
index 91a400785..fbbdfad1e 100644
--- a/src/Validation.Common.Job/Validation.Common.Job.csproj
+++ b/src/Validation.Common.Job/Validation.Common.Job.csproj
@@ -100,10 +100,10 @@
2.23.0
- 2.23.0
+ 2.25.0-master-29664
- 4.4.4-dev-26726
+ 4.4.4-dev-29942
2.5.0
diff --git a/src/Validation.Common.Job/Validation.Common.Job.nuspec b/src/Validation.Common.Job/Validation.Common.Job.nuspec
index 0adae1f71..a03fae7c3 100644
--- a/src/Validation.Common.Job/Validation.Common.Job.nuspec
+++ b/src/Validation.Common.Job/Validation.Common.Job.nuspec
@@ -19,8 +19,8 @@
-
-
+
+
diff --git a/src/Validation.PackageSigning.ProcessSignature/Job.cs b/src/Validation.PackageSigning.ProcessSignature/Job.cs
index fe87a1821..09aa0026f 100644
--- a/src/Validation.PackageSigning.ProcessSignature/Job.cs
+++ b/src/Validation.PackageSigning.ProcessSignature/Job.cs
@@ -1,13 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
using Autofac;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.WindowsAzure.Storage;
+using NuGet.Jobs.Configuration;
using NuGet.Jobs.Validation.PackageSigning.Configuration;
using NuGet.Jobs.Validation.PackageSigning.Messages;
using NuGet.Jobs.Validation.PackageSigning.Storage;
@@ -30,7 +30,12 @@ protected override void ConfigureJobServices(IServiceCollection services, IConfi
services.AddTransient, SubscriptionProcessor>();
- services.AddTransient, EntityRepository>();
+ services.AddScoped(serviceProvider =>
+ new EntitiesContext(
+ serviceProvider.GetRequiredService>().Value.ConnectionString,
+ readOnly: false));
+ services.Add(ServiceDescriptor.Transient(typeof(IEntityRepository<>), typeof(EntityRepository<>)));
+ services.AddTransient();
services.AddTransient();
@@ -61,7 +66,7 @@ protected override void ConfigureJobServices(IServiceCollection services, IConfi
PackageSignatureVerifierFactory.CreateFull(),
p.GetRequiredService(),
p.GetRequiredService(),
- p.GetRequiredService>(),
+ p.GetRequiredService(),
p.GetRequiredService(),
p.GetRequiredService>()));
}
diff --git a/src/Validation.PackageSigning.ProcessSignature/SignatureValidator.cs b/src/Validation.PackageSigning.ProcessSignature/SignatureValidator.cs
index e3b14498c..f92e61c30 100644
--- a/src/Validation.PackageSigning.ProcessSignature/SignatureValidator.cs
+++ b/src/Validation.PackageSigning.ProcessSignature/SignatureValidator.cs
@@ -19,6 +19,7 @@
using NuGet.Services.Validation;
using NuGet.Services.Validation.Issues;
using NuGetGallery;
+using NuGetGallery.Extensions;
namespace NuGet.Jobs.Validation.PackageSigning.ProcessSignature
{
@@ -32,7 +33,7 @@ public class SignatureValidator : ISignatureValidator
private readonly IPackageSignatureVerifier _fullPackageSignatureVerifier;
private readonly ISignaturePartsExtractor _signaturePartsExtractor;
private readonly IProcessorPackageFileService _packageFileService;
- private readonly IEntityRepository _certificates;
+ private readonly ICorePackageService _corePackageService;
private readonly ITelemetryService _telemetryService;
private readonly ILogger _logger;
@@ -42,7 +43,7 @@ public SignatureValidator(
IPackageSignatureVerifier fullPackageSignatureVerifier,
ISignaturePartsExtractor signaturePartsExtractor,
IProcessorPackageFileService packageFileService,
- IEntityRepository certificates,
+ ICorePackageService corePackageService,
ITelemetryService telemetryService,
ILogger logger)
{
@@ -51,7 +52,7 @@ public SignatureValidator(
_fullPackageSignatureVerifier = fullPackageSignatureVerifier ?? throw new ArgumentNullException(nameof(fullPackageSignatureVerifier));
_signaturePartsExtractor = signaturePartsExtractor ?? throw new ArgumentNullException(nameof(signaturePartsExtractor));
_packageFileService = packageFileService ?? throw new ArgumentNullException(nameof(packageFileService));
- _certificates = certificates ?? throw new ArgumentNullException(nameof(certificates));
+ _corePackageService = corePackageService ?? throw new ArgumentNullException(nameof(corePackageService));
_telemetryService = telemetryService ?? throw new ArgumentNullException(nameof(telemetryService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -71,20 +72,30 @@ public async Task ValidateAsync(
return await RejectAsync(context, ValidationIssue.PackageIsZip64);
}
- // Validate signed packages and accept unsigned packages.
if (await context.PackageReader.IsSignedAsync(cancellationToken))
{
return await HandleSignedPackageAsync(context);
}
- else
- {
- return await HandleUnsignedPackageAsync(context);
- }
+
+ return await HandleUnsignedPackageAsync(context);
}
}
-
+
private async Task HandleUnsignedPackageAsync(Context context)
{
+ var packageRegistration = _corePackageService.FindPackageRegistrationById(context.Message.PackageId);
+
+ if (packageRegistration.IsSigningRequired())
+ {
+ _logger.LogWarning(
+ "Package {PackageId} {PackageVersion} for validation {ValidationId} must be signed but is unsigned.",
+ context.Message.PackageId,
+ context.Message.PackageVersion,
+ context.Message.ValidationId);
+
+ return await RejectAsync(context, ValidationIssue.PackageIsNotSigned);
+ }
+
_logger.LogInformation(
"Package {PackageId} {PackageVersion} is unsigned, no additional validations necessary for {ValidationId}.",
context.Message.PackageId,
@@ -178,7 +189,7 @@ private async Task PerformInitialValidationsAsync(Cont
// We now know we can safely read the signature.
context.Signature = await context.PackageReader.GetPrimarySignatureAsync(context.CancellationToken);
-
+
// Only reject counter signatures that have the author commitment type. Repository counter signatures
// are removed and replaced if they are invalid and valid ones are left as-is. Counter signatures
// without author or repository signature commitment type are not produced by the client but
@@ -323,12 +334,12 @@ private async Task PerformFinalValidationAsync(Context
.SignerInfo
.Certificate
.ComputeSHA256Thumbprint();
- var isKnownCertificate = _certificates
- .GetAll()
- .Any(c => signingFingerprint == c.Thumbprint);
- if (!isKnownCertificate)
+
+ var packageRegistration = _corePackageService.FindPackageRegistrationById(context.Message.PackageId);
+
+ if (!packageRegistration.IsAcceptableSigningCertificate(signingFingerprint))
{
- _logger.LogInformation(
+ _logger.LogWarning(
"Signed package {PackageId} {PackageVersion} is blocked for validation {ValidationId} since it has an unknown certificate fingerprint: {UnknownFingerprint}",
context.Message.PackageId,
context.Message.PackageVersion,
@@ -357,6 +368,11 @@ private async Task PerformFinalValidationAsync(Context
context.Message.ValidationId,
signingFingerprint);
+ await _corePackageService.UpdatePackageSigningCertificateAsync(
+ context.Message.PackageId,
+ context.Message.PackageVersion,
+ signingFingerprint);
+
return null;
}
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorFacts.cs b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorFacts.cs
index 8040f19d0..a98b02a64 100644
--- a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorFacts.cs
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorFacts.cs
@@ -3,7 +3,6 @@
using System;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -29,15 +28,15 @@ public class ValidateAsync
{
private MemoryStream _packageStream;
private readonly int _packageKey;
- private readonly SignatureValidationMessage _message;
+ private SignatureValidationMessage _message;
private readonly CancellationToken _cancellationToken;
private readonly Mock _packageSigningStateService;
- private VerifySignaturesResult _mimialVerifyResult;
+ private VerifySignaturesResult _mimimalVerifyResult;
private readonly Mock _mimimalPackageSignatureVerifier;
private VerifySignaturesResult _fullVerifyResult;
private readonly Mock _fullPackageSignatureVerifier;
private readonly Mock _signaturePartsExtractor;
- private readonly Mock> _certificates;
+ private readonly Mock _corePackageService;
private readonly ILogger _logger;
private readonly Mock _packageFileService;
private readonly Uri _nupkgUri;
@@ -57,11 +56,11 @@ public ValidateAsync(ITestOutputHelper output)
_packageSigningStateService = new Mock();
- _mimialVerifyResult = new VerifySignaturesResult(true);
+ _mimimalVerifyResult = new VerifySignaturesResult(true);
_mimimalPackageSignatureVerifier = new Mock();
_mimimalPackageSignatureVerifier
.Setup(x => x.VerifySignaturesAsync(It.IsAny(), It.IsAny(), It.IsAny()))
- .ReturnsAsync(() => _mimialVerifyResult);
+ .ReturnsAsync(() => _mimimalVerifyResult);
_fullVerifyResult = new VerifySignaturesResult(true);
_fullPackageSignatureVerifier = new Mock();
@@ -70,14 +69,10 @@ public ValidateAsync(ITestOutputHelper output)
.ReturnsAsync(() => _fullVerifyResult);
_signaturePartsExtractor = new Mock();
- _certificates = new Mock>();
+ _corePackageService = new Mock();
var loggerFactory = new LoggerFactory().AddXunit(output);
_logger = loggerFactory.CreateLogger();
- _certificates
- .Setup(x => x.GetAll())
- .Returns(Enumerable.Empty().AsQueryable());
-
_packageFileService = new Mock();
_nupkgUri = new Uri("https://example-storage/TestProcessor/b777135f-1aac-4ec2-a3eb-1f64fe1880d5/nuget.versioning.4.3.0.nupkg");
_packageFileService
@@ -92,7 +87,7 @@ public ValidateAsync(ITestOutputHelper output)
_fullPackageSignatureVerifier.Object,
_signaturePartsExtractor.Object,
_packageFileService.Object,
- _certificates.Object,
+ _corePackageService.Object,
_telemetryService.Object,
_logger);
}
@@ -136,6 +131,8 @@ private void Validate(
x => x.ExtractAsync(It.IsAny(), It.IsAny(), It.IsAny()),
Times.Never);
}
+
+ _corePackageService.VerifyAll();
}
[Fact]
@@ -157,12 +154,45 @@ public async Task RejectsZip64Packages()
Assert.Equal(ValidationIssueCode.PackageIsZip64, issue.IssueCode);
}
+ [Fact]
+ public async Task RejectsUnsignedPackagesWhenSigningIsRequired()
+ {
+ // Arrange
+ _packageStream = TestResources.GetResourceStream(TestResources.UnsignedPackage);
+ TestUtility.RequireSignedPackage(_corePackageService, TestResources.UnsignedPackageId);
+ _message = new SignatureValidationMessage(
+ TestResources.UnsignedPackageId,
+ TestResources.UnsignedPackageVersion,
+ new Uri($"https://unit.test/{TestResources.UnsignedPackage.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
+ // Act
+ var result = await _target.ValidateAsync(
+ _packageKey,
+ _packageStream,
+ _message,
+ _cancellationToken);
+
+ // Assert
+ Validate(result, ValidationStatus.Failed, PackageSigningStatus.Invalid);
+ var issue = Assert.Single(result.Issues);
+ Assert.Equal(ValidationIssueCode.PackageIsNotSigned, issue.IssueCode);
+ }
+
[Fact]
public async Task AcceptsSignedPackagesWithKnownCertificates()
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
- ConfigureKnownSignedPackage(TestResources.Leaf1Thumbprint);
+ TestUtility.RequireSignedPackage(
+ _corePackageService,
+ TestResources.SignedPackageLeafId,
+ TestResources.Leaf1Thumbprint);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
// Act
var result = await _target.ValidateAsync(
@@ -181,7 +211,12 @@ public async Task RejectsSignedPackagesWithFailedMinimalVerifyResult()
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
- _mimialVerifyResult = new VerifySignaturesResult(valid: false);
+ _mimimalVerifyResult = new VerifySignaturesResult(valid: false);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
// Act
var result = await _target.ValidateAsync(
@@ -203,7 +238,7 @@ public async Task RejectsPackagesWithMimimalVerificationErrors()
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
- _mimialVerifyResult = new VerifySignaturesResult(
+ _mimimalVerifyResult = new VerifySignaturesResult(
valid: false,
results: new[]
{
@@ -217,6 +252,11 @@ public async Task RejectsPackagesWithMimimalVerificationErrors()
message: "The package signature is invalid."),
})
});
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
// Act
var result = await _target.ValidateAsync(
@@ -238,8 +278,16 @@ public async Task RejectsSignedPackagesWithKnownCertificatesButFailedFullVerifyR
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
- ConfigureKnownSignedPackage(TestResources.Leaf1Thumbprint);
+ TestUtility.RequireSignedPackage(
+ _corePackageService,
+ TestResources.SignedPackageLeafId,
+ TestResources.Leaf1Thumbprint);
_fullVerifyResult = new VerifySignaturesResult(valid: false);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
// Act
var result = await _target.ValidateAsync(
@@ -258,7 +306,10 @@ public async Task RejectsPackagesWithFullVerificationErrors()
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
- ConfigureKnownSignedPackage(TestResources.Leaf1Thumbprint);
+ TestUtility.RequireSignedPackage(
+ _corePackageService,
+ TestResources.SignedPackageLeafId,
+ TestResources.Leaf1Thumbprint);
_fullVerifyResult = new VerifySignaturesResult(
valid: false,
results: new[]
@@ -281,6 +332,11 @@ public async Task RejectsPackagesWithFullVerificationErrors()
message: "Some other thing happened."),
})
});
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
// Act
var result = await _target.ValidateAsync(
@@ -305,7 +361,15 @@ public async Task RejectsSignedPackagesWithUnknownCertificates()
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
- ConfigureKnownSignedPackage(TestResources.Leaf2Thumbprint);
+ TestUtility.RequireSignedPackage(
+ _corePackageService,
+ TestResources.SignedPackageLeafId,
+ TestResources.Leaf2Thumbprint);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
// Act
var result = await _target.ValidateAsync(
@@ -325,8 +389,9 @@ public async Task DoesNotUploadPackageWhenValidationFailed()
{
// Arrange
_packageStream = TestResources.GetResourceStream(TestResources.AuthorAndRepoSignedPackageLeaf1);
+ TestUtility.RequireUnsignedPackage(_corePackageService, _message.PackageId);
- // Arrange & Act
+ // Act
var result = await _target.ValidateAsync(
_packageKey,
_packageStream,
@@ -341,13 +406,40 @@ public async Task DoesNotUploadPackageWhenValidationFailed()
}
[Theory]
- [InlineData(TestResources.RepoSignedPackageLeaf1, PackageSigningStatus.Unsigned)]
- [InlineData(TestResources.AuthorAndRepoSignedPackageLeaf1, PackageSigningStatus.Valid)]
- public async Task StripsAndAcceptsPackagesWithRepositorySignatures(string resourceName, PackageSigningStatus signingStatus)
+ [InlineData(
+ TestResources.RepoSignedPackageLeaf1,
+ TestResources.RepoSignedPackageLeafId,
+ TestResources.RepoSignedPackageLeaf1Version,
+ PackageSigningStatus.Unsigned,
+ false)]
+ [InlineData(
+ TestResources.AuthorAndRepoSignedPackageLeaf1,
+ TestResources.AuthorAndRepoSignedPackageLeafId,
+ TestResources.AuthorAndRepoSignedPackageLeaf1Version,
+ PackageSigningStatus.Valid,
+ true)]
+ public async Task StripsAndAcceptsPackagesWithRepositorySignatures(
+ string resourceName,
+ string packageId,
+ string packageVersion,
+ PackageSigningStatus signingStatus,
+ bool allowSignedPackage)
{
// Arrange
_packageStream = TestResources.GetResourceStream(resourceName);
- ConfigureKnownSignedPackage(TestResources.Leaf1Thumbprint);
+ if (allowSignedPackage)
+ {
+ TestUtility.RequireSignedPackage(_corePackageService, packageId, TestResources.Leaf1Thumbprint);
+ }
+ else
+ {
+ TestUtility.RequireUnsignedPackage(_corePackageService, packageId);
+ }
+ _message = new SignatureValidationMessage(
+ packageId,
+ packageVersion,
+ new Uri($"https://unit.test/{resourceName.ToLowerInvariant()}"),
+ Guid.NewGuid());
Stream uploadedStream = null;
_packageFileService
@@ -355,7 +447,7 @@ public async Task StripsAndAcceptsPackagesWithRepositorySignatures(string resour
.Returns(Task.CompletedTask)
.Callback((_, __, ___, s) => uploadedStream = s);
- // Arrange & Act
+ // Act
var result = await _target.ValidateAsync(
_packageKey,
_packageStream,
@@ -376,12 +468,105 @@ public async Task StripsAndAcceptsPackagesWithRepositorySignatures(string resour
}
[Fact]
- public async Task AcceptsUnsignedPackages()
+ public async Task StripsAndRejectsPackagesWithRepositorySignatureWhenPackageMustBeAuthorSigned()
+ {
+ _packageStream = TestResources.GetResourceStream(TestResources.RepoSignedPackageLeaf1);
+ TestUtility.RequireSignedPackage(_corePackageService, TestResources.RepoSignedPackageLeafId);
+ _message = new SignatureValidationMessage(
+ TestResources.RepoSignedPackageLeafId,
+ TestResources.RepoSignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.RepoSignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
+ Stream uploadedStream = null;
+ _packageFileService
+ .Setup(x => x.SaveAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
+ .Returns(Task.CompletedTask)
+ .Callback((_, __, ___, s) => uploadedStream = s);
+
+ var result = await _target.ValidateAsync(
+ _packageKey,
+ _packageStream,
+ _message,
+ _cancellationToken);
+
+ Validate(result, ValidationStatus.Failed, PackageSigningStatus.Invalid);
+ Assert.Equal(1, result.Issues.Count);
+ var issue = Assert.IsType(result.Issues[0]);
+ Assert.Equal(ValidationIssueCode.PackageIsNotSigned, issue.IssueCode);
+ }
+
+ [Fact]
+ public async Task StripsAndRejectsPackagesWithRepositorySignatureWhenPackageIsAuthorSignedWithUnknownCertificate()
+ {
+ _packageStream = TestResources.GetResourceStream(TestResources.AuthorAndRepoSignedPackageLeaf1);
+ TestUtility.RequireSignedPackage(_corePackageService, TestResources.AuthorAndRepoSignedPackageLeafId, TestResources.Leaf2Thumbprint);
+ _message = new SignatureValidationMessage(
+ TestResources.AuthorAndRepoSignedPackageLeafId,
+ TestResources.AuthorAndRepoSignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.AuthorAndRepoSignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
+ var result = await _target.ValidateAsync(
+ _packageKey,
+ _packageStream,
+ _message,
+ _cancellationToken);
+
+ Validate(result, ValidationStatus.Failed, PackageSigningStatus.Invalid);
+ Assert.Equal(1, result.Issues.Count);
+ var issue = Assert.IsType(result.Issues[0]);
+ Assert.Equal(ValidationIssueCode.PackageIsSigned, issue.IssueCode);
+ }
+
+ [Fact]
+ public async Task WhenPackageSupportsButDoesNotRequireSigning_AcceptsUnsignedPackages()
{
// Arrange
+ var user1 = new User()
+ {
+ Key = 1
+ };
+ var user2 = new User()
+ {
+ Key = 2
+ };
+ var packageRegistration = new PackageRegistration()
+ {
+ Key = 3,
+ Id = TestResources.UnsignedPackageId
+ };
+ var certificate = new Certificate()
+ {
+ Key = 4,
+ Thumbprint = TestResources.Leaf1Thumbprint
+ };
+ var userCertificate = new UserCertificate()
+ {
+ Key = 5,
+ CertificateKey = certificate.Key,
+ Certificate = certificate,
+ UserKey = user1.Key,
+ User = user1
+ };
+
+ user1.UserCertificates.Add(userCertificate);
+ certificate.UserCertificates.Add(userCertificate);
+
+ packageRegistration.Owners.Add(user1);
+ packageRegistration.Owners.Add(user2);
+
_packageStream = TestResources.GetResourceStream(TestResources.UnsignedPackage);
+ _corePackageService
+ .Setup(x => x.FindPackageRegistrationById(It.Is(id => id == _message.PackageId)))
+ .Returns(packageRegistration);
+ _message = new SignatureValidationMessage(
+ TestResources.UnsignedPackageId,
+ TestResources.UnsignedPackageVersion,
+ new Uri($"https://unit.test/{TestResources.UnsignedPackage.ToLowerInvariant()}"),
+ Guid.NewGuid());
- // Arrange & Act
+ // Act
var result = await _target.ValidateAsync(
_packageKey,
_packageStream,
@@ -393,12 +578,53 @@ public async Task AcceptsUnsignedPackages()
Assert.Empty(result.Issues);
}
- private void ConfigureKnownSignedPackage(string thumbprint)
+ [Fact]
+ public async Task WhenPackageSupportsButDoesNotRequireSigning_AcceptsPackagesSignedWithKnownCertificates()
{
- _certificates
- .Setup(x => x.GetAll())
- .Returns(new[] { new Certificate { Thumbprint = thumbprint } }.AsQueryable());
+ // Arrange
+ _packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
+ TestUtility.RequireSignedPackage(_corePackageService, TestResources.SignedPackageLeafId, TestResources.Leaf1Thumbprint);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
+ // Act
+ var result = await _target.ValidateAsync(
+ _packageKey,
+ _packageStream,
+ _message,
+ _cancellationToken);
+
+ // Assert
+ Validate(result, ValidationStatus.Succeeded, PackageSigningStatus.Valid);
+ Assert.Empty(result.Issues);
+ }
+
+ [Fact]
+ public async Task WhenPackageRequiresUnsignedPackages_AcceptsUnsignedPackages()
+ {
+ // Arrange
+ _packageStream = TestResources.GetResourceStream(TestResources.UnsignedPackage);
+ TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.UnsignedPackageId);
+ _message = new SignatureValidationMessage(
+ TestResources.UnsignedPackageId,
+ TestResources.UnsignedPackageVersion,
+ new Uri($"https://unit.test/{TestResources.UnsignedPackage.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
+ // Act
+ var result = await _target.ValidateAsync(
+ _packageKey,
+ _packageStream,
+ _message,
+ _cancellationToken);
+
+ // Assert
+ Validate(result, ValidationStatus.Succeeded, PackageSigningStatus.Unsigned);
+ Assert.Empty(result.Issues);
}
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs
index 203d6ec6c..5419d0071 100644
--- a/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/SignatureValidatorIntegrationTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
@@ -44,8 +43,7 @@ public class SignatureValidatorIntegrationTests : IDisposable
private readonly SignaturePartsExtractor _signaturePartsExtractor;
private readonly Mock _packageFileService;
private readonly Uri _nupkgUri;
- private readonly Mock> _certificates;
- private readonly List _trustedThumbprints;
+ private readonly Mock _corePackageService;
private readonly IPackageSignatureVerifier _minimalPackageSignatureVerifier;
private readonly IPackageSignatureVerifier _fullPackageSignatureVerifier;
private readonly Mock _telemetryClient;
@@ -54,7 +52,7 @@ public class SignatureValidatorIntegrationTests : IDisposable
private readonly int _packageKey;
private Stream _packageStream;
private byte[] _savedPackageBytes;
- private readonly SignatureValidationMessage _message;
+ private SignatureValidationMessage _message;
private readonly CancellationToken _token;
private readonly SignatureValidator _target;
@@ -91,7 +89,7 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
loggerFactory.CreateLogger());
_certificateStore = new Mock();
-
+
_signaturePartsExtractor = new SignaturePartsExtractor(
_certificateStore.Object,
_validationEntitiesContext.Object,
@@ -115,11 +113,7 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
}
});
- _certificates = new Mock>();
- _trustedThumbprints = new List();
- _certificates
- .Setup(x => x.GetAll())
- .Returns(() => _trustedThumbprints.Select(x => new Certificate { Thumbprint = x }).AsQueryable());
+ _corePackageService = new Mock();
// These dependencies are concrete.
_minimalPackageSignatureVerifier = PackageSignatureVerifierFactory.CreateMinimal();
@@ -146,14 +140,14 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
_fullPackageSignatureVerifier,
_signaturePartsExtractor,
_packageFileService.Object,
- _certificates.Object,
+ _corePackageService.Object,
_telemetryService,
_logger);
}
public async Task GetSignedPackageStream1Async()
{
- AllowCertificateThumbprint(await _fixture.GetSigningCertificateThumbprintAsync());
+ TestUtility.RequireSignedPackage(_corePackageService, _message.PackageId, await _fixture.GetSigningCertificateThumbprintAsync());
return await _fixture.GetSignedPackageStream1Async(_output);
}
@@ -179,9 +173,15 @@ public async Task AcceptsValidSignedPackage()
public async Task RejectsUntrustedSigningCertificate()
{
// Arrange
- AllowCertificateThumbprint(TestResources.Leaf1Thumbprint);
+ TestUtility.RequireSignedPackage(_corePackageService, TestResources.SignedPackageLeafId, TestResources.Leaf1Thumbprint);
_packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/validation/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
// Act
var result = await _target.ValidateAsync(
_packageKey,
@@ -223,10 +223,18 @@ await _fixture.GetSigningCertificateAsync(),
_output);
}
- AllowCertificateThumbprint(await _fixture.GetSigningCertificateThumbprintAsync());
+ TestUtility.RequireSignedPackage(_corePackageService,
+ TestResources.SignedPackageLeafId,
+ await _fixture.GetSigningCertificateThumbprintAsync());
_packageStream = new MemoryStream(packageBytes);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/validation/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
// Act
var result = await _target.ValidateAsync(
_packageKey,
@@ -274,10 +282,18 @@ await _fixture.GetSigningCertificateAsync(),
// https://github.com/NuGet/Home/issues/6508
await Task.Delay(TimeSpan.FromSeconds(1));
- AllowCertificateThumbprint(await _fixture.GetSigningCertificateThumbprintAsync());
+ TestUtility.RequireSignedPackage(_corePackageService,
+ TestResources.SignedPackageLeafId,
+ await _fixture.GetSigningCertificateThumbprintAsync());
_packageStream = new MemoryStream(packageBytes);
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/validation/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
+
SignatureValidatorResult result;
using (testServer.RegisterResponders(timestampService, addOcsp: false))
{
@@ -329,7 +345,7 @@ await _fixture.GetTimestampServiceUrlAsync(),
// https://github.com/NuGet/Home/issues/6508
await Task.Delay(TimeSpan.FromSeconds(1));
- AllowCertificateThumbprint(signingCertificate.ComputeSHA256Thumbprint());
+ TestUtility.RequireSignedPackage(_corePackageService, TestResources.SignedPackageLeafId, signingCertificate.ComputeSHA256Thumbprint());
_packageStream = new MemoryStream(packageBytes);
@@ -454,12 +470,15 @@ public async Task RejectsMultipleSignatures()
{
// Arrange
SetSignatureContent(
+ TestResources.SignedPackageLeafId,
TestResources.GetResourceStream(TestResources.SignedPackageLeaf1),
configuredSignedCms: signedCms =>
{
using (var additionalCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null))
{
- AllowCertificateThumbprint(additionalCertificate.ComputeSHA256Thumbprint());
+ TestUtility.RequireSignedPackage(_corePackageService,
+ TestResources.SignedPackageLeafId,
+ additionalCertificate.ComputeSHA256Thumbprint());
signedCms.ComputeSignature(new CmsSigner(additionalCertificate));
}
});
@@ -491,7 +510,7 @@ public async Task RejectsAuthorCounterSignatures()
{
using (var counterCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null))
{
- AllowCertificateThumbprint(counterCertificate.ComputeSHA256Thumbprint());
+ TestUtility.RequireSignedPackage(_corePackageService, _message.PackageId, counterCertificate.ComputeSHA256Thumbprint());
var cmsSigner = new CmsSigner(counterCertificate);
cmsSigner.SignedAttributes.Add(AttributeUtility.CreateCommitmentTypeIndication(SignatureType.Author));
@@ -557,6 +576,11 @@ await _fixture.GetTimestampServiceUrlAsync(),
public async Task StripsRepositorySignatures()
{
// Arrange
+ _message = new SignatureValidationMessage(
+ TestResources.UnsignedPackageId,
+ TestResources.UnsignedPackageVersion,
+ new Uri($"https://unit.test/validation/{TestResources.UnsignedPackage.ToLowerInvariant()}"),
+ Guid.NewGuid());
var packageBytes = await _fixture.GenerateSignedPackageBytesAsync(
TestResources.GetResourceStream(TestResources.UnsignedPackage),
new RepositorySignPackageRequest(
@@ -568,6 +592,7 @@ await _fixture.GetSigningCertificateAsync(),
await _fixture.GetTimestampServiceUrlAsync(),
_output);
var packageStream = new MemoryStream(packageBytes);
+ TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.UnsignedPackageId);
// Act
var result = await _target.ValidateAsync(
@@ -603,7 +628,7 @@ public async Task RejectsMutuallyExclusiveCounterSignaturesCommitmentTypes(Signa
{
using (var counterCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null))
{
- AllowCertificateThumbprint(counterCertificate.ComputeSHA256Thumbprint());
+ TestUtility.RequireSignedPackage(_corePackageService, _message.PackageId, counterCertificate.ComputeSHA256Thumbprint());
var cmsSigner = new CmsSigner(counterCertificate);
foreach (var type in counterSignatureTypes)
@@ -637,6 +662,11 @@ public async Task RejectsMutuallyExclusiveCounterSignaturesCommitmentTypes(Signa
public async Task AllowsNonAuthorAndRepositoryCounterSignatures(string commitmentTypeOidBase64)
{
// Arrange
+ _message = new SignatureValidationMessage(
+ TestResources.SignedPackageLeafId,
+ TestResources.SignedPackageLeaf1Version,
+ new Uri($"https://unit.test/validation/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"),
+ Guid.NewGuid());
var packageStream = await GetSignedPackageStream1Async();
ModifySignatureContent(
packageStream,
@@ -644,8 +674,6 @@ public async Task AllowsNonAuthorAndRepositoryCounterSignatures(string commitmen
{
using (var counterCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null))
{
- AllowCertificateThumbprint(counterCertificate.ComputeSHA256Thumbprint());
-
var cmsSigner = new CmsSigner(counterCertificate);
if (commitmentTypeOidBase64 != null)
@@ -660,7 +688,7 @@ public async Task AllowsNonAuthorAndRepositoryCounterSignatures(string commitmen
cmsSigner.SignedAttributes.Add(attribute);
}
-
+
signedCms.SignerInfos[0].ComputeCounterSignature(cmsSigner);
}
});
@@ -684,6 +712,7 @@ public async Task RejectsInvalidSignatureContent()
{
// Arrange
SetSignatureContent(
+ TestResources.SignedPackageLeafId,
TestResources.GetResourceStream(TestResources.SignedPackageLeaf1),
"!!--:::FOO...");
@@ -708,6 +737,7 @@ public async Task RejectInvalidSignatureContentVersion()
{
// Arrange
SetSignatureContent(
+ TestResources.SignedPackageLeafId,
TestResources.GetResourceStream(TestResources.SignedPackageLeaf1),
"Version:2" + Environment.NewLine + Environment.NewLine + "2.16.840.1.101.3.4.2.1-Hash:hash");
@@ -733,6 +763,7 @@ public async Task RejectsNonAuthorSignature()
NuGetHashAlgorithmName.SHA256,
hashValue: "hash");
SetSignatureContent(
+ TestResources.SignedPackageLeafId,
TestResources.GetResourceStream(TestResources.SignedPackageLeaf1),
content.GetBytes());
@@ -798,7 +829,6 @@ private void SetSignatureFileContent(Stream packageStream, byte[] fileContent)
}
}
-
private void ModifySignatureContent(Stream packageStream, Action configuredSignedCms = null)
{
SignedCms signedCms;
@@ -822,7 +852,11 @@ private void ModifySignatureContent(Stream packageStream, Action conf
SetSignatureFileContent(packageStream, signedCms.Encode());
}
- private void SetSignatureContent(Stream packageStream, byte[] signatureContent = null, Action configuredSignedCms = null)
+ private void SetSignatureContent(
+ string packageId,
+ Stream packageStream,
+ byte[] signatureContent = null,
+ Action configuredSignedCms = null)
{
if (signatureContent == null)
{
@@ -834,7 +868,7 @@ private void SetSignatureContent(Stream packageStream, byte[] signatureContent =
using (var certificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null))
{
- AllowCertificateThumbprint(certificate.ComputeSHA256Thumbprint());
+ TestUtility.RequireSignedPackage(_corePackageService, packageId, certificate.ComputeSHA256Thumbprint());
var contentInfo = new ContentInfo(signatureContent);
var signedCms = new SignedCms(contentInfo);
@@ -849,15 +883,12 @@ private void SetSignatureContent(Stream packageStream, byte[] signatureContent =
}
}
- private void SetSignatureContent(Stream packageStream, string signatureContent)
+ private void SetSignatureContent(string packageId, Stream packageStream, string signatureContent)
{
- SetSignatureContent(packageStream, signatureContent: Encoding.UTF8.GetBytes(signatureContent));
+ SetSignatureContent(packageId, packageStream, signatureContent: Encoding.UTF8.GetBytes(signatureContent));
}
- private void AllowCertificateThumbprint(string thumbprint)
- {
- _trustedThumbprints.Add(thumbprint);
- }
+
private void VerifyPackageSigningStatus(SignatureValidatorResult result, ValidationStatus validationStatus, PackageSigningStatus packageSigningStatus)
{
@@ -901,4 +932,4 @@ public Stream GetSource()
}
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestResources.cs b/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestResources.cs
index 3cee0307e..46f1f6cd8 100644
--- a/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestResources.cs
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestResources.cs
@@ -11,12 +11,20 @@ namespace Validation.PackageSigning.ProcessSignature.Tests
public static class TestResources
{
private const string ResourcePrefix = "Validation.PackageSigning.ProcessSignature.Tests.TestData.";
+ public const string SignedPackageLeafId = "TestSigned.leaf";
+ public const string SignedPackageLeaf1Version = "1.1.0";
public const string SignedPackageLeaf1 = "TestSigned.leaf-1.1.0.0.nupkg";
public const string SignedPackageLeaf2 = "TestSigned.leaf-2.2.0.0.nupkg";
+ public const string UnsignedPackageId = "TestUnsigned";
+ public const string UnsignedPackageVersion = "1.0.0";
public const string UnsignedPackage = "TestUnsigned.1.0.0.nupkg";
public const string Zip64Package = "Zip64Package.1.0.0.nupkg";
+ public const string RepoSignedPackageLeafId = "TestRepoSigned.leaf";
public const string RepoSignedPackageLeaf1 = "TestRepoSigned.leaf-1.1.0.0.nupkg";
+ public const string RepoSignedPackageLeaf1Version = "1.1.0.0";
+ public const string AuthorAndRepoSignedPackageLeafId = "TestAuthorAndRepoSigned.leaf";
public const string AuthorAndRepoSignedPackageLeaf1 = "TestAuthorAndRepoSigned.leaf-1.1.0.0.nupkg";
+ public const string AuthorAndRepoSignedPackageLeaf1Version = "1.1.0.0";
///
/// This is the SHA-256 thumbprint of the root CA certificate for the signing certificate of .
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestUtility.cs b/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestUtility.cs
new file mode 100644
index 000000000..df0a25a40
--- /dev/null
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/Support/TestUtility.cs
@@ -0,0 +1,67 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Moq;
+using NuGetGallery;
+
+namespace Validation.PackageSigning.ProcessSignature.Tests
+{
+ internal static class TestUtility
+ {
+ internal static void RequireUnsignedPackage(Mock corePackageService, string packageId)
+ {
+ var packageRegistration = new PackageRegistration()
+ {
+ Key = 1,
+ Id = packageId
+ };
+ var user = new User()
+ {
+ Key = 2
+ };
+
+ packageRegistration.Owners.Add(user);
+
+ corePackageService
+ .Setup(x => x.FindPackageRegistrationById(It.Is(id => id == packageId)))
+ .Returns(packageRegistration);
+ }
+
+ internal static void RequireSignedPackage(
+ Mock corePackageService,
+ string packageId,
+ string thumbprint = null)
+ {
+ var packageRegistration = new PackageRegistration()
+ {
+ Key = 1,
+ Id = packageId
+ };
+ var user = new User()
+ {
+ Key = 2
+ };
+ var certificate = new Certificate()
+ {
+ Key = 3,
+ Thumbprint = thumbprint ?? Guid.NewGuid().ToString()
+ };
+
+ user.UserCertificates.Add(new UserCertificate()
+ {
+ Key = 4,
+ CertificateKey = certificate.Key,
+ Certificate = certificate,
+ UserKey = user.Key,
+ User = user
+ });
+
+ packageRegistration.Owners.Add(user);
+
+ corePackageService
+ .Setup(x => x.FindPackageRegistrationById(It.Is(id => id == packageId)))
+ .Returns(packageRegistration);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Validation.PackageSigning.ProcessSignature.Tests/Validation.PackageSigning.ProcessSignature.Tests.csproj b/tests/Validation.PackageSigning.ProcessSignature.Tests/Validation.PackageSigning.ProcessSignature.Tests.csproj
index b2021513c..a157a4f50 100644
--- a/tests/Validation.PackageSigning.ProcessSignature.Tests/Validation.PackageSigning.ProcessSignature.Tests.csproj
+++ b/tests/Validation.PackageSigning.ProcessSignature.Tests/Validation.PackageSigning.ProcessSignature.Tests.csproj
@@ -47,6 +47,7 @@
+