Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fixes #12 by using NuGet LocalFolderUtility to parse out wildcard inp… #13

Merged
merged 2 commits into from
May 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.3" />
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="4.5.1" />
<PackageReference Include="NuGet.Packaging" Version="5.2.0-xprivate.60006" />
<PackageReference Include="NuGet.Protocol" Version="5.0.0" />
clairernovotny marked this conversation as resolved.
Show resolved Hide resolved
<PackageReference Include="Portable.BouncyCastle" Version="1.8.5" />
<PackageReference Include="RSAKeyVaultProvider" Version="1.1.22" />
</ItemGroup>
Expand Down
45 changes: 25 additions & 20 deletions NuGetKeyVaultSignTool.Core/SignCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using NuGet.Common;
using NuGet.Packaging.Signing;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using NuGet.Protocol;

namespace NuGetKeyVaultSignTool
{
Expand Down Expand Up @@ -76,38 +77,42 @@ async Task<string> Authenticate(string authority, string resource, string scope)

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 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;
Expand Down
51 changes: 30 additions & 21 deletions NuGetKeyVaultSignTool.Core/VerifyCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,51 +38,59 @@ public async Task<bool> 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)
{
logger.LogError(e, e.Message);
return false;
}

return allPackagesVerified;
}
}
}
12 changes: 3 additions & 9 deletions NuGetKeyVaultSignTool/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down