private void SetSignatureContent( string packageId, Stream packageStream, byte[] signatureContent = null, Action <SignedCms> configuredSignedCms = null) { if (signatureContent == null) { signatureContent = new SignatureContent( SigningSpecifications.V1, NuGetHashAlgorithmName.SHA256, hashValue: "hash").GetBytes(); } using (var certificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null)) { TestUtility.RequireSignedPackage(_corePackageService, packageId, certificate.ComputeSHA256Thumbprint()); var contentInfo = new ContentInfo(signatureContent); var signedCms = new SignedCms(contentInfo); signedCms.ComputeSignature(new CmsSigner(certificate)); configuredSignedCms?.Invoke(signedCms); var fileContent = signedCms.Encode(); SetSignatureFileContent(packageStream, fileContent); } }
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 <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <Stream>())) .Returns(Task.CompletedTask) .Callback <string, string, Guid, Stream>((_, __, ___, 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 <NoDataValidationIssue>(result.Issues[0]); Assert.Equal(ValidationIssueCode.PackageIsNotSigned, issue.IssueCode); }
public async Task WhenRepositorySigningIsRequired_FailsValidationOfSignedPackagesWithNoRepositorySignature() { // Arrange _packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1); TestUtility.RequireSignedPackage( _corePackageService, TestResources.SignedPackageLeafId, TestResources.SignedPackageLeaf1Version, TestResources.Leaf1Thumbprint); _message = new SignatureValidationMessage( TestResources.SignedPackageLeafId, TestResources.SignedPackageLeaf1Version, new Uri($"https://unit.test/{TestResources.SignedPackageLeaf1.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: true); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Failed, PackageSigningStatus.Valid, shouldExtract: true); Assert.Empty(result.Issues); }
public async Task RejectsUntrustedSigningCertificate() { // Arrange 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, _packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); var issue = Assert.Single(result.Issues); var clientIssue = Assert.IsType <ClientSigningVerificationFailure>(issue); Assert.Equal("NU3012", clientIssue.ClientCode); Assert.Equal( "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.", clientIssue.ClientMessage); }
public async Task RejectsAuthorCounterSignatures() { // Arrange var packageStream = await GetSignedPackageStream1Async(); ModifySignatureContent( packageStream, configuredSignedCms: signedCms => { using (var counterCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null)) { TestUtility.RequireSignedPackage(_corePackageService, _message.PackageId, counterCertificate.ComputeSHA256Thumbprint()); var cmsSigner = new CmsSigner(counterCertificate); cmsSigner.SignedAttributes.Add(AttributeUtility.CreateCommitmentTypeIndication(SignatureType.Author)); signedCms.SignerInfos[0].ComputeCounterSignature(cmsSigner); } }); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); var issue = Assert.Single(result.Issues); Assert.Equal(ValidationIssueCode.AuthorCounterSignaturesNotSupported, issue.IssueCode); }
public async Task WhenRepositorySigningIsRequired_FailsValidationOfPackageWhoseRepositorySignatureIsStripped( string resourceName, string packageId, string packageVersion, PackageSigningStatus signingStatus, bool allowSignedPackage) { // Arrange _packageStream = TestResources.GetResourceStream(resourceName); if (allowSignedPackage) { TestUtility.RequireSignedPackage(_corePackageService, packageId, packageVersion, TestResources.Leaf1Thumbprint); } else { TestUtility.RequireUnsignedPackage(_corePackageService, packageId, packageVersion); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{TestResources.RepoSignedPackageLeafId.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: true); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Failed, signingStatus, shouldExtract: signingStatus == PackageSigningStatus.Valid); Assert.Empty(result.Issues); }
public async Task RejectsMultipleSignatures() { // Arrange SetSignatureContent( TestResources.SignedPackageLeafId, TestResources.GetResourceStream(TestResources.SignedPackageLeaf1), configuredSignedCms: signedCms => { using (var additionalCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null)) { TestUtility.RequireSignedPackage(_corePackageService, TestResources.SignedPackageLeafId, additionalCertificate.ComputeSHA256Thumbprint()); signedCms.ComputeSignature(new CmsSigner(additionalCertificate)); } }); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); var issue = Assert.Single(result.Issues); Assert.Equal(ValidationIssueCode.ClientSigningVerificationFailure, issue.IssueCode); var typedIssue = Assert.IsType <ClientSigningVerificationFailure>(issue); Assert.Equal("NU3009", typedIssue.ClientCode); Assert.Equal("The package signature file does not contain exactly one primary signature.", typedIssue.ClientMessage); }
public async Task RejectsSignedPackagesWithKnownCertificatesButFailedFullVerifyResult() { // Arrange _packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1); 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( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); Assert.Empty(result.Issues); }
public async Task RejectsSignedPackagesWithUnknownCertificates() { // Arrange _packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1); 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( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); Assert.Single(result.Issues); var issue = Assert.IsType <UnauthorizedCertificateFailure>(result.Issues[0]); Assert.Equal(ValidationIssueCode.PackageIsSignedWithUnauthorizedCertificate, issue.IssueCode); Assert.Equal(TestResources.Leaf2Sha1Thumbprint, issue.Sha1Thumbprint); }
public async Task AcceptsSignedPackagesWithUnknownCertificatesOnRevalidation() { // Arrange _packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1); TestUtility.RequireSignedPackage( _corePackageService, TestResources.SignedPackageLeafId, TestResources.SignedPackageLeaf1Version, TestResources.Leaf2Thumbprint, PackageStatus.Available); _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); }
public async Task RejectsPackagesWithFullVerificationErrors() { // Arrange _packageStream = TestResources.GetResourceStream(TestResources.SignedPackageLeaf1); TestUtility.RequireSignedPackage( _corePackageService, TestResources.SignedPackageLeafId, TestResources.SignedPackageLeaf1Version, TestResources.Leaf1Thumbprint); _fullVerifyResult = new VerifySignaturesResult( valid: false, signed: true, results: new[] { new InvalidSignaturePackageVerificationResult( SignatureVerificationStatus.Suspect, new[] { SignatureLog.Issue( fatal: true, code: NuGetLogCode.NU3008, message: "The package integrity check failed."), SignatureLog.Issue( fatal: false, code: NuGetLogCode.NU3016, message: "The package hash uses an unsupported hash algorithm."), SignatureLog.Issue( fatal: true, code: NuGetLogCode.NU3000, 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( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); Assert.Equal(2, result.Issues.Count); var issue1 = Assert.IsType <ClientSigningVerificationFailure>(result.Issues[0]); Assert.Equal("NU3008", issue1.ClientCode); Assert.Equal("The package integrity check failed.", issue1.ClientMessage); var issue2 = Assert.IsType <ClientSigningVerificationFailure>(result.Issues[1]); Assert.Equal("NU3000", issue2.ClientCode); Assert.Equal("Some other thing happened.", issue2.ClientMessage); }
public async Task WhenStripsValidRepositorySignature_StripsAndAcceptsRepositorySignatureWhenRepositorySignatureIsNotRequired( string resourceName, string packageId, string packageVersion, PackageSigningStatus expectedSigningStatus) { // Arrange _configuration.StripValidRepositorySignatures = true; _configuration.AllowedRepositorySigningCertificates = new List <string> { TestResources.Leaf1Thumbprint, TestResources.Leaf2Thumbprint }; _packageStream = TestResources.GetResourceStream(resourceName); if (resourceName == TestResources.RepoSignedPackageLeaf1) { TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.RepoSignedPackageLeafId, TestResources.RepoSignedPackageLeaf1Version); } if (resourceName == TestResources.AuthorAndRepoSignedPackageLeaf1) { TestUtility.RequireSignedPackage(_corePackageService, TestResources.AuthorAndRepoSignedPackageLeafId, TestResources.AuthorAndRepoSignedPackageLeaf1Version, TestResources.Leaf1Thumbprint); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{resourceName.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: false); Stream uploadedStream = null; _packageFileService .Setup(x => x.SaveAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <Stream>())) .Returns(Task.CompletedTask) .Callback <string, string, Guid, Stream>((_, __, ___, s) => uploadedStream = s); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Succeeded, expectedSigningStatus, _nupkgUri); Assert.Empty(result.Issues); _packageFileService.Verify( x => x.SaveAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId, It.IsAny <Stream>()), Times.Once); _packageFileService.Verify( x => x.GetReadAndDeleteUriAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId), Times.Once); Assert.IsType <FileStream>(uploadedStream); Assert.Throws <ObjectDisposedException>(() => uploadedStream.Length); }
public async Task AcceptsTrustedSigningCertificateWithUnavailableRevocation() { // Arrange var testServer = await _fixture.GetTestServerAsync(); var rootCa = CertificateAuthority.Create(testServer.Url); var intermediateCa = rootCa.CreateIntermediateCertificateAuthority(); var rootCertificate = new X509Certificate2(rootCa.Certificate.GetEncoded()); var signingCertificate = _fixture.CreateSigningCertificate(intermediateCa); using (var trust = new TrustedTestCert <X509Certificate2>( rootCertificate, x => x, StoreName.Root, StoreLocation.LocalMachine)) { byte[] packageBytes; using (testServer.RegisterResponders(intermediateCa)) { packageBytes = await _fixture.GenerateSignedPackageBytesAsync( TestResources.SignedPackageLeaf1, signingCertificate, await _fixture.GetTimestampServiceUrlAsync(), _output); } // Wait one second for the OCSP response cached by the operating system during signing to get stale. // This can be mitigated by leaving the OCSP unavailable during signing once this work item is done: // https://github.com/NuGet/Home/issues/6508 await Task.Delay(TimeSpan.FromSeconds(1)); TestUtility.RequireSignedPackage(_corePackageService, TestResources.SignedPackageLeafId, signingCertificate.ComputeSHA256Thumbprint()); _packageStream = new MemoryStream(packageBytes); SignatureValidatorResult result; using (testServer.RegisterResponders(intermediateCa, addOcsp: false)) { // Act result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _token); } // Assert VerifyPackageSigningStatus(result, ValidationStatus.Succeeded, PackageSigningStatus.Valid); Assert.Empty(result.Issues); var allMessages = string.Join(Environment.NewLine, _logger.Messages); Assert.Contains("NU3018: The revocation function was unable to check revocation because the revocation server was offline.", allMessages); Assert.Contains("NU3018: The revocation function was unable to check revocation for the certificate.", allMessages); } }
public async Task RejectsUntrustedTimestampingCertificate() { // Arrange var testServer = await _fixture.GetTestServerAsync(); var untrustedRootCa = CertificateAuthority.Create(testServer.Url); var untrustedRootCertficate = new X509Certificate2(untrustedRootCa.Certificate.GetEncoded()); var timestampService = TimestampService.Create(untrustedRootCa); using (testServer.RegisterDefaultResponders(timestampService)) { byte[] packageBytes; using (var temporaryTrust = new TrustedTestCert <X509Certificate2>( untrustedRootCertficate, x => x, StoreName.Root, StoreLocation.LocalMachine)) { packageBytes = await _fixture.GenerateSignedPackageBytesAsync( TestResources.SignedPackageLeaf1, await _fixture.GetSigningCertificateAsync(), timestampService.Url, _output); } 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, _packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); var issue = Assert.Single(result.Issues); var clientIssue = Assert.IsType <ClientSigningVerificationFailure>(issue); Assert.Equal("NU3028", clientIssue.ClientCode); Assert.Equal( "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.", clientIssue.ClientMessage); } }
public async Task StripsAndAcceptsPackagesWithRepositorySignatures( string resourceName, string packageId, string packageVersion, PackageSigningStatus signingStatus, bool allowSignedPackage) { // Arrange _packageStream = TestResources.GetResourceStream(resourceName); 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 .Setup(x => x.SaveAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <Stream>())) .Returns(Task.CompletedTask) .Callback <string, string, Guid, Stream>((_, __, ___, s) => uploadedStream = s); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Succeeded, signingStatus, _nupkgUri); Assert.Empty(result.Issues); _packageFileService.Verify( x => x.SaveAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId, It.IsAny <Stream>()), Times.Once); _packageFileService.Verify( x => x.GetReadAndDeleteUriAsync(_message.PackageId, _message.PackageVersion, _message.ValidationId), Times.Once); Assert.IsType <FileStream>(uploadedStream); Assert.Throws <ObjectDisposedException>(() => uploadedStream.Length); }
public async Task WhenStripsValidRepositorySignature_AcceptsRepositorySignatureWhenRepositorySignatureIsRequired( string resourceName, string packageId, string packageVersion, PackageSigningStatus expectedSigningStatus) { // Arrange _configuration.StripValidRepositorySignatures = true; _configuration.AllowedRepositorySigningCertificates = new List <string> { TestResources.Leaf1Thumbprint, TestResources.Leaf2Thumbprint }; _packageStream = TestResources.GetResourceStream(resourceName); if (resourceName == TestResources.RepoSignedPackageLeaf1) { TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.RepoSignedPackageLeafId, TestResources.RepoSignedPackageLeaf1Version); } if (resourceName == TestResources.AuthorAndRepoSignedPackageLeaf1) { TestUtility.RequireSignedPackage(_corePackageService, TestResources.AuthorAndRepoSignedPackageLeafId, TestResources.AuthorAndRepoSignedPackageLeaf1Version, TestResources.Leaf1Thumbprint); } _message = new SignatureValidationMessage( packageId, packageVersion, new Uri($"https://unit.test/{resourceName.ToLowerInvariant()}"), Guid.NewGuid(), requireRepositorySignature: true); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _cancellationToken); // Assert Validate(result, ValidationStatus.Succeeded, expectedSigningStatus); Assert.Empty(result.Issues); }
public async Task RejectsMutuallyExclusiveCounterSignaturesCommitmentTypes(SignatureType[] counterSignatureTypes) { // Arrange var packageStream = await GetSignedPackageStream1Async(); ModifySignatureContent( packageStream, configuredSignedCms: signedCms => { using (var counterCertificate = SigningTestUtility.GenerateCertificate(subjectName: null, modifyGenerator: null)) { TestUtility.RequireSignedPackage(_corePackageService, _message.PackageId, counterCertificate.ComputeSHA256Thumbprint()); var cmsSigner = new CmsSigner(counterCertificate); foreach (var type in counterSignatureTypes) { cmsSigner.SignedAttributes.Add(AttributeUtility.CreateCommitmentTypeIndication(type)); } signedCms.SignerInfos[0].ComputeCounterSignature(cmsSigner); } }); // Act var result = await _target.ValidateAsync( _packageKey, _packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Failed, PackageSigningStatus.Invalid); var issue = Assert.Single(result.Issues); Assert.Equal(ValidationIssueCode.ClientSigningVerificationFailure, issue.IssueCode); var typedIssue = Assert.IsType <ClientSigningVerificationFailure>(issue); Assert.Equal("NU3000", typedIssue.ClientCode); Assert.Equal("The commitment-type-indication attribute contains an invalid combination of values.", typedIssue.ClientMessage); }
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); }
public async Task <MemoryStream> GetSignedPackageStream1Async() { TestUtility.RequireSignedPackage(_corePackageService, _message.PackageId, await _fixture.GetSigningCertificateThumbprintAsync()); return(await _fixture.GetSignedPackageStream1Async(_output)); }