internal static SignTest Create( X509Certificate2 certificate, HashAlgorithmName hashAlgorithm, byte[] package = null, ISignatureProvider signatureProvider = null) { ISignedPackage signedPackage; MemoryStream readStream = null; MemoryStream writeStream = null; if (package == null) { signedPackage = Mock.Of <ISignedPackage>(); } else { readStream = new MemoryStream(package); writeStream = new MemoryStream(); signedPackage = new SignedPackageArchive(readStream, writeStream); } signatureProvider = signatureProvider ?? Mock.Of <ISignatureProvider>(); var signer = new Signer(signedPackage, signatureProvider); var request = new SignPackageRequest(certificate, signatureHashAlgorithm: hashAlgorithm); return(new SignTest( signer, signedPackage, signatureProvider, request, readStream, writeStream)); }
/// <summary> /// Generates a signed copy of a package and returns the path to that package /// This method timestamps a package and should only be used with tests marked with [CIOnlyFact] /// </summary> /// <param name="certificate">Certificate to be used while signing the package</param> /// <param name="nupkg">Package to be signed</param> /// <param name="dir">Directory for placing the signed package</param> /// <param name="timestampService">RFC 3161 timestamp service URL.</param> /// <param name="request">An author signing request.</param> /// <returns>Path to the signed copy of the package</returns> public static async Task <string> CreateSignedAndTimeStampedPackageAsync( X509Certificate2 certificate, SimpleTestPackageContext nupkg, string dir, Uri timestampService, AuthorSignPackageRequest request = null) { var testLogger = new TestLogger(); using (var zipReadStream = nupkg.CreateAsStream()) using (var zipWriteStream = nupkg.CreateAsStream()) { var signedPackagePath = Path.Combine(dir, Guid.NewGuid().ToString()); using (var signPackage = new SignedPackageArchive(zipReadStream, zipWriteStream)) { request = request ?? new AuthorSignPackageRequest(certificate, HashAlgorithmName.SHA256); // Sign the package await SignAndTimeStampPackageAsync(testLogger, certificate, signPackage, timestampService, request); } zipWriteStream.Seek(offset: 0, loc: SeekOrigin.Begin); using (Stream fileStream = File.OpenWrite(signedPackagePath)) { zipWriteStream.CopyTo(fileStream); } return(signedPackagePath); } }
/// <summary> /// Generates a signed copy of a package and returns the path to that package /// This method timestamps a package and should only be used with tests marked with [CIOnlyFact] /// </summary> /// <param name="testCert">Certificate to be used while signing the package</param> /// <param name="nupkg">Package to be signed</param> /// <param name="dir">Directory for placing the signed package</param> /// <param name="timestampService">RFC 3161 timestamp service URL.</param> /// <returns>Path to the signed copy of the package</returns> public static async Task <string> CreateSignedAndTimeStampedPackageAsync( X509Certificate2 testCert, SimpleTestPackageContext nupkg, string dir, Uri timestampService) { var testLogger = new TestLogger(); using (var zipReadStream = nupkg.CreateAsStream()) using (var zipWriteStream = nupkg.CreateAsStream()) { var signedPackagePath = Path.Combine(dir, Guid.NewGuid().ToString()); using (var signPackage = new SignedPackageArchive(zipReadStream, zipWriteStream)) { // Sign the package await SignAndTimeStampPackageAsync(testLogger, testCert, signPackage, timestampService); } zipWriteStream.Seek(offset: 0, loc: SeekOrigin.Begin); using (Stream fileStream = File.OpenWrite(signedPackagePath)) { zipWriteStream.CopyTo(fileStream); } return(signedPackagePath); } }
private Test(MemoryStream inputPackageStream) { InputPackageStream = inputPackageStream; OutputPackageStream = new MemoryStream(); Package = new SignedPackageArchive(InputPackageStream, OutputPackageStream); }
internal async Task CountersignAsync() { PrimarySignature primarySignature; using (var archiveReader = new PackageArchiveReader(SignedPackage)) { primarySignature = await archiveReader.GetPrimarySignatureAsync(CancellationToken.None); } using (var request = new UnknownSignPackageRequest( new X509Certificate2(Certificate), HashAlgorithmName.SHA256)) { var cmsSigner = SigningUtility.CreateCmsSigner(request, NullLogger.Instance); var signedCms = primarySignature.SignedCms; signedCms.SignerInfos[0].ComputeCounterSignature(cmsSigner); primarySignature = PrimarySignature.Load(signedCms.Encode()); } using (var originalPackage = new MemoryStream(Zip.ToByteArray(), writable: false)) using (var signedPackage = new MemoryStream()) using (var archive = new SignedPackageArchive(originalPackage, signedPackage)) using (var signatureStream = new MemoryStream(primarySignature.GetBytes())) { await archive.AddSignatureAsync(signatureStream, CancellationToken.None); SignedPackage = new MemoryStream(signedPackage.ToArray(), writable: false); } var isSigned = await SignedArchiveTestUtility.IsSignedAsync(SignedPackage); Assert.True(isSigned); }
public static async Task <VerifySignaturesResult> VerifySignatureAsync(SignedPackageArchive signPackage, SignedPackageVerifierSettings settings) { var verificationProviders = new[] { new SignatureTrustAndValidityVerificationProvider() }; var verifier = new PackageSignatureVerifier(verificationProviders, settings); var result = await verifier.VerifySignaturesAsync(signPackage, CancellationToken.None); return(result); }
internal Task <bool> IsSignedAsync() { using (var unused = new MemoryStream()) { var signedPackage = new SignedPackageArchive(_writeStream, unused); return(signedPackage.IsSignedAsync(CancellationToken.None)); } }
private VerifyTest( TestDirectory directory, SignedPackageArchive package, PrimarySignature primarySignature, SignatureVerifySettings settings) { _directory = directory; Package = package; PrimarySignature = primarySignature; Settings = settings; }
internal Test(MemoryStream stream) { ReadStream = stream; WriteStream = stream; Package = new SignedPackageArchive(ReadStream, WriteStream); var signatureProvider = new X509SignatureProvider(timestampProvider: null); Signer = new Signer(Package, signatureProvider); }
private GetTrustResultAsyncTest( TestDirectory directory, SignedPackageArchive package, Signature signature, SignedPackageVerifierSettings settings) { _directory = directory; Package = package; Signature = signature; Settings = settings; Provider = new SignatureTrustAndValidityVerificationProvider(); }
/// <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, X509Certificate2 certificate, SignedPackageArchive signPackage, Uri timestampService) { var testSignatureProvider = new X509SignatureProvider(new Rfc3161TimestampProvider(timestampService)); var signer = new Signer(signPackage, testSignatureProvider); var request = new AuthorSignPackageRequest(certificate, HashAlgorithmName.SHA256); await signer.SignAsync(request, testLogger, CancellationToken.None); }
private VerifyTest( TestDirectory directory, FileStream signedPackageReadStream, SignedPackageArchive package, PrimarySignature primarySignature, SignatureVerifySettings settings) { _directory = directory; _signedPackageReadStream = signedPackageReadStream; Package = package; PrimarySignature = primarySignature; Settings = settings; }
private static async Task RemoveSignatureAsync( ILogger logger, ISignatureProvider signatureProvider, string packagePath, string originalPackageCopyPath, CancellationToken token) { using (var packageReadStream = File.OpenRead(packagePath)) using (var packageWriteStream = File.Open(originalPackageCopyPath, FileMode.Open)) using (var package = new SignedPackageArchive(packageReadStream, packageWriteStream)) { var signer = new Signer(package, signatureProvider); await signer.RemoveSignaturesAsync(logger, token); } }
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); } }
internal Test(X509Certificate2 certificate) { _directory = TestDirectory.Create(); _certificate = new X509Certificate2(certificate); var packageContext = new SimpleTestPackageContext(); ReadStream = packageContext.CreateAsStream(); WriteStream = packageContext.CreateAsStream(); Package = new SignedPackageArchive(ReadStream, WriteStream); Request = new AuthorSignPackageRequest(_certificate, HashAlgorithmName.SHA256); var signatureProvider = new X509SignatureProvider(timestampProvider: null); Signer = new Signer(Package, signatureProvider); }
internal static async Task <GetTrustResultAsyncTest> CreateAsync(SignedPackageVerifierSettings settings, X509Certificate2 certificate) { using (var certificateClone = new X509Certificate2(certificate)) { var directory = TestDirectory.Create(); var packageContext = new SimpleTestPackageContext(); var unsignedPackageFile = packageContext.CreateAsFile(directory, "package.nupkg"); var signedPackageFile = await SignedArchiveTestUtility.SignPackageFileWithBasicSignedCmsAsync( directory, unsignedPackageFile, certificateClone); var package = new SignedPackageArchive(signedPackageFile.OpenRead(), new MemoryStream()); var signature = await package.GetSignatureAsync(CancellationToken.None); return(new GetTrustResultAsyncTest(directory, package, signature, settings)); } }
public async Task StripsRepositorySignatures() { // Arrange _message = new SignatureValidationMessage( TestResources.UnsignedPackageId, TestResources.UnsignedPackageVersion, new Uri($"https://unit.test/validation/{TestResources.UnsignedPackage.ToLowerInvariant()}"), Guid.NewGuid()); var packageBytes = await _fixture.GenerateSignedPackageBytesAsync( TestResources.GetResourceStream(TestResources.UnsignedPackage), new RepositorySignPackageRequest( await _fixture.GetSigningCertificateAsync(), NuGetHashAlgorithmName.SHA256, NuGetHashAlgorithmName.SHA256, new Uri("https://example-source/v3/index.json"), new[] { "nuget", "microsoft" }), await _fixture.GetTimestampServiceUrlAsync(), _output); var packageStream = new MemoryStream(packageBytes); TestUtility.RequireUnsignedPackage(_corePackageService, TestResources.UnsignedPackageId); // Act var result = await _target.ValidateAsync( _packageKey, packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Succeeded, PackageSigningStatus.Unsigned); Assert.Empty(result.Issues); Assert.Equal(_nupkgUri, result.NupkgUri); Assert.NotNull(_savedPackageBytes); using (var savedPackageStream = new MemoryStream(_savedPackageBytes)) using (var packageReader = new SignedPackageArchive(savedPackageStream, Stream.Null)) { Assert.Equal("TestUnsigned", packageReader.NuspecReader.GetId()); Assert.Equal("1.0.0", packageReader.NuspecReader.GetVersion().ToNormalizedString()); Assert.False(await packageReader.IsSignedAsync(CancellationToken.None), "The package should no longer be signed."); } }
// This generates a package with a basic signed CMS. // The signature MUST NOT have any signed or unsigned attributes. public static async Task <FileInfo> SignPackageFileWithBasicSignedCmsAsync( TestDirectory directory, FileInfo packageFile, X509Certificate2 certificate) { var signatureContent = CreateSignatureContent(packageFile); var signedPackageFile = new FileInfo(Path.Combine(directory, Guid.NewGuid().ToString())); var signature = CreateSignature(signatureContent, certificate); using (var packageReadStream = packageFile.OpenRead()) using (var packageWriteStream = signedPackageFile.OpenWrite()) using (var package = new SignedPackageArchive(packageReadStream, packageWriteStream)) using (var signatureStream = new MemoryStream(signature.Encode())) { await package.AddSignatureAsync(signatureStream, CancellationToken.None); } return(signedPackageFile); }
public async Task <SignatureValidatorResult> ValidateAsync( int packageKey, Stream packageStream, SignatureValidationMessage message, CancellationToken cancellationToken) { using (var packageReader = new SignedPackageArchive(packageStream, packageWriteStream: Stream.Null)) using (var context = new Context(packageKey, packageStream, packageReader, message, cancellationToken)) { // Reject Zip64 package whether or not they are signed. if (await context.PackageReader.IsZip64Async(context.CancellationToken)) { return(await RejectAsync(context, ValidationIssue.PackageIsZip64)); } SignatureValidatorResult result; if (await context.PackageReader.IsSignedAsync(cancellationToken)) { result = await HandleSignedPackageAsync(context); } else { result = await HandleUnsignedPackageAsync(context); } // Force the validation to fail if the repository signature is expected but missing. The signature // and signing state that are stored in the database may be still valid. if (context.Message.RequireRepositorySignature && !context.HasRepositorySignature) { _logger.LogCritical( "Package {PackageId} {PackageVersion} for validation {ValidationId} is expected to be repository signed.", context.Message.PackageId, context.Message.PackageVersion, context.Message.ValidationId); return(new SignatureValidatorResult(ValidationStatus.Failed, result.Issues, nupkgUri: null)); } return(result); } }
private static async Task AddSignatureAndUpdatePackageAsync( ILogger logger, ISignatureProvider signatureProvider, AuthorSignPackageRequest request, string packagePath, string outputPath, CancellationToken token) { var originalPackageCopyPath = CopyPackage(packagePath); using (var packageReadStream = File.OpenRead(packagePath)) using (var packageWriteStream = File.Open(originalPackageCopyPath, FileMode.Open)) using (var package = new SignedPackageArchive(packageReadStream, packageWriteStream)) { var signer = new Signer(package, signatureProvider); await signer.SignAsync(request, logger, token); } OverwritePackage(originalPackageCopyPath, outputPath); FileUtility.Delete(originalPackageCopyPath); }
private static async Task TestRemoveSignatureAsync(byte[] expectedPackage, byte[] signedPackage) { using (var readStream = new MemoryStream(signedPackage)) using (var writeStream = new MemoryStream()) using (var signedArchive = new SignedPackageArchive(readStream, writeStream)) { var isSigned = await SignedArchiveTestUtility.IsSignedAsync(readStream); Assert.True(isSigned); await signedArchive.RemoveSignatureAsync(CancellationToken.None); isSigned = await SignedArchiveTestUtility.IsSignedAsync(writeStream); Assert.False(isSigned); var unsignedPackage = writeStream.ToArray(); Assert.Equal(expectedPackage, unsignedPackage); } }
public async Task StripsRepositoryCounterSignatures() { // Arrange var packageBytes = await _fixture.GenerateSignedPackageBytesAsync( await GetSignedPackageStream1Async(), new RepositorySignPackageRequest( await _fixture.GetSigningCertificateAsync(), NuGetHashAlgorithmName.SHA256, NuGetHashAlgorithmName.SHA256, new Uri("https://example-source/v3/index.json"), new[] { "nuget", "microsoft" }), await _fixture.GetTimestampServiceUrlAsync(), _output); var packageStream = new MemoryStream(packageBytes); // Act var result = await _target.ValidateAsync( _packageKey, packageStream, _message, _token); // Assert VerifyPackageSigningStatus(result, ValidationStatus.Succeeded, PackageSigningStatus.Valid); Assert.Empty(result.Issues); Assert.Equal(_nupkgUri, result.NupkgUri); Assert.NotNull(_savedPackageBytes); using (var savedPackageStream = new MemoryStream(_savedPackageBytes)) using (var packageReader = new SignedPackageArchive(savedPackageStream, Stream.Null)) { Assert.Equal("TestSigned.leaf-1", packageReader.NuspecReader.GetId()); Assert.Equal("1.0.0", packageReader.NuspecReader.GetVersion().ToNormalizedString()); Assert.True(await packageReader.IsSignedAsync(CancellationToken.None), "The package should still be signed."); var signature = await packageReader.GetPrimarySignatureAsync(CancellationToken.None); Assert.Equal(SignatureType.Author, signature.Type); Assert.Empty(signature.SignedCms.SignerInfos[0].CounterSignerInfos); } }
// This generates a package with a basic signed CMS. // The signature MUST NOT have any signed or unsigned attributes. public static async Task <FileInfo> SignPackageFileWithBasicSignedCmsAsync( TestDirectory directory, FileInfo packageFile, X509Certificate2 certificate) { SignatureContent signatureContent; using (var stream = packageFile.OpenRead()) using (var hashAlgorithm = HashAlgorithmName.SHA256.GetHashProvider()) { var hash = hashAlgorithm.ComputeHash(stream, leaveStreamOpen: false); signatureContent = new SignatureContent(SigningSpecifications.V1, HashAlgorithmName.SHA256, Convert.ToBase64String(hash)); } var signedPackageFile = new FileInfo(Path.Combine(directory, Guid.NewGuid().ToString())); var cmsSigner = new CmsSigner(certificate) { DigestAlgorithm = HashAlgorithmName.SHA256.ConvertToOid(), IncludeOption = X509IncludeOption.WholeChain }; var contentInfo = new ContentInfo(signatureContent.GetBytes()); var signature = new SignedCms(contentInfo); signature.ComputeSignature(cmsSigner); Assert.Empty(signature.SignerInfos[0].SignedAttributes); Assert.Empty(signature.SignerInfos[0].UnsignedAttributes); using (var packageReadStream = packageFile.OpenRead()) using (var packageWriteStream = signedPackageFile.OpenWrite()) using (var package = new SignedPackageArchive(packageReadStream, packageWriteStream)) using (var signatureStream = new MemoryStream(signature.Encode())) { await package.AddSignatureAsync(signatureStream, CancellationToken.None); } return(signedPackageFile); }
public async Task <SignatureValidatorResult> ValidateAsync( int packageKey, Stream packageStream, SignatureValidationMessage message, CancellationToken cancellationToken) { using (var packageReader = new SignedPackageArchive(packageStream, packageWriteStream: Stream.Null)) using (var context = new Context(packageKey, packageStream, packageReader, message, cancellationToken)) { // Reject Zip64 package whether or not they are signed. if (await context.PackageReader.IsZip64Async(context.CancellationToken)) { return(await RejectAsync(context, ValidationIssue.PackageIsZip64)); } if (await context.PackageReader.IsSignedAsync(cancellationToken)) { return(await HandleSignedPackageAsync(context)); } return(await HandleUnsignedPackageAsync(context)); } }
/// <summary> /// Write a zip file to a stream. /// </summary> public static async Task CreatePackageAsync(Stream stream, SimpleTestPackageContext packageContext) { var id = packageContext.Id; var version = packageContext.Version; var runtimeJson = packageContext.RuntimeJson; var pathResolver = new VersionFolderPathResolver(null); var testLogger = new TestLogger(); var tempStream = stream; var isUsingTempStream = false; if (packageContext.IsPrimarySigned) { tempStream = new MemoryStream(); isUsingTempStream = true; } using (var zip = new ZipArchive(tempStream, ZipArchiveMode.Create, leaveOpen: true)) { if (packageContext.Files.Any()) { foreach (var entryFile in packageContext.Files) { zip.AddEntry(entryFile.Key, entryFile.Value); } } else { zip.AddEntry("contentFiles/any/any/config.xml", new byte[] { 0 }); zip.AddEntry("contentFiles/cs/net45/code.cs", new byte[] { 0 }); zip.AddEntry("lib/net45/a.dll", new byte[] { 0 }); zip.AddEntry("lib/netstandard1.0/a.dll", new byte[] { 0 }); zip.AddEntry($"build/net45/{id}.targets", @"<Project />", Encoding.UTF8); zip.AddEntry("runtimes/any/native/a.dll", new byte[] { 0 }); zip.AddEntry("tools/a.exe", new byte[] { 0 }); } if (!string.IsNullOrEmpty(runtimeJson)) { zip.AddEntry("runtime.json", runtimeJson, Encoding.UTF8); } var frameworkAssembliesAndContentFiles = packageContext.UseDefaultRuntimeAssemblies ? $@"<frameworkAssemblies> <frameworkAssembly assemblyName=""System.Runtime""/> </frameworkAssemblies> <contentFiles> <files include=""cs/net45/config/config.xml"" buildAction=""none"" /> <files include=""cs/net45/config/config.xml"" copyToOutput=""true"" flatten=""false"" /> <files include=""cs/net45/images/image.jpg"" buildAction=""embeddedresource"" /> </contentFiles>" : string.Empty; var nuspecXml = packageContext.Nuspec?.ToString() ?? $@"<?xml version=""1.0"" encoding=""utf-8""?> <package> <metadata> <id>{id}</id> <version>{version.ToString()}</version> <title /> {frameworkAssembliesAndContentFiles} </metadata> </package>"; var xml = XDocument.Parse(nuspecXml); // Add the min client version if it exists if (!string.IsNullOrEmpty(packageContext.MinClientVersion)) { xml.Root.Element(XName.Get("metadata")) .Add(new XAttribute(XName.Get("minClientVersion"), packageContext.MinClientVersion)); } List <(string, List <PackageDependency>)> dependenciesPerFramework = GetPackageDependencies(packageContext); if (dependenciesPerFramework.Any()) { var metadata = xml.Element(XName.Get("package")).Element(XName.Get("metadata")); var dependenciesNode = new XElement(XName.Get("dependencies")); foreach (var deps in dependenciesPerFramework) { var groupNode = new XElement(XName.Get("group")); if (!string.IsNullOrEmpty(deps.Item1)) { groupNode.SetAttributeValue("targetFramework", deps.Item1); } dependenciesNode.Add(groupNode); metadata.Add(dependenciesNode); foreach (var dependency in deps.Item2) { var node = new XElement(XName.Get("dependency")); groupNode.Add(node); node.Add(new XAttribute(XName.Get("id"), dependency.Id)); node.Add(new XAttribute(XName.Get("version"), dependency.VersionRange.ToNormalizedString())); if (dependency.Include.Count > 0) { node.Add(new XAttribute(XName.Get("include"), string.Join(",", dependency.Include))); } if (dependency.Exclude.Count > 0) { node.Add(new XAttribute(XName.Get("exclude"), string.Join(",", dependency.Exclude))); } } } } if (packageContext.FrameworkReferences.Any()) { var metadata = xml.Element(XName.Get("package")).Element(XName.Get("metadata")); var frameworkReferencesNode = new XElement(XName.Get("frameworkReferences")); foreach (var kvp in packageContext.FrameworkReferences) { var groupNode = new XElement(XName.Get("group")); groupNode.SetAttributeValue("targetFramework", kvp.Key.GetFrameworkString()); frameworkReferencesNode.Add(groupNode); metadata.Add(frameworkReferencesNode); foreach (var frameworkReference in kvp.Value) { var node = new XElement(XName.Get("frameworkReference")); groupNode.Add(node); node.Add(new XAttribute(XName.Get("name"), frameworkReference)); } } } if (packageContext.PackageTypes.Count > 0) { var metadata = xml.Element("package").Element("metadata"); var packageTypes = new XElement("packageTypes"); metadata.Add(packageTypes); foreach (var packageType in packageContext.PackageTypes) { var packageTypeElement = new XElement("packageType"); packageTypeElement.Add(new XAttribute("name", packageType.Name)); if (packageType.Version != PackageType.EmptyVersion) { packageTypeElement.Add(new XAttribute("version", packageType.Version)); } packageTypes.Add(packageTypeElement); } } zip.AddEntry($"{id}.nuspec", xml.ToString(), Encoding.UTF8); } if (isUsingTempStream) { using (tempStream) #if IS_SIGNING_SUPPORTED using (var signPackage = new SignedPackageArchive(tempStream, stream)) #endif { #if IS_SIGNING_SUPPORTED using (var request = GetPrimarySignRequest(packageContext)) { await AddSignatureToPackageAsync(packageContext, signPackage, request, testLogger); } if (packageContext.IsRepositoryCounterSigned) { using (var request = new RepositorySignPackageRequest(new X509Certificate2(packageContext.RepositoryCountersignatureCertificate), HashAlgorithmName.SHA256, HashAlgorithmName.SHA256, packageContext.V3ServiceIndexUrl, packageContext.PackageOwners)) { await AddRepositoryCountersignatureToSignedPackageAsync(packageContext, signPackage, request, testLogger); } } #endif } } // Reset position stream.Position = 0; }
/// <summary> /// Sign a package for test purposes. /// </summary> public static async Task SignPackageAsync(TestLogger testLogger, X509Certificate2 certificate, SignedPackageArchive signPackage) { var testSignatureProvider = new X509SignatureProvider(new Rfc3161TimestampProvider(new Uri(_testTimestampServer))); var signer = new Signer(signPackage, testSignatureProvider); var request = new SignPackageRequest(certificate, signatureHashAlgorithm: Common.HashAlgorithmName.SHA256); await signer.SignAsync(request, testLogger, 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, SignedPackageArchive signPackage) { var testSignatureProvider = new X509SignatureProvider(timestampProvider: null); var signer = new Signer(signPackage, testSignatureProvider); var request = new SignPackageRequest(certificate, signatureHashAlgorithm: HashAlgorithmName.SHA256); await signer.SignAsync(request, testLogger, CancellationToken.None); }
public async Task <int> SignAsync(string file, string timestampUrl, HashAlgorithmName signatureHashAlgorithm, HashAlgorithmName timestampeHashAlgorithm, string keyVaultCertificateName, string keyVaultUrl, string keyVaultClientId, string keyVaultClientSecret, string keyVaultAccessToken) { string validatedToken = null; async Task <string> Authenticate(string authority, string resource, string scope) { if (!string.IsNullOrWhiteSpace(keyVaultAccessToken)) { validatedToken = keyVaultAccessToken; return(keyVaultAccessToken); } var context = new AuthenticationContext(authority); var credential = new ClientCredential(keyVaultClientId, keyVaultClientSecret); var result = await context.AcquireTokenAsync(resource, credential) .ConfigureAwait(false); if (result == null) { throw new InvalidOperationException("Authentication to Azure failed."); } validatedToken = result.AccessToken; return(result.AccessToken); } var client = new KeyVaultClient(Authenticate, new HttpClient()); // We call this here to verify it's a valid cert // It also implicitly validates the access token or credentials var kvcert = await client.GetCertificateAsync(keyVaultUrl, keyVaultCertificateName) .ConfigureAwait(false); var cert = new X509Certificate2(kvcert.Cer); var rsa = client.ToRSA(kvcert.KeyIdentifier, cert); // TODO: Add Hash Alg choice var request = new SignPackageRequest() { Certificate = cert, SignatureHashAlgorithm = signatureHashAlgorithm, TimestampHashAlgorithm = timestampeHashAlgorithm }; string tempFilePath = null; try { tempFilePath = CopyPackage(file); var signatureProvider = new KeyVaultSignatureProvider(rsa, new Rfc3161TimestampProvider(new Uri(timestampUrl))); // remove first to overwrite // This command overwrites by default, like signtool using (var packageWriteStream = File.Open(tempFilePath, FileMode.Open)) using (var package = new SignedPackageArchive(packageWriteStream)) { var signer = new Signer(package, signatureProvider); await signer.RemoveSignaturesAsync(new NullLogger(), CancellationToken.None); } // Now sign using (var packageWriteStream = File.Open(tempFilePath, FileMode.Open)) using (var package = new SignedPackageArchive(packageWriteStream)) { var signer = new Signer(package, signatureProvider); await signer.SignAsync(request, new NullLogger(), CancellationToken.None); } OverwritePackage(tempFilePath, file); } catch (Exception e) { Console.Error.WriteLine(e.Message); Console.Error.WriteLine(e.StackTrace); return(-1); } finally { try { FileUtility.Delete(tempFilePath); } catch { } } return(0); }
/// <summary> /// Write a zip file to a stream. /// </summary> public static void CreatePackage(Stream stream, SimpleTestPackageContext packageContext) { var id = packageContext.Id; var version = packageContext.Version; var runtimeJson = packageContext.RuntimeJson; var pathResolver = new VersionFolderPathResolver(null); var testLogger = new TestLogger(); var tempStream = stream; var isUsingTempStream = false; if (packageContext.AuthorSignatureCertificate != null) { tempStream = new MemoryStream(); isUsingTempStream = true; } using (var zip = new ZipArchive(tempStream, ZipArchiveMode.Create, leaveOpen: true)) { if (packageContext.Files.Any()) { foreach (var entryFile in packageContext.Files) { zip.AddEntry(entryFile.Key, entryFile.Value); } } else { zip.AddEntry("contentFiles/any/any/config.xml", new byte[] { 0 }); zip.AddEntry("contentFiles/cs/net45/code.cs", new byte[] { 0 }); zip.AddEntry("lib/net45/a.dll", new byte[] { 0 }); zip.AddEntry("lib/netstandard1.0/a.dll", new byte[] { 0 }); zip.AddEntry($"build/net45/{id}.targets", @"<targets />", Encoding.UTF8); zip.AddEntry("runtimes/any/native/a.dll", new byte[] { 0 }); zip.AddEntry("tools/a.exe", new byte[] { 0 }); } if (!string.IsNullOrEmpty(runtimeJson)) { zip.AddEntry("runtime.json", runtimeJson, Encoding.UTF8); } var frameworkAssembliesAndContentFiles = packageContext.UseDefaultRuntimeAssemblies ? $@"<frameworkAssemblies> <frameworkAssembly assemblyName=""System.Runtime""/> </frameworkAssemblies> <contentFiles> <files include=""cs/net45/config/config.xml"" buildAction=""none"" /> <files include=""cs/net45/config/config.xml"" copyToOutput=""true"" flatten=""false"" /> <files include=""cs/net45/images/image.jpg"" buildAction=""embeddedresource"" /> </contentFiles>" : string.Empty; var nuspecXml = packageContext.Nuspec?.ToString() ?? $@"<?xml version=""1.0"" encoding=""utf-8""?> <package> <metadata> <id>{id}</id> <version>{version.ToString()}</version> <title /> {frameworkAssembliesAndContentFiles} </metadata> </package>"; var xml = XDocument.Parse(nuspecXml); // Add the min client version if it exists if (!string.IsNullOrEmpty(packageContext.MinClientVersion)) { xml.Root.Element(XName.Get("metadata")) .Add(new XAttribute(XName.Get("minClientVersion"), packageContext.MinClientVersion)); } var dependencies = packageContext.Dependencies.Select(e => new PackageDependency( e.Id, VersionRange.Parse(e.Version), string.IsNullOrEmpty(e.Include) ? new List <string>() : e.Include.Split(',').ToList(), string.IsNullOrEmpty(e.Exclude) ? new List <string>() : e.Exclude.Split(',').ToList())); if (dependencies.Any()) { var metadata = xml.Element(XName.Get("package")).Element(XName.Get("metadata")); var dependenciesNode = new XElement(XName.Get("dependencies")); var groupNode = new XElement(XName.Get("group")); dependenciesNode.Add(groupNode); metadata.Add(dependenciesNode); foreach (var dependency in dependencies) { var node = new XElement(XName.Get("dependency")); groupNode.Add(node); node.Add(new XAttribute(XName.Get("id"), dependency.Id)); node.Add(new XAttribute(XName.Get("version"), dependency.VersionRange.ToNormalizedString())); if (dependency.Include.Count > 0) { node.Add(new XAttribute(XName.Get("include"), string.Join(",", dependency.Include))); } if (dependency.Exclude.Count > 0) { node.Add(new XAttribute(XName.Get("exclude"), string.Join(",", dependency.Exclude))); } } } if (packageContext.PackageTypes.Count > 0) { var metadata = xml.Element("package").Element("metadata"); var packageTypes = new XElement("packageTypes"); metadata.Add(packageTypes); foreach (var packageType in packageContext.PackageTypes) { var packageTypeElement = new XElement("packageType"); packageTypeElement.Add(new XAttribute("name", packageType.Name)); if (packageType.Version != PackageType.EmptyVersion) { packageTypeElement.Add(new XAttribute("version", packageType.Version)); } packageTypes.Add(packageTypeElement); } } zip.AddEntry($"{id}.nuspec", xml.ToString(), Encoding.UTF8); } if (isUsingTempStream) { using (var signPackage = new SignedPackageArchive(tempStream, stream)) { var testSignatureProvider = new X509SignatureProvider(timestampProvider: null); var signer = new Signer(signPackage, testSignatureProvider); var request = new AuthorSignPackageRequest(packageContext.AuthorSignatureCertificate, hashAlgorithm: HashAlgorithmName.SHA256); signer.SignAsync(request, testLogger, CancellationToken.None).Wait(); } tempStream.Dispose(); } // Reset position stream.Position = 0; }