diff --git a/NuGetKeyVaultSignTool.Core/NuGetKeyVaultSignTool.Core.csproj b/NuGetKeyVaultSignTool.Core/NuGetKeyVaultSignTool.Core.csproj index 74ee5e8..1921a24 100644 --- a/NuGetKeyVaultSignTool.Core/NuGetKeyVaultSignTool.Core.csproj +++ b/NuGetKeyVaultSignTool.Core/NuGetKeyVaultSignTool.Core.csproj @@ -9,6 +9,7 @@ + diff --git a/NuGetKeyVaultSignTool.Core/SignCommand.cs b/NuGetKeyVaultSignTool.Core/SignCommand.cs index e4a5a81..3f1a0bc 100644 --- a/NuGetKeyVaultSignTool.Core/SignCommand.cs +++ b/NuGetKeyVaultSignTool.Core/SignCommand.cs @@ -10,6 +10,7 @@ using NuGet.Common; using NuGet.Packaging.Signing; using ILogger = Microsoft.Extensions.Logging.ILogger; +using NuGet.Protocol; namespace NuGetKeyVaultSignTool { @@ -76,38 +77,42 @@ async Task Authenticate(string authority, string resource, string scope) public async Task 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 packagesToSign = LocalFolderUtility.ResolvePackageFromPath(packagePath); + var signatureProvider = new KeyVaultSignatureProvider(rsa, new Rfc3161TimestampProvider(new Uri(timestampUrl))); var request = new AuthorSignPackageRequest(publicCertificate, signatureHashAlgorithm, timestampHashAlgorithm); string originalPackageCopyPath = null; - try + foreach (var package in packagesToSign) { - originalPackageCopyPath = CopyPackage(packagePath); - - using (var options = SigningOptions.CreateFromFilePaths(originalPackageCopyPath, outputPath, overwrite, signatureProvider, new NuGetLogger(logger, fileName))) + logger.LogInformation($"{nameof(SignAsync)} [{package}]: Begin Signing {Path.GetFileName(package)}"); + try { - await SigningUtility.SignAsync(options, request, CancellationToken.None); + originalPackageCopyPath = CopyPackage(package); + + using (var options = SigningOptions.CreateFromFilePaths(originalPackageCopyPath, package, overwrite, signatureProvider, new NuGetLogger(logger, package))) + { + await SigningUtility.SignAsync(options, request, CancellationToken.None); + } } - } - catch (Exception e) - { - logger.LogError(e, e.Message); - return false; - } - finally - { - try + catch (Exception e) { - FileUtility.Delete(originalPackageCopyPath); + logger.LogError(e, e.Message); + return false; } - catch + finally { + try + { + FileUtility.Delete(originalPackageCopyPath); + } + catch + { + } + + logger.LogInformation($"{nameof(SignAsync)} [{package}]: End Signing {Path.GetFileName(package)}"); } - - logger.LogInformation($"{nameof(SignAsync)} [{fileName}]: End Signing {packagePath}"); } return true; diff --git a/NuGetKeyVaultSignTool.Core/VerifyCommand.cs b/NuGetKeyVaultSignTool.Core/VerifyCommand.cs index 958a3a0..2a61525 100644 --- a/NuGetKeyVaultSignTool.Core/VerifyCommand.cs +++ b/NuGetKeyVaultSignTool.Core/VerifyCommand.cs @@ -13,13 +13,14 @@ using NuGet.Packaging.Signing; using Microsoft.Extensions.Logging; using ILogger = Microsoft.Extensions.Logging.ILogger; +using NuGet.Protocol; namespace NuGetKeyVaultSignTool { public class VerifyCommand { readonly ILogger logger; - + public VerifyCommand(ILogger logger) { this.logger = logger; @@ -37,44 +38,50 @@ public async Task VerifyAsync(string file, StringBuilder buffer) throw new ArgumentNullException(nameof(buffer)); } - + var trustProviders = new ISignatureVerificationProvider[] { new IntegrityVerificationProvider(), new SignatureTrustAndValidityVerificationProvider() }; var verifier = new PackageSignatureVerifier(trustProviders); + + var allPackagesVerified = true; + try { var result = 0; - using (var package = new PackageArchiveReader(file)) - { - var verificationResult = await verifier.VerifySignaturesAsync(package, SignedPackageVerifierSettings.GetVerifyCommandDefaultPolicy(), CancellationToken.None); - + var packagesToVerify = LocalFolderUtility.ResolvePackageFromPath(file); - if (verificationResult.IsValid) - { - return verificationResult.IsValid; - } - else + foreach (var packageFile in packagesToVerify) + { + using (var package = new PackageArchiveReader(packageFile)) { - var logMessages = verificationResult.Results.SelectMany(p => p.Issues).Select(p => p .AsRestoreLogMessage()).ToList(); - foreach (var msg in logMessages) + var verificationResult = await verifier.VerifySignaturesAsync(package, SignedPackageVerifierSettings.GetVerifyCommandDefaultPolicy(), CancellationToken.None); + + if (verificationResult.IsValid) { - buffer.AppendLine(msg.Message); + allPackagesVerified = true; } - if (logMessages.Any(m => m.Level >= NuGet.Common.LogLevel.Warning)) + else { - var errors = logMessages.Where(m => m.Level == NuGet.Common.LogLevel.Error).Count(); - var warnings = logMessages.Where(m => m.Level == NuGet.Common.LogLevel.Warning).Count(); + var logMessages = verificationResult.Results.SelectMany(p => p.Issues).Select(p => p.AsRestoreLogMessage()).ToList(); + foreach (var msg in logMessages) + { + buffer.AppendLine(msg.Message); + } + if (logMessages.Any(m => m.Level >= NuGet.Common.LogLevel.Warning)) + { + var errors = logMessages.Where(m => m.Level == NuGet.Common.LogLevel.Error).Count(); + var warnings = logMessages.Where(m => m.Level == NuGet.Common.LogLevel.Warning).Count(); - buffer.AppendLine($"Finished with {errors} errors and {warnings} warnings."); + buffer.AppendLine($"Finished with {errors} errors and {warnings} warnings."); - result = errors; + result = errors; + } + allPackagesVerified = false; } - return false; } - } } catch (Exception e) @@ -82,6 +89,8 @@ public async Task VerifyAsync(string file, StringBuilder buffer) logger.LogError(e, e.Message); return false; } + + return allPackagesVerified; } } } diff --git a/NuGetKeyVaultSignTool/Program.cs b/NuGetKeyVaultSignTool/Program.cs index f57ee19..55bd847 100644 --- a/NuGetKeyVaultSignTool/Program.cs +++ b/NuGetKeyVaultSignTool/Program.cs @@ -32,9 +32,9 @@ internal static int Main(string[] args) var packagePath = signConfiguration.Argument("packagePath", "Package to sign."); var outputPath = signConfiguration.Option("-o | --output", "The output file. If omitted, overwrites input.", CommandOptionType.SingleValue); var force = signConfiguration.Option("-f | --force", "Overwrites a sigature if it exists.", CommandOptionType.NoValue); - var fileDigestAlgorithm = signConfiguration.Option("-fd | --file-digest", "The digest algorithm to hash the file with.", CommandOptionType.SingleValue); + var fileDigestAlgorithm = signConfiguration.Option("-fd | --file-digest", "The digest algorithm to hash the file with. Default option is sha256", CommandOptionType.SingleValue); var rfc3161TimeStamp = signConfiguration.Option("-tr | --timestamp-rfc3161", "Specifies the RFC 3161 timestamp server's URL. If this option (or -t) is not specified, the signed file will not be timestamped.", CommandOptionType.SingleValue); - var rfc3161Digest = signConfiguration.Option("-td | --timestamp-digest", "Used with the -tr switch to request a digest algorithm used by the RFC 3161 timestamp server.", CommandOptionType.SingleValue); + var rfc3161Digest = signConfiguration.Option("-td | --timestamp-digest", "Used with the -tr switch to request a digest algorithm used by the RFC 3161 timestamp server. Default option is sha256", CommandOptionType.SingleValue); var signatureType = signConfiguration.Option("-st | --signature-type", "The signature type (omit for author, default. Only author is supported currently).", CommandOptionType.SingleValue); var azureKeyVaultUrl = signConfiguration.Option("-kvu | --azure-key-vault-url", "The URL to an Azure Key Vault.", CommandOptionType.SingleValue); var azureKeyVaultClientId = signConfiguration.Option("-kvi | --azure-key-vault-client-id", "The Client ID to authenticate to the Azure Key Vault.", CommandOptionType.SingleValue); @@ -46,7 +46,7 @@ internal static int Main(string[] args) { if (string.IsNullOrWhiteSpace(packagePath.Value)) { - logger.LogError("All arguments are required"); + logger.LogError("Path to file(s) to sign are requried"); return -1; } @@ -122,12 +122,6 @@ internal static int Main(string[] args) return -1; } - if (!File.Exists(file.Value)) - { - application.Error.WriteLine("File does not exist"); - return -1; - } - var cmd = new VerifyCommand(logger); var buffer = new StringBuilder(); var result = await cmd.VerifyAsync(file.Value, buffer);