-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use Azure Key Vault's RSA implementation (#750)
Resolve #649
- Loading branch information
Showing
9 changed files
with
466 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE.txt file in the project root for more information. | ||
|
||
using Microsoft.Extensions.Logging; | ||
using NuGet.Common; | ||
using LogLevel = NuGet.Common.LogLevel; | ||
|
||
namespace Sign.Core | ||
{ | ||
internal sealed class NuGetLogger : NuGet.Common.ILogger | ||
{ | ||
private readonly Microsoft.Extensions.Logging.ILogger _logger; | ||
private readonly string _fileName; | ||
|
||
internal NuGetLogger(Microsoft.Extensions.Logging.ILogger logger, string fileName) | ||
{ | ||
ArgumentNullException.ThrowIfNull(logger, nameof(logger)); | ||
ArgumentException.ThrowIfNullOrEmpty(fileName, nameof(fileName)); | ||
|
||
_logger = logger; | ||
_fileName = fileName; | ||
} | ||
|
||
public void Log(LogLevel level, string data) | ||
{ | ||
_logger.Log(ConvertLevel(level), $"NuGet [{_fileName}]: {data}"); | ||
} | ||
|
||
public void Log(ILogMessage message) | ||
{ | ||
Log(message.Level, message.FormatWithCode()); | ||
} | ||
|
||
public Task LogAsync(LogLevel level, string data) | ||
{ | ||
Log(level, data); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
public Task LogAsync(ILogMessage message) | ||
{ | ||
Log(message.Level, message.FormatWithCode()); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
public void LogDebug(string data) | ||
{ | ||
Log(LogLevel.Debug, data); | ||
} | ||
|
||
public void LogError(string data) | ||
{ | ||
Log(LogLevel.Error, data); | ||
} | ||
|
||
public void LogInformation(string data) | ||
{ | ||
Log(LogLevel.Information, data); | ||
} | ||
|
||
public void LogInformationSummary(string data) | ||
{ | ||
Log(LogLevel.Information, data); | ||
} | ||
|
||
public void LogMinimal(string data) | ||
{ | ||
Log(LogLevel.Minimal, data); | ||
} | ||
|
||
public void LogVerbose(string data) | ||
{ | ||
Log(LogLevel.Verbose, data); | ||
} | ||
|
||
public void LogWarning(string data) | ||
{ | ||
Log(LogLevel.Warning, data); | ||
} | ||
|
||
private static Microsoft.Extensions.Logging.LogLevel ConvertLevel(LogLevel level) | ||
{ | ||
return level switch | ||
{ | ||
LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug, | ||
LogLevel.Verbose => Microsoft.Extensions.Logging.LogLevel.Trace, | ||
LogLevel.Information => Microsoft.Extensions.Logging.LogLevel.Information, | ||
LogLevel.Minimal => Microsoft.Extensions.Logging.LogLevel.Information, | ||
LogLevel.Warning => Microsoft.Extensions.Logging.LogLevel.Warning, | ||
LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error, | ||
_ => Microsoft.Extensions.Logging.LogLevel.Information | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE.txt file in the project root for more information. | ||
|
||
using System.Security.Cryptography.X509Certificates; | ||
using Microsoft.Extensions.Logging; | ||
using NuGet.Common; | ||
using NuGet.Packaging.Signing; | ||
using NuGet.Protocol; | ||
using ILogger = Microsoft.Extensions.Logging.ILogger; | ||
|
||
namespace Sign.Core | ||
{ | ||
internal sealed class NuGetPackageSigner | ||
{ | ||
private readonly ILogger _logger; | ||
|
||
public NuGetPackageSigner(ILogger logger) | ||
{ | ||
ArgumentNullException.ThrowIfNull(logger, nameof(logger)); | ||
|
||
_logger = logger; | ||
} | ||
|
||
public async Task<bool> SignAsync( | ||
string packagePath, | ||
string outputPath, | ||
Uri timestampUrl, | ||
SignatureType signatureType, | ||
HashAlgorithmName signatureHashAlgorithm, | ||
HashAlgorithmName timestampHashAlgorithm, | ||
X509Certificate2 signingCertificate, | ||
System.Security.Cryptography.RSA rsa, | ||
bool overwrite, | ||
CancellationToken cancellationToken = default) | ||
{ | ||
ArgumentException.ThrowIfNullOrEmpty(packagePath, nameof(packagePath)); | ||
ArgumentException.ThrowIfNullOrEmpty(outputPath, nameof(outputPath)); | ||
ArgumentNullException.ThrowIfNull(timestampUrl, nameof(timestampUrl)); | ||
ArgumentNullException.ThrowIfNull(signingCertificate, nameof(signingCertificate)); | ||
ArgumentNullException.ThrowIfNull(rsa, nameof(rsa)); | ||
|
||
bool inPlaceSigning = String.Equals(packagePath, outputPath); | ||
bool usingWildCards = packagePath.Contains('*') || packagePath.Contains('?'); | ||
IEnumerable<string> packageFilePaths = LocalFolderUtility.ResolvePackageFromPath(packagePath); | ||
NuGetSignatureProvider signatureProvider = new(rsa, new Rfc3161TimestampProvider(timestampUrl)); | ||
SignPackageRequest? request = null; | ||
|
||
if (signatureType == SignatureType.Author) | ||
{ | ||
request = new AuthorSignPackageRequest(signingCertificate, signatureHashAlgorithm, timestampHashAlgorithm); | ||
} | ||
else | ||
{ | ||
throw new NotSupportedException(nameof(signatureType)); | ||
} | ||
|
||
foreach (string packageFilePath in packageFilePaths) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
|
||
string packageFileName = Path.GetFileName(packageFilePath); | ||
|
||
_logger.LogInformation($"{nameof(SignAsync)} [{packageFilePath}]: Begin signing {packageFileName}"); | ||
|
||
string? originalPackageCopyPath = null; | ||
|
||
try | ||
{ | ||
originalPackageCopyPath = CopyPackage(packageFilePath); | ||
string signedPackagePath = outputPath; | ||
|
||
if (inPlaceSigning) | ||
{ | ||
signedPackagePath = packageFilePath; | ||
} | ||
else if (usingWildCards) | ||
{ | ||
string? pathName = Path.GetDirectoryName(outputPath + Path.DirectorySeparatorChar); | ||
|
||
if (!string.IsNullOrEmpty(pathName) && !Directory.Exists(pathName)) | ||
{ | ||
Directory.CreateDirectory(pathName); | ||
} | ||
|
||
signedPackagePath = pathName + Path.DirectorySeparatorChar + packageFileName; | ||
} | ||
|
||
using (SigningOptions options = SigningOptions.CreateFromFilePaths( | ||
originalPackageCopyPath, | ||
signedPackagePath, | ||
overwrite, | ||
signatureProvider, | ||
new NuGetLogger(_logger, packageFilePath))) | ||
{ | ||
await SigningUtility.SignAsync(options, request, cancellationToken); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogError(e, e.Message); | ||
return false; | ||
} | ||
finally | ||
{ | ||
if (!string.IsNullOrEmpty(originalPackageCopyPath)) | ||
{ | ||
try | ||
{ | ||
FileUtility.Delete(originalPackageCopyPath); | ||
} | ||
catch | ||
{ | ||
} | ||
} | ||
|
||
_logger.LogInformation($"{nameof(SignAsync)} [{packageFilePath}]: End signing {packageFileName}"); | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private static string CopyPackage(string sourceFilePath) | ||
{ | ||
string destFilePath = Path.GetTempFileName(); | ||
|
||
File.Copy(sourceFilePath, destFilePath, overwrite: true); | ||
|
||
return destFilePath; | ||
} | ||
|
||
private static void OverwritePackage(string sourceFilePath, string destFilePath) | ||
{ | ||
File.Copy(sourceFilePath, destFilePath, overwrite: true); | ||
} | ||
} | ||
} |
Oops, something went wrong.