public async Task SignAsync_WhenRepositoryCountersigningPrimarySignature_SucceedsAsync() { using (var test = await Test.CreateAsync(_testFixture.TrustedTestCertificate.Source.Cert)) { await SigningUtility.SignAsync(test.Options, test.AuthorRequest, CancellationToken.None); using (var package = new PackageArchiveReader(test.Options.OutputPackageStream)) { var primarySignature = await package.GetPrimarySignatureAsync(CancellationToken.None); Assert.IsType <AuthorPrimarySignature>(primarySignature); } using (var countersignatureOptions = SigningOptions.CreateFromFilePaths( test.OutputFile.FullName, test.GetNewTempFilePath(), overwrite: false, signatureProvider: new X509SignatureProvider(timestampProvider: null), logger: NullLogger.Instance)) { await SigningUtility.SignAsync(countersignatureOptions, test.RepositoryRequest, CancellationToken.None); var isRepositoryCountersigned = await SignedArchiveTestUtility.IsRepositoryCountersignedAsync(countersignatureOptions.OutputPackageStream); Assert.True(isRepositoryCountersigned); } } }
public async Task SignAsync_WhenRepositoryCountersigningRepositorySignedPackage_ThrowsAsync() { using (var test = await Test.CreateAsync(_testFixture.TrustedTestCertificate.Source.Cert)) { await SigningUtility.SignAsync(test.Options, test.RepositoryRequest, CancellationToken.None); using (var package = new PackageArchiveReader(test.Options.OutputPackageStream)) { var primarySignature = await package.GetPrimarySignatureAsync(CancellationToken.None); Assert.IsType <RepositoryPrimarySignature>(primarySignature); } using (var countersignatureOptions = SigningOptions.CreateFromFilePaths( test.OutputFile.FullName, test.GetNewTempFilePath(), overwrite: false, signatureProvider: new X509SignatureProvider(timestampProvider: null), logger: NullLogger.Instance)) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(countersignatureOptions, test.RepositoryRequest, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3033, exception.Code); Assert.Contains("A repository primary signature must not have a repository countersignature", exception.Message); } } }
private static async Task <MemoryStream> CreateSignedPackageAsync( X509Certificate2 certificate, Stream unsignedPackage = null) { if (unsignedPackage == null) { var packageContext = new SimpleTestPackageContext(); unsignedPackage = packageContext.CreateAsStream(); } var signatureProvider = new X509SignatureProvider(timestampProvider: null); var overwrite = true; using (var request = new AuthorSignPackageRequest(certificate, HashAlgorithmName.SHA256)) using (var outputPackageStream = new MemoryStream()) using (var options = new SigningOptions( new Lazy <Stream>(() => unsignedPackage), new Lazy <Stream>(() => outputPackageStream), overwrite, signatureProvider, NullLogger.Instance)) { await SigningUtility.SignAsync(options, request, CancellationToken.None); var isSigned = await SignedArchiveTestUtility.IsSignedAsync(options.OutputPackageStream); Assert.True(isSigned); return(new MemoryStream(outputPackageStream.ToArray())); } }
public async Task SignAsync_WhenChainBuildingFails_ThrowsAsync() { var package = new SimpleTestPackageContext(); using (var packageStream = await package.CreateAsStreamAsync()) using (var test = SignTest.Create( _fixture.GetExpiredCertificate(), HashAlgorithmName.SHA256, packageStream.ToArray(), new X509SignatureProvider(timestampProvider: null))) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3018, exception.Code); Assert.Equal("Certificate chain validation failed.", exception.Message); Assert.Equal(1, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); Assert.Contains(test.Logger.LogMessages, message => message.Code == NuGetLogCode.NU3018 && message.Level == LogLevel.Error && message.Message == "A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file."); Assert.Contains(test.Logger.LogMessages, message => message.Code == NuGetLogCode.NU3018 && message.Level == LogLevel.Warning && message.Message == "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider."); } }
public async Task <byte[]> GenerateSignedPackageBytesAsync( Stream inputPackageStream, SignPackageRequest request, Uri timestampUri, ITestOutputHelper output) { var testLogger = new TestLogger(output); var timestampProvider = new Rfc3161TimestampProvider(timestampUri); var signatureProvider = new X509SignatureProvider(timestampProvider); using (var outputPackageStream = new MemoryStream()) { await SigningUtility.SignAsync( new SigningOptions( inputPackageStream : new Lazy <Stream>(() => inputPackageStream), outputPackageStream : new Lazy <Stream>(() => outputPackageStream), overwrite : true, signatureProvider : signatureProvider, logger : testLogger), request, CancellationToken.None); return(outputPackageStream.ToArray()); } }
public async Task SignAsync_WhenCancellationTokenIsCancelled_ThrowsAsync() { using (var test = SignTest.Create(new X509Certificate2(), HashAlgorithmName.SHA256)) { await Assert.ThrowsAsync <OperationCanceledException>( () => SigningUtility.SignAsync(test.Options, test.Request, new CancellationToken(canceled: true))); } }
public async Task <bool> SignAsync(string packagePath, string outputPath, string timestampUrl, Uri v3ServiceIndex, IReadOnlyList <string> packageOwners, SignatureType signatureType, HashAlgorithmName signatureHashAlgorithm, HashAlgorithmName timestampHashAlgorithm, bool overwrite, X509Certificate2 publicCertificate, System.Security.Cryptography.RSA rsa, CancellationToken cancellationToken = default) { var packagesToSign = LocalFolderUtility.ResolvePackageFromPath(packagePath); var signatureProvider = new KeyVaultSignatureProvider(rsa, new Rfc3161TimestampProvider(new Uri(timestampUrl))); SignPackageRequest request = null; if (signatureType == SignatureType.Author) { request = new AuthorSignPackageRequest(publicCertificate, signatureHashAlgorithm, timestampHashAlgorithm); } else if (signatureType == SignatureType.Repository) { request = new RepositorySignPackageRequest(publicCertificate, signatureHashAlgorithm, timestampHashAlgorithm, v3ServiceIndex, packageOwners); } else { throw new ArgumentOutOfRangeException(nameof(signatureType)); } string originalPackageCopyPath = null; foreach (var package in packagesToSign) { cancellationToken.ThrowIfCancellationRequested(); logger.LogInformation($"{nameof(SignAsync)} [{package}]: Begin Signing {Path.GetFileName(package)}"); try { originalPackageCopyPath = CopyPackage(package); using var options = SigningOptions.CreateFromFilePaths(originalPackageCopyPath, outputPath, overwrite, signatureProvider, new NuGetLogger(logger, package)); await SigningUtility.SignAsync(options, request, cancellationToken); } catch (Exception e) { logger.LogError(e, e.Message); return(false); } finally { try { FileUtility.Delete(originalPackageCopyPath); } catch { } logger.LogInformation($"{nameof(SignAsync)} [{package}]: End Signing {Path.GetFileName(package)}"); } } return(true); }
public async Task SignAsync_WhenPackageIsZip64_ThrowsAsync() { using (var test = SignTest.Create( _fixture.GetDefaultCertificate(), HashAlgorithmName.SHA256, SigningTestUtility.GetResourceBytes("CentralDirectoryHeaderWithZip64ExtraField.zip"))) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3006, exception.Code); Assert.Equal("Signed Zip64 packages are not supported.", exception.Message); } }
public async Task SignAsync_AddsPackageRepositorySignatureAsync() { using (var test = await Test.CreateAsync(_testFixture.TrustedTestCertificate.Source.Cert)) { await SigningUtility.SignAsync(test.Options, test.RepositoryRequest, CancellationToken.None); using (var package = new PackageArchiveReader(test.Options.OutputPackageStream)) { var primarySignature = await package.GetPrimarySignatureAsync(CancellationToken.None); Assert.IsType <RepositoryPrimarySignature>(primarySignature); } } }
public async Task SignAsync_WhenCertificateSignatureAlgorithmIsUnsupported_ThrowsAsync() { using (var certificate = SigningTestUtility.GenerateCertificate( "test", generator => { }, "SHA256WITHRSAANDMGF1")) using (var test = SignTest.Create(certificate, HashAlgorithmName.SHA256)) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3013, exception.Code); Assert.Contains("The signing certificate has an unsupported signature algorithm.", exception.Message); } }
public async Task SignAsync_WhenCertificatePublicKeyLengthIsUnsupported_ThrowsAsync() { using (var certificate = SigningTestUtility.GenerateCertificate( "test", generator => { }, publicKeyLength: 1024)) using (var test = SignTest.Create(certificate, HashAlgorithmName.SHA256)) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3014, exception.Code); Assert.Contains("The signing certificate does not meet a minimum public key length requirement.", exception.Message); } }
public static async Task CreateSignedPackageAsync( SignPackageRequest request, Stream packageReadStream, Stream packageWriteStream) { using (var signedPackage = new SignedPackageArchive(packageReadStream, packageWriteStream)) using (var options = new SigningOptions( new Lazy <Stream>(() => packageReadStream), new Lazy <Stream>(() => packageWriteStream), overwrite: false, signatureProvider: new X509SignatureProvider(timestampProvider: null), logger: NullLogger.Instance)) { await SigningUtility.SignAsync(options, request, CancellationToken.None); } }
public async Task SignAsync_WithExpiredCertificate_ThrowsAsync() { using (var test = new Test(_testFixture.TrustedTestCertificateExpired.Source.Cert)) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.AuthorRequest, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3018, exception.Code); Assert.Contains("Certificate chain validation failed.", exception.Message); var isSigned = await SignedArchiveTestUtility.IsSignedAsync(test.Options.InputPackageStream); Assert.False(isSigned); Assert.False(test.OutputFile.Exists); } }
public async Task SignAsync_WithNotYetValidCertificate_ThrowsAsync() { using (var test = await Test.CreateAsync(_testFixture.TrustedTestCertificateNotYetValid.Source.Cert)) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.AuthorRequest, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3017, exception.Code); Assert.Contains("The signing certificate is not yet valid", exception.Message); var isSigned = await SignedArchiveTestUtility.IsSignedAsync(test.Options.InputPackageStream); Assert.False(isSigned); Assert.False(test.OutputFile.Exists); } }
public async Task SignAsync_WithUntrustedSelfSignedCertificate_SucceedsAsync() { using (var packageStream = new SimpleTestPackageContext().CreateAsStream()) using (var test = SignTest.Create( _fixture.GetDefaultCertificate(), HashAlgorithmName.SHA256, packageStream.ToArray(), new X509SignatureProvider(timestampProvider: null))) { await SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None); Assert.True(await SignedArchiveTestUtility.IsSignedAsync(test.Options.OutputPackageStream)); Assert.Equal(0, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); Assert.Equal(1, test.Logger.Messages.Count()); Assert.True(test.Logger.Messages.Contains("A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.")); } }
public async Task SignAsync_WhenPackageEntryCountWouldRequireZip64_FailsAsync() { const ushort desiredFileCount = 0xFFFF - 1; var package = new SimpleTestPackageContext(); var requiredFileCount = desiredFileCount - package.Files.Count; for (var i = 0; i < requiredFileCount - 1 /*nuspec*/; ++i) { package.AddFile(i.ToString()); } using (var packageStream = await package.CreateAsStreamAsync()) { using (var zipArchive = new ZipArchive(packageStream, ZipArchiveMode.Read, leaveOpen: true)) { // Sanity check before testing. Assert.Equal(desiredFileCount, zipArchive.Entries.Count()); } packageStream.Position = 0; using (var test = SignTest.Create( _fixture.GetDefaultCertificate(), HashAlgorithmName.SHA256, packageStream.ToArray(), new X509SignatureProvider(timestampProvider: null))) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3039, exception.Code); Assert.Equal("The package cannot be signed as it would require the Zip64 format.", exception.Message); Assert.Equal(0, test.Options.OutputPackageStream.Length); Assert.Equal(0, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); Assert.Equal(1, test.Logger.Messages.Count()); Assert.True(test.Logger.Messages.Contains("A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.")); } } }
public async Task SignAsync_WhenRepositoryCountersigningRepositoryCountersignedPackage_ThrowsAsync() { using (var test = await Test.CreateAsync(_testFixture.TrustedTestCertificate.Source.Cert)) { await SigningUtility.SignAsync(test.Options, test.AuthorRequest, CancellationToken.None); using (var package = new PackageArchiveReader(test.Options.OutputPackageStream)) { var isSigned = await SignedArchiveTestUtility.IsSignedAsync(test.Options.OutputPackageStream); Assert.True(isSigned); } var countersignedPackageOutputPath = test.GetNewTempFilePath(); using (var countersignatureOptions = SigningOptions.CreateFromFilePaths( test.OutputFile.FullName, countersignedPackageOutputPath, overwrite: false, signatureProvider: new X509SignatureProvider(timestampProvider: null), logger: NullLogger.Instance)) { await SigningUtility.SignAsync(countersignatureOptions, test.RepositoryRequest, CancellationToken.None); var isRepositoryCountersigned = await SignedArchiveTestUtility.IsRepositoryCountersignedAsync(countersignatureOptions.OutputPackageStream); Assert.True(isRepositoryCountersigned); } using (var countersignatureOptions = SigningOptions.CreateFromFilePaths( countersignedPackageOutputPath, test.GetNewTempFilePath(), overwrite: false, signatureProvider: new X509SignatureProvider(timestampProvider: null), logger: NullLogger.Instance)) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(countersignatureOptions, test.RepositoryRequest, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3032, exception.Code); Assert.Contains("The package already contains a repository countersignature", exception.Message); } } }
/// <summary> /// Sign and timestamp a package for test purposes. /// This method timestamps a package and should only be used with tests marked with [CIOnlyFact] /// </summary> private static async Task SignAndTimeStampPackageAsync( TestLogger testLogger, string inputPackagePath, string outputPackagePath, Uri timestampService, AuthorSignPackageRequest request) { var testSignatureProvider = new X509SignatureProvider(new Rfc3161TimestampProvider(timestampService)); var overwrite = false; using (var options = SigningOptions.CreateFromFilePaths( inputPackagePath, outputPackagePath, overwrite, testSignatureProvider, testLogger)) { await SigningUtility.SignAsync(options, request, CancellationToken.None); } }
/// <summary> /// Sign a package for test purposes. /// This does not timestamp a signature and can be used outside corp network. /// </summary> private static async Task SignPackageAsync(TestLogger testLogger, X509Certificate2 certificate, string inputPackagePath, string outputPackagePath) { #if IS_DESKTOP var testSignatureProvider = new X509SignatureProvider(timestampProvider: null); using (var cert = new X509Certificate2(certificate)) using (var request = new AuthorSignPackageRequest(cert, HashAlgorithmName.SHA256)) { const bool overwrite = false; using (var options = SigningOptions.CreateFromFilePaths( inputPackagePath, outputPackagePath, overwrite, testSignatureProvider, testLogger)) { await SigningUtility.SignAsync(options, request, CancellationToken.None); } } #endif }
public async Task SignAsync_WithUntrustedSelfSignedCertificate_SucceedsAsync() { var package = new SimpleTestPackageContext(); using (var packageStream = await package.CreateAsStreamAsync()) using (var test = SignTest.Create( _fixture.GetDefaultCertificate(), HashAlgorithmName.SHA256, packageStream.ToArray(), new X509SignatureProvider(timestampProvider: null))) { await SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None); Assert.True(await SignedArchiveTestUtility.IsSignedAsync(test.Options.OutputPackageStream)); Assert.Equal(0, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); Assert.Equal(1, test.Logger.Messages.Count()); SigningTestUtility.AssertUntrustedRoot(test.Logger.LogMessages, LogLevel.Warning); } }
public async Task <bool> SignAsync(string packagePath, string outputPath, string timestampUrl, HashAlgorithmName signatureHashAlgorithm, HashAlgorithmName timestampHashAlgorithm, bool overwrite, X509Certificate2 publicCertificate, System.Security.Cryptography.RSA rsa) { var fileName = Path.GetFileName(packagePath); logger.LogInformation($"{nameof(SignAsync)} [{fileName}]: Begin Signing {packagePath}"); var signatureProvider = new KeyVaultSignatureProvider(rsa, new Rfc3161TimestampProvider(new Uri(timestampUrl))); var request = new AuthorSignPackageRequest(publicCertificate, signatureHashAlgorithm, timestampHashAlgorithm); string originalPackageCopyPath = null; try { originalPackageCopyPath = CopyPackage(packagePath); using (var options = SigningOptions.CreateFromFilePaths(originalPackageCopyPath, outputPath, overwrite, signatureProvider, new NuGetLogger(logger, fileName))) { await SigningUtility.SignAsync(options, request, CancellationToken.None); } } catch (Exception e) { logger.LogError(e, e.Message); return(false); } finally { try { FileUtility.Delete(originalPackageCopyPath); } catch { } logger.LogInformation($"{nameof(SignAsync)} [{fileName}]: End Signing {packagePath}"); } return(true); }
public async Task SignAsync_WhenChainBuildingFails_ThrowsAsync() { var package = new SimpleTestPackageContext(); using (var packageStream = await package.CreateAsStreamAsync()) using (var test = SignTest.Create( _fixture.GetExpiredCertificate(), HashAlgorithmName.SHA256, packageStream.ToArray(), new X509SignatureProvider(timestampProvider: null))) { var exception = await Assert.ThrowsAsync <SignatureException>( () => SigningUtility.SignAsync(test.Options, test.Request, CancellationToken.None)); Assert.Equal(NuGetLogCode.NU3018, exception.Code); Assert.Equal("Certificate chain validation failed.", exception.Message); Assert.Equal(1, test.Logger.Errors); Assert.Equal(1, test.Logger.Warnings); SigningTestUtility.AssertNotTimeValid(test.Logger.LogMessages, LogLevel.Error); SigningTestUtility.AssertUntrustedRoot(test.Logger.LogMessages, LogLevel.Warning); } }
public async Task <int> ExecuteCommandAsync( IEnumerable <string> packagesToSign, SignPackageRequest signPackageRequest, string timestamper, ILogger logger, string outputDirectory, bool overwrite, CancellationToken token) { var success = true; try { SigningUtility.Verify(signPackageRequest, logger); } catch (Exception e) { success = false; ExceptionUtilities.LogException(e, logger); } if (success) { var signatureProvider = GetSignatureProvider(timestamper); foreach (var packagePath in packagesToSign) { // Set the output of the signing operation to a temp file because signing cannot be done in place. var tempPackageFile = new FileInfo(Path.GetTempFileName()); try { string outputPath; if (string.IsNullOrEmpty(outputDirectory)) { outputPath = packagePath; } else { outputPath = Path.Combine(outputDirectory, Path.GetFileName(packagePath)); } using (var options = SigningOptions.CreateFromFilePaths( packagePath, tempPackageFile.FullName, overwrite, signatureProvider, logger)) { await SigningUtility.SignAsync(options, signPackageRequest, token); } if (tempPackageFile.Length > 0) { FileUtility.Replace(tempPackageFile.FullName, outputPath); } else { throw new SignatureException(Strings.Error_UnableToSignPackage); } } catch (Exception e) { success = false; ExceptionUtilities.LogException(e, logger); } finally { FileUtility.Delete(tempPackageFile.FullName); } } } if (success) { logger.LogInformation(Strings.SignCommandSuccess); } return(success ? 0 : 1); }