diff --git a/src/arcade/Arcade.slnx b/src/arcade/Arcade.slnx index cc381104afc..a4c51eaafd6 100644 --- a/src/arcade/Arcade.slnx +++ b/src/arcade/Arcade.slnx @@ -45,6 +45,7 @@ + @@ -71,7 +72,6 @@ - diff --git a/src/arcade/eng/Version.Details.props b/src/arcade/eng/Version.Details.props index 39ca5e519b3..74f32236a9c 100644 --- a/src/arcade/eng/Version.Details.props +++ b/src/arcade/eng/Version.Details.props @@ -14,8 +14,8 @@ This file should be imported by eng/Versions.props 10.0.100-preview.4.25220.1 - 10.0.0-beta.25469.2 - 10.0.0-beta.25469.2 + 10.0.0-beta.25507.1 + 10.0.0-beta.25507.1 1.1.0-beta.25424.1 1.1.0-beta.25424.1 diff --git a/src/arcade/eng/Version.Details.xml b/src/arcade/eng/Version.Details.xml index b108dd09482..8e4ff3e2e9b 100644 --- a/src/arcade/eng/Version.Details.xml +++ b/src/arcade/eng/Version.Details.xml @@ -20,13 +20,13 @@ https://github.com/dotnet/templating 43b5827697e501c442eb75ffff832cd4df2514fe - + https://github.com/dotnet/arcade - 6275af47ebda0d394d4a5a401b77bc6f2304204a + 4eaa220ea860cee9fa61df42411bbf79394edd23 - + https://github.com/dotnet/arcade - 6275af47ebda0d394d4a5a401b77bc6f2304204a + 4eaa220ea860cee9fa61df42411bbf79394edd23 https://github.com/dotnet/arcade-services diff --git a/src/arcade/global.json b/src/arcade/global.json index a90a1ab74f6..b8b866ce354 100644 --- a/src/arcade/global.json +++ b/src/arcade/global.json @@ -12,8 +12,8 @@ "dotnet": "10.0.100-rc.1.25451.107" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25469.2", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25469.2", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25507.1", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25507.1", "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs index b7fb42ee99b..1c5db2ade1d 100644 --- a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs +++ b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/bundle/bundle.wxs @@ -61,7 +61,15 @@ - + + + + + + + + + diff --git a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets index 8632bcf50af..742bf80955f 100644 --- a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets +++ b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix5/wix.targets @@ -340,7 +340,7 @@ - + diff --git a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/Resources/InnerZipFile.zip b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/Resources/InnerZipFile.zip new file mode 100644 index 00000000000..333b5199c4e Binary files /dev/null and b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/Resources/InnerZipFile.zip differ diff --git a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs index cacd084dab3..3b4cd8581ea 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs @@ -1281,6 +1281,93 @@ public void SignZipFile() }); } + [Fact] + public void SignArchivesUsingDetachedSignature() + { + // List of files to be considered for signing + var itemsToSign = new List() + { + new ItemToSign(GetResourcePath("test.zip")), + new ItemToSign(GetResourcePath("test.tgz")), + new ItemToSign(GetResourcePath("NestedZip.zip")), + new ItemToSign(GetResourcePath("InnerZipFile.zip")) + }; + + var strongNameSignInfo = new Dictionary>(); + + // Overriding information + var explicitCertKeys = new Dictionary() + { + { new ExplicitCertificateKey("test.zip"), "ArchiveCert" }, + { new ExplicitCertificateKey("test.tgz"), "ArchiveCert" }, + { new ExplicitCertificateKey("InnerZipFile.zip"), "ArchiveCert" } + }; + + var additionalCertificateInfo = new Dictionary>() + { + { "ArchiveCert", + new List() { + new AdditionalCertificateInformation() { GeneratesDetachedSignature = true } + } + } + }; + + ValidateFileSignInfos(itemsToSign, strongNameSignInfo, explicitCertKeys, s_fileExtensionSignInfo, new[] + { + "File 'NativeLibrary.dll' Certificate='Microsoft400'", + "File 'SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'Nested.NativeLibrary.dll' Certificate='Microsoft400'", + "File 'Nested.SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'test.zip' Certificate='ArchiveCert'", + "File 'test.tgz' Certificate='ArchiveCert'", + "File 'InnerZipFile.zip' Certificate='ArchiveCert'", + "File 'Mid.SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'MidNativeLibrary.dll' Certificate='Microsoft400'", + "File 'NestedZip.zip'", + }, + additionalCertificateInfo: additionalCertificateInfo, + expectedCopyFiles: new[] + { + $"{Path.Combine(_tmpDir, "ContainerSigning", "6", "InnerZipFile.zip")} -> {Path.Combine(_tmpDir, "InnerZipFile.zip")}", + $"{Path.Combine(_tmpDir, "ContainerSigning", "6", "InnerZipFile.zip.sig")} -> {Path.Combine(_tmpDir, "InnerZipFile.zip.sig")}" + }); + + ValidateGeneratedProject(itemsToSign, strongNameSignInfo, explicitCertKeys, s_fileExtensionSignInfo, new[] + { +$@" + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + + + Microsoft400 + +", +$@" + + ArchiveCert + + + ArchiveCert + + + ArchiveCert + +" + }, additionalCertificateInfo: additionalCertificateInfo); + } + /// /// Verifies that signing of pkgs can be done on Windows, even though /// we will not unpack or repack them. @@ -2590,6 +2677,11 @@ public void ValidateSignToolTaskParsing() }), // Signed pe file new TaskItem(GetResourcePath("SignedLibrary.dll"), new Dictionary + { + { SignToolConstants.CollisionPriorityId, "123" } + }), + // Sign a test.zip + new TaskItem(GetResourcePath("test.zip"), new Dictionary { { SignToolConstants.CollisionPriorityId, "123" } }) @@ -2621,6 +2713,11 @@ public void ValidateSignToolTaskParsing() { "CertificateName", "DualSignCertificate" }, { "PublicKeyToken", "31bf3856ad364e35" }, { "CollisionPriorityId", "123" } + }), + new TaskItem("test.zip", new Dictionary + { + { "CertificateName", "DetachedArchiveCert" }, + { "CollisionPriorityId", "123" } }) }; @@ -2637,7 +2734,11 @@ public void ValidateSignToolTaskParsing() { "MacCertificate", "MacDeveloperHarden" }, { "MacNotarizationAppName", "com.microsoft.dotnet" }, { "CollisionPriorityId", "123" } - }) + }), + new TaskItem("DetachedArchiveCert", new Dictionary + { + { "DetachedSignature", "true" } + }), }; var task = new SignToolTask @@ -2670,7 +2771,11 @@ public void ValidateSignToolTaskParsing() "File 'ProjectOne.dll' TargetFramework='.NETCoreApp,Version=v2.1' Certificate='3PartySHA2' StrongName='ArcadeStrongTest'", "File 'ProjectOne.dll' TargetFramework='.NETStandard,Version=v2.0' Certificate='OverrideCertificateName' StrongName='ArcadeStrongTest'", "File 'ContainerOne.1.0.0.nupkg' Certificate='NuGet'", - "File 'SignedLibrary.dll' TargetFramework='.NETCoreApp,Version=v2.0' Certificate='DualSignCertificate'" + "File 'SignedLibrary.dll' TargetFramework='.NETCoreApp,Version=v2.0' Certificate='DualSignCertificate'", + "File 'SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'Nested.NativeLibrary.dll' Certificate='Microsoft400'", + "File 'Nested.SOS.NETCore.dll' TargetFramework='.NETCoreApp,Version=v1.0' Certificate='Microsoft400'", + "File 'test.zip' Certificate='DetachedArchiveCert'" }; task.ParsedSigningInput.FilesToSign.Select(f => f.ToString()).Should().BeEquivalentTo(expected); } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs index e7e2ed2f4a2..06f87035dee 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/AdditionalCertificateInformation.cs @@ -21,6 +21,10 @@ public class AdditionalCertificateInformation /// If the certificate name represents a sign+notarize operation, this is the name of the notarize operation. /// public string MacNotarizationAppName { get; set; } + /// + /// If true, this certificate should generate detached signatures instead of in-place signing. + /// + public bool GeneratesDetachedSignature { get; set; } public string CollisionPriorityId { get; set; } } } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs index 1eaca00b273..ecd63cf0009 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs @@ -554,9 +554,10 @@ private void VerifyCertificates(TaskLoggingHelper log) } else if (fileName.IsZip()) { - if (fileName.SignInfo.Certificate != null) + // Zip files can't be signed without a detached signature. If a certificate is provided but the signature is not detached. + if (!fileName.SignInfo.GeneratesDetachedSignature && fileName.SignInfo.Certificate != null) { - log.LogError($"Zip {fileName} should not be signed with this certificate: {fileName.SignInfo.Certificate}"); + log.LogError($"'{fileName}' may only be signed with a detached signature. '{fileName.SignInfo.Certificate}' does not produce a detached signature"); } if (fileName.SignInfo.StrongName != null) @@ -564,6 +565,19 @@ private void VerifyCertificates(TaskLoggingHelper log) log.LogError($"Zip {fileName} cannot be strong name signed."); } } + else if (fileName.IsTarGZip()) + { + // Tar.gz files can't be signed without a detached signature. If a certificate is provided but the signature is not detached. + if (!fileName.SignInfo.GeneratesDetachedSignature && fileName.SignInfo.Certificate != null) + { + log.LogError($"'{fileName}' may only be signed with a detached signature. '{fileName.SignInfo.Certificate}' does not produce a detached signature"); + } + + if (fileName.SignInfo.StrongName != null) + { + log.LogError($"TarGZip {fileName} cannot be strong name signed."); + } + } if (fileName.IsExecutableWixContainer()) { if (isInvalidEmptyCertificate) @@ -589,7 +603,28 @@ private void VerifyAfterSign(TaskLoggingHelper log, FileSignInfo file) // No need to check if the file should not have been signed. if (file.SignInfo.ShouldSign) { - if (file.IsPEFile()) + // For files with detached signatures, verify the .sig file exists + if (file.SignInfo.GeneratesDetachedSignature) + { + string sigFilePath = file.DetachedSignatureFullPath; + if (!File.Exists(sigFilePath)) + { + _log.LogError($"Detached signature file {sigFilePath} does not exist for {file.FullPath}"); + } + else + { + var fileInfo = new FileInfo(sigFilePath); + if (fileInfo.Length == 0) + { + _log.LogError($"Detached signature file {sigFilePath} is empty."); + } + else + { + _log.LogMessage(MessageImportance.Low, $"Detached signature file {sigFilePath} exists and is non-empty."); + } + } + } + else if (file.IsPEFile()) { using (var stream = File.OpenRead(file.FullPath)) { diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs index 8a48211bb31..1eb5b38408c 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/Configuration.cs @@ -224,6 +224,14 @@ private FileSignInfo TrackFile(PathWithHash file, PathWithHash parentContainer, // Copy the signed content to the destination path. _filesToCopy.Add(new KeyValuePair(existingSignInfo.FullPath, file.FullPath)); + + // If this is a top-level file that uses detached signatures, also copy the detached signature file + if (existingSignInfo.SignInfo.GeneratesDetachedSignature) + { + _filesToCopy.Add(new KeyValuePair(existingSignInfo.DetachedSignatureFullPath, fileSignInfo.DetachedSignatureFullPath)); + _log.LogMessage(MessageImportance.Low, $"Will copy detached signature from '{existingSignInfo.DetachedSignatureFullPath}' to '{fileSignInfo.DetachedSignatureFullPath}'"); + } + return fileSignInfo; } @@ -262,7 +270,7 @@ private FileSignInfo TrackFile(PathWithHash file, PathWithHash parentContainer, // Only sign containers if the file itself is unsigned, or // an item in the container is unsigned. hasSignableParts = _zipDataMap[fileSignInfo.FileContentKey].NestedParts.Values.Any(b => b.FileSignInfo.SignInfo.ShouldSign || b.FileSignInfo.HasSignableParts); - if(hasSignableParts) + if (hasSignableParts) { // If the file has contents that need to be signed, then re-evaluate the signing info fileSignInfo = fileSignInfo.WithSignableParts(); @@ -529,6 +537,12 @@ private FileSignInfo ExtractSignInfo( Check3rdPartyMicrosoftSignatureMismatch(file, peInfo, signInfo); + // Check if this cert should use detached signatures instead of in-place signing + if (ShouldUseDetachedSignature(file, signInfo)) + { + signInfo = signInfo.WithDetachedSignature(signInfo.Certificate); + } + return new FileSignInfo(file, signInfo, (peInfo != null && peInfo.TargetFramework != "") ? peInfo.TargetFramework : null, wixContentFilePath: wixContentFilePath); } @@ -864,5 +878,27 @@ private bool ShouldSkip3rdPartyCheck(string fileName) { return _itemsToSkip3rdPartyCheck != null && _itemsToSkip3rdPartyCheck.Contains(Path.GetFileName(fileName)); } + + /// + /// Determines if a file should use detached signatures based on certificate configuration. + /// + /// The file to check + /// True if the file should use detached signatures + private bool ShouldUseDetachedSignature(PathWithHash file, SignInfo signInfo) + { + // Check if the certificate is configured for detached signatures + if (signInfo.Certificate != null && _additionalCertificateInformation.TryGetValue(signInfo.Certificate, out var additionalInfo)) + { + var additionalCertInfo = additionalInfo.FirstOrDefault(a => string.IsNullOrEmpty(a.CollisionPriorityId) || + a.CollisionPriorityId == signInfo.CollisionPriorityId); + if (additionalCertInfo != null && additionalCertInfo.GeneratesDetachedSignature) + { + _log.LogMessage(MessageImportance.Low, $"File {file.FileName} will use detached signatures based on certificate configuration"); + return true; + } + } + + return false; + } } } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs index b8c775ddb36..14f4531cbcf 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/ExplicitCertificateKey.cs @@ -25,20 +25,6 @@ public ExplicitCertificateKey(string fileName, string publicKeyToken = null, str ExecutableType = executableType; } - private static ExecutableType ParseExecutableType(string executableType) - { - if (string.IsNullOrEmpty(executableType)) - return ExecutableType.None; - - return executableType switch - { - "PE" => ExecutableType.PE, - "MachO" => ExecutableType.MachO, - "ELF" => ExecutableType.ELF, - _ => ExecutableType.None - }; - } - public override bool Equals(object obj) => obj is ExplicitCertificateKey key && Equals(key); diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs index 62e5c8636f6..47062c119c6 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs @@ -17,6 +17,9 @@ internal readonly struct FileSignInfo internal readonly SignInfo SignInfo; internal ImmutableArray ContentHash => File.ContentHash; internal readonly string WixContentFilePath; + internal string DetachedSignatureFilePath => $"{FileName}.sig"; + internal string DetachedSignatureFullPath => $"{FullPath}.sig"; + internal readonly PathWithHash File; // optional file information that allows to disambiguate among multiple files with the same name: diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs index a6bb1087218..2f618337432 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignInfo.cs @@ -18,6 +18,11 @@ internal readonly struct SignInfo /// public static readonly SignInfo AlreadySigned = new SignInfo(ignoreThisFile: false, alreadySigned: true, isAlreadyStrongNamed: false); + /// + /// Used to flag that the file should generate a detached signature. + /// + public static readonly SignInfo DetachedSignature = new SignInfo(ignoreThisFile: false, alreadySigned: false, isAlreadyStrongNamed: false, generatesDetachedSignature: true); + /// /// The authenticode certificate which should be used to sign the binary. This can be null /// in cases where we have a zip container where the contents are signed but not the actual @@ -42,6 +47,11 @@ internal readonly struct SignInfo internal bool IsAlreadySigned { get; } + /// + /// True if this file should generate a detached signature rather than being signed in-place. + /// + internal bool GeneratesDetachedSignature { get; } + /// /// This is used to decide what SignInfos to use in the case of a collision. In case of a collision /// we'll use the lower value since it would map a lower node in the graph and has precedence @@ -57,7 +67,7 @@ internal readonly struct SignInfo public bool ShouldNotarize => !string.IsNullOrEmpty(NotarizationAppName) && !ShouldIgnore; - public SignInfo(string certificate, string strongName, string notarizationAppName, string collisionPriorityId, bool shouldIgnore, bool isAlreadySigned, bool isAlreadyStrongNamed) + private SignInfo(string certificate, string strongName, string notarizationAppName, string collisionPriorityId, bool shouldIgnore, bool isAlreadySigned, bool isAlreadyStrongNamed, bool generatesDetachedSignature = false) { ShouldIgnore = shouldIgnore; IsAlreadySigned = isAlreadySigned; @@ -66,10 +76,11 @@ public SignInfo(string certificate, string strongName, string notarizationAppNam CollisionPriorityId = collisionPriorityId; IsAlreadyStrongNamed = isAlreadyStrongNamed; NotarizationAppName = notarizationAppName; + GeneratesDetachedSignature = generatesDetachedSignature; } - private SignInfo(bool ignoreThisFile, bool alreadySigned, bool isAlreadyStrongNamed) - : this(certificate: null, strongName: null, notarizationAppName: null, collisionPriorityId: null, ignoreThisFile, alreadySigned, isAlreadyStrongNamed) + private SignInfo(bool ignoreThisFile, bool alreadySigned, bool isAlreadyStrongNamed, bool generatesDetachedSignature = false) + : this(certificate: null, strongName: null, notarizationAppName: null, collisionPriorityId: null, ignoreThisFile, alreadySigned, isAlreadyStrongNamed, generatesDetachedSignature) { } @@ -79,20 +90,23 @@ internal SignInfo(string certificate, string strongName = null, string notarizat } internal SignInfo WithCertificateName(string value, string collisionPriorityId) - => new SignInfo(value, StrongName, NotarizationAppName, collisionPriorityId, false, false, IsAlreadyStrongNamed); + => new SignInfo(value, StrongName, NotarizationAppName, collisionPriorityId, false, false, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithNotarization(string appName, string collisionPriorityId) - => new SignInfo(Certificate, StrongName, appName, collisionPriorityId, false, false, IsAlreadyStrongNamed); + => new SignInfo(Certificate, StrongName, appName, collisionPriorityId, false, false, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithCollisionPriorityId(string collisionPriorityId) - => new SignInfo(Certificate, StrongName, NotarizationAppName, collisionPriorityId, ShouldIgnore, IsAlreadySigned, IsAlreadyStrongNamed); + => new SignInfo(Certificate, StrongName, NotarizationAppName, collisionPriorityId, ShouldIgnore, IsAlreadySigned, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithIsAlreadySigned(bool value = false) => Certificate != null ? - new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, value, value, IsAlreadyStrongNamed) : - new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, true, value, IsAlreadyStrongNamed); + new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, value, value, IsAlreadyStrongNamed, GeneratesDetachedSignature) : + new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, true, value, IsAlreadyStrongNamed, GeneratesDetachedSignature); internal SignInfo WithIsAlreadyStrongNamed(bool value = false) => - new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, ShouldIgnore, IsAlreadySigned, value); + new SignInfo(Certificate, StrongName, NotarizationAppName, CollisionPriorityId, ShouldIgnore, IsAlreadySigned, value, GeneratesDetachedSignature); + + internal SignInfo WithDetachedSignature(string certificate) + => new SignInfo(certificate, StrongName, NotarizationAppName, CollisionPriorityId, false, false, IsAlreadyStrongNamed, true); } } diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs index 6aa74d2ccc1..6b88e6d156b 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignTool.cs @@ -13,6 +13,7 @@ using Microsoft.Build.Utilities; using NuGet.Packaging; using Microsoft.DotNet.StrongName; +using System.ComponentModel; namespace Microsoft.DotNet.SignTool { @@ -148,15 +149,37 @@ private bool AuthenticodeSignAndNotarize(IBuildEngine buildEngine, int round, IE var zippedPaths = ZipMacFiles(filesToSign); - // First the signing pass - var signProjectPath = Path.Combine(dir, $"Round{round}-Sign.proj"); - File.WriteAllText(signProjectPath, GenerateBuildFileContent(filesToSign, zippedPaths, false)); - string signingLogName = $"SigningRound{round}"; - status = RunMSBuild(buildEngine, signProjectPath, Path.Combine(_args.LogDir, $"{signingLogName}.binlog"), Path.Combine(_args.LogDir, $"{signingLogName}.log"), Path.Combine(_args.LogDir, $"{signingLogName}.error.log")); + // Identify files that need detached signatures + var detachedSignatureFiles = filesToSign.Where(f => f.SignInfo.GeneratesDetachedSignature).ToList(); + var originalFileBackups = new Dictionary(); - if (!status) + try { - return false; + PrepareDetachedSignatureFiles(detachedSignatureFiles, originalFileBackups); + + var signProjectPath = Path.Combine(dir, $"Round{round}-Sign.proj"); + File.WriteAllText(signProjectPath, GenerateBuildFileContent(filesToSign, zippedPaths, false)); + string signingLogName = $"SigningRound{round}"; + status = RunMSBuild(buildEngine, signProjectPath, Path.Combine(_args.LogDir, $"{signingLogName}.binlog"), Path.Combine(_args.LogDir, $"{signingLogName}.log"), Path.Combine(_args.LogDir, $"{signingLogName}.error.log")); + + if (!status) + { + return false; + } + + // After signing, handle detached signatures + CompleteDetachedSignatures(detachedSignatureFiles, originalFileBackups); + } + finally + { + // Delete any original detached signature files + foreach (var backupPath in originalFileBackups.Values) + { + if (File.Exists(backupPath)) + { + File.Delete(backupPath); + } + } } // Now unzip. Notarization does not expect zipped packages. @@ -175,6 +198,47 @@ private bool AuthenticodeSignAndNotarize(IBuildEngine buildEngine, int round, IE return status; } + /// + /// Copies the signed content to the .sig file and restores the original file. + /// + /// + /// + private void CompleteDetachedSignatures(List detachedSignatureFiles, Dictionary originalFileBackups) + { + foreach (var fileInfo in detachedSignatureFiles) + { + // Copy the signed content to .sig file + File.Copy(fileInfo.FullPath, fileInfo.DetachedSignatureFullPath); + _log.LogMessage($"Created detached signature file: {fileInfo.DetachedSignatureFullPath}"); + + // Restore the original file + string backupPath = originalFileBackups[fileInfo.FullPath]; + File.Copy(backupPath, fileInfo.FullPath, overwrite: true); + _log.LogMessage($"Restored original file: {fileInfo.FullPath}"); + } + } + + /// + /// Creates backup copies of the specified files to prepare for detached signature operations. + /// + /// Each file is backed up by copying it to a new file with the ".original" extension + /// appended to its path. The method updates the provided dictionary to allow later restoration of the original + /// files if needed. + /// A list of file information objects representing the files for which detached signature backups will be + /// created. Each file in the list will be copied to a backup location. + /// A dictionary that will be populated with mappings from the original file paths to their corresponding backup + /// file paths. The dictionary is updated in place. + private void PrepareDetachedSignatureFiles(List detachedSignatureFiles, Dictionary originalFileBackups) + { + foreach (var fileInfo in detachedSignatureFiles) + { + string backupPath = fileInfo.FullPath + ".original"; + File.Copy(fileInfo.FullPath, backupPath); + originalFileBackups[fileInfo.FullPath] = backupPath; + _log.LogMessage($"Backed up original file for detached signature: {fileInfo.FullPath} -> {backupPath}"); + } + } + private string GenerateBuildFileContent(IEnumerable filesToSign, Dictionary zippedPaths, bool notarize) { var builder = new StringBuilder(); diff --git a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs index b999bbd6502..14d65f5bf0f 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool/src/SignToolTask.cs @@ -336,6 +336,8 @@ private Dictionary> ParseAddition var macSigningOperation = certificateSignInfo.GetMetadata("MacCertificate"); var macNotarizationAppName = certificateSignInfo.GetMetadata("MacNotarizationAppName"); var collisionPriorityId = certificateSignInfo.GetMetadata(SignToolConstants.CollisionPriorityId); + var detachedSignatureCertificate = certificateSignInfo.GetMetadata("DetachedSignature"); + bool detachedSignatureCertificateValue = false; if (string.IsNullOrEmpty(macSigningOperation) != string.IsNullOrEmpty(macNotarizationAppName)) { @@ -348,11 +350,18 @@ private Dictionary> ParseAddition continue; } + if (!string.IsNullOrEmpty(detachedSignatureCertificate) && !bool.TryParse(detachedSignatureCertificate, out detachedSignatureCertificateValue)) + { + Log.LogError($"DetachedSignature must be 'true' or 'false"); + continue; + } + var additionalCertInfo = new AdditionalCertificateInformation { DualSigningAllowed = dualSignAllowedValue, MacSigningOperation = macSigningOperation, MacNotarizationAppName = macNotarizationAppName, + GeneratesDetachedSignature = detachedSignatureCertificateValue, CollisionPriorityId = collisionPriorityId }; diff --git a/src/nuget-client/build/DotNetSdkTestVersions.txt b/src/nuget-client/build/DotNetSdkTestVersions.txt index 041f89b91b4..d4a2109c8e2 100644 --- a/src/nuget-client/build/DotNetSdkTestVersions.txt +++ b/src/nuget-client/build/DotNetSdkTestVersions.txt @@ -2,4 +2,4 @@ # To make sure that the right version of dotnet.exe (and maybe other files) is used, always install from lowest version to highest version -Channel 8.0 -Runtime dotnet -Channel 9.0 -Runtime dotnet --Channel 10.0.1xx -Version 10.0.100-rc.2.25465.104 +-Channel 10.0.1xx -Quality daily diff --git a/src/nuget-client/build/common.project.props b/src/nuget-client/build/common.project.props index 5f7af2d3650..ab90d04409a 100644 --- a/src/nuget-client/build/common.project.props +++ b/src/nuget-client/build/common.project.props @@ -142,8 +142,6 @@ - $(SemanticVersion).$(PreReleaseVersion) - $(SemanticVersion).0 $(SemanticVersion).$(PreReleaseVersion) $(SemanticVersion)$(PreReleaseInformationVersion) $(SemanticVersion)$(PreReleaseInformationVersion)+$(BUILD_SOURCEVERSION) diff --git a/src/nuget-client/build/common.targets b/src/nuget-client/build/common.targets index b0ea719307b..14934090e62 100644 --- a/src/nuget-client/build/common.targets +++ b/src/nuget-client/build/common.targets @@ -2,7 +2,7 @@ - + $(SemanticVersion).$(PreReleaseVersion) $(SemanticVersion).0 diff --git a/src/nuget-client/build/config.props b/src/nuget-client/build/config.props index 83fcdc328ce..26e1ba81e9b 100644 --- a/src/nuget-client/build/config.props +++ b/src/nuget-client/build/config.props @@ -22,7 +22,7 @@ rc - false + true $([MSBuild]::Add(11, $(MajorNuGetVersion))) diff --git a/src/nuget-client/eng/Version.Details.props b/src/nuget-client/eng/Version.Details.props index 02eb28a0001..1092349c1de 100644 --- a/src/nuget-client/eng/Version.Details.props +++ b/src/nuget-client/eng/Version.Details.props @@ -21,8 +21,8 @@ This file should be imported by eng/Versions.props 4.5.0 - 10.0.0-beta.25420.109 - 10.0.0-beta.25420.109 + 10.0.0-beta.25468.104 + 10.0.0-beta.25468.104 diff --git a/src/nuget-client/eng/Version.Details.xml b/src/nuget-client/eng/Version.Details.xml index 90dcf3571a7..328e46c38da 100644 --- a/src/nuget-client/eng/Version.Details.xml +++ b/src/nuget-client/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + - 10.0.0-rc.2.25466.2 + 10.0.0-rtm.25502.1 4.9.0-rc2.21473.1 @@ -100,12 +100,12 @@ This file should be imported by eng/Versions.props 10.0.0-prerelease.25475.1 10.0.0-prerelease.25475.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 - 1.0.0-prerelease.25467.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 + 1.0.0-prerelease.25502.1 10.0.0-alpha.0.25479.2 diff --git a/src/runtime/eng/Version.Details.xml b/src/runtime/eng/Version.Details.xml index e40ce5b17dd..1f28d582d03 100644 --- a/src/runtime/eng/Version.Details.xml +++ b/src/runtime/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/icu - 4c504bd8f75919cc512c456551f4229847da9e21 + a91b254e70decd379d76338b7bb171ee98301aef https://github.com/dotnet/wcf @@ -307,21 +307,21 @@ https://github.com/dotnet/dotnet e72b5bbe719d747036ce9c36582a205df9f1c361 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa https://github.com/dotnet/hotreload-utils @@ -355,13 +355,13 @@ https://github.com/dotnet/dotnet e72b5bbe719d747036ce9c36582a205df9f1c361 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 59dc6a9bf1b3e3ab71c73d94160c2049fb104cd1 + 71ce9774e9875270b80faaac1d6b60568a80e1fa diff --git a/src/runtime/src/mono/mono/mini/aot-compiler.c b/src/runtime/src/mono/mono/mini/aot-compiler.c index 5349e634ed9..9598e9d3f20 100644 --- a/src/runtime/src/mono/mono/mini/aot-compiler.c +++ b/src/runtime/src/mono/mono/mini/aot-compiler.c @@ -638,7 +638,7 @@ is_direct_pinvoke_enabled (const MonoAotCompile *acfg) /* Wrappers around the image writer functions */ -#define MAX_SYMBOL_SIZE 256 +#define MAX_SYMBOL_SIZE 1024 #if defined(TARGET_WIN32) && defined(TARGET_X86) static const char * diff --git a/src/source-manifest.json b/src/source-manifest.json index 9e6b331554a..a988ed957bc 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -1,10 +1,10 @@ { "repositories": [ { - "barId": 285108, + "barId": 286215, "path": "arcade", "remoteUri": "https://github.com/dotnet/arcade", - "commitSha": "e6f510cb87812d56ad781d93ff0513cdcccd0eb4" + "commitSha": "7ff6478d902606d65aa33cb8cedc2730e1843fe1" }, { "barId": 286219, @@ -61,10 +61,10 @@ "commitSha": "dc755eb75a2a1f6a82036588da128eb859d96e8e" }, { - "barId": 284434, + "barId": 286446, "path": "nuget-client", "remoteUri": "https://github.com/nuget/nuget.client", - "commitSha": "28eeb0947095a716b98b5c34454625708cb3ac76" + "commitSha": "5514d935e3e77d90d931758cf9e2589735b905a3" }, { "barId": 286084, @@ -79,10 +79,10 @@ "commitSha": "23d275e30097136b12a68d1bab4997148361d116" }, { - "barId": 285920, + "barId": 286218, "path": "runtime", "remoteUri": "https://github.com/dotnet/runtime", - "commitSha": "05a3a9ba8860b076afc88a6bf0d455f2c3b522d3" + "commitSha": "d321bc6abef02ed27790e8da3740d253976b9ac6" }, { "barId": 277711,