From f1424575362624c08220f2693106ba9d0c082701 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Mon, 4 Nov 2024 22:41:25 +0000 Subject: [PATCH 1/8] Sign .deb files --- .../tools/Sign.props | 1 + .../FakeSignTool.cs | 5 ++ .../Resources/test.deb | Bin 0 -> 678 bytes .../SignToolTests.cs | 40 +++++++++- .../src/BatchSignUtil.cs | 20 +++++ .../src/Configuration.cs | 12 +++ .../src/FileSignInfo.cs | 5 ++ .../src/RealSignTool.cs | 5 ++ src/Microsoft.DotNet.SignTool/src/SignTool.cs | 1 + .../src/SignToolConstants.cs | 5 +- .../src/ValidationOnlySignTool.cs | 3 + .../src/VerifySignatures.cs | 73 ++++++++++++++++++ 12 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 src/Microsoft.DotNet.SignTool.Tests/Resources/test.deb diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props b/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props index fa601f085e1..1169cb81e7b 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props @@ -50,6 +50,7 @@ a public key token. The certificate can be overriden using the StrongNameSignInfo or the FileSignInfo item group. --> + diff --git a/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs b/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs index 0e0179b0264..359c28ed057 100644 --- a/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs +++ b/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs @@ -60,6 +60,11 @@ private static void SignPEFile(string path) } } + public override bool VerifySignedDeb(string filePath) + { + return true; + } + public override bool VerifySignedPowerShellFile(string filePath) { return true; diff --git a/src/Microsoft.DotNet.SignTool.Tests/Resources/test.deb b/src/Microsoft.DotNet.SignTool.Tests/Resources/test.deb new file mode 100644 index 0000000000000000000000000000000000000000..e6f2d8af44a9c525930a05a5e263fd7d21bdfac3 GIT binary patch literal 678 zcmY$iNi0gvu;WTeP0CEn(@o0EODw8XP*5;5H#RUgH8(XfR8TMg@?oT*fq|KciGl(U zK|unSk)8opa(-S(QGSkINn(*+dKF>)Mi%C9{qo%$3?RV7{PyB~ufql+Y#-vDYn~G> z@%`^K@!^5!#03@emmb%>VXErsc>ms(WR9k)P{%)YTb7))v}D;=GI@<&_pDV>*Is%WLhg{$EkD_^rU4x8djZ>z&sBtpDkk z^8cOwr<{)cF@Cat*WOF|uTJQ)esi?h`1u&0?nx72{xyd`6$i{adQbATPeu00zR%lU z9XZBt$bs7_1hlN@;6(JAE*B4+cVSq zG;7A5821a0PgZpG@0!*xvwYP7*`>1b>w3TB+%3Aq<1VFc9(CSMloRZKB;vsS4}8mF zgB~+zFfeeXB$gz?0~Q!+gyP1~5^LCA-pzMNLBb*NnH}rZt0%U8;@a0(yxKR*N#*6! zziVY>OJ3<(-v1<=U|kTFR8}R@l{9Pdd&{-G{Kul!uPuID$6>`0*}=*a8^0~6%WUbt z>wD{;TbG78UtiVx)qK~6S^rLd?SC2Pwsr2mXGuDLr@xE0jn8`fPw&UZ{iTin_j~{ new SignInfo("PSMCertificate") } }, {".psc1", new List{ new SignInfo("PSCCertificate") } }, {".dylib", new List{ new SignInfo("DylibCertificate") } }, + {".deb", new List{ new SignInfo("LinuxSign") } }, {".dll", new List{ new SignInfo("Microsoft400") } }, // lgtm [cs/common-default-passwords] Safe, these are certificate names {".exe", new List{ new SignInfo("Microsoft400") } }, // lgtm [cs/common-default-passwords] Safe, these are certificate names {".msi", new List{ new SignInfo("Microsoft400") } }, // lgtm [cs/common-default-passwords] Safe, these are certificate names @@ -51,6 +52,7 @@ public class SignToolTests : IDisposable { ".psm1", new List{ new SignInfo("PSMCertificate", collisionPriorityId: "123") } }, { ".psc1", new List{ new SignInfo("PSCCertificate", collisionPriorityId: "123") } }, { ".dylib", new List{ new SignInfo("DylibCertificate", collisionPriorityId: "123") } }, + { ".deb", new List{ new SignInfo("LinuxSign", collisionPriorityId: "123") } }, { ".dll", new List { new SignInfo("Microsoft400", collisionPriorityId: "123"), // lgtm [cs/common-default-passwords] Safe, these are certificate names @@ -97,6 +99,10 @@ public class SignToolTests : IDisposable { "CertificateName", "DylibCertificate" }, { SignToolConstants.CollisionPriorityId, "123" } }), + new TaskItem(".deb", new Dictionary { + { "CertificateName", "LinuxSign" }, + { SignToolConstants.CollisionPriorityId, "123" } + }), new TaskItem(".dll", new Dictionary { { "CertificateName", "Microsoft400" }, // lgtm [cs/common-default-passwords] Safe, these are certificate names { SignToolConstants.CollisionPriorityId, "123" } @@ -231,7 +237,9 @@ public class SignToolTests : IDisposable ".esd", ".py", - ".pyd" + ".pyd", + + ".deb", }; public static IEnumerable GetSignableExtensions() @@ -1206,6 +1214,36 @@ public void SignedSymbolsNupkg() }); } + [Fact] + public void CheckDebSigning() + { + // List of files to be considered for signing + var itemsToSign = new ITaskItem[] + { + new TaskItem(GetResourcePath("test.deb")) + }; + + // Default signing information + var strongNameSignInfo = new Dictionary>(); + + // Overriding information + var fileSignInfo = new Dictionary(); + + ValidateFileSignInfos(itemsToSign, strongNameSignInfo, fileSignInfo, s_fileExtensionSignInfo, new[] + { + "File 'test.deb' Certificate='LinuxSign'" + }); + + ValidateGeneratedProject(itemsToSign, strongNameSignInfo, fileSignInfo, s_fileExtensionSignInfo, new[] + { +$@" + + LinuxSign + +" + }); + } + [Fact] public void CheckPowershellSigning() { diff --git a/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs b/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs index 65fec4b7c29..1949f7b3c36 100644 --- a/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs +++ b/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs @@ -495,6 +495,17 @@ private void VerifyCertificates(TaskLoggingHelper log) log.LogError($"VSIX {fileName} cannot be strong name signed."); } } + else if (fileName.IsDeb()) + { + if (isInvalidEmptyCertificate) + { + log.LogError($"Deb package {fileName} should have a certificate name."); + } + if (!IsLinuxSignCertificate(fileName.SignInfo.Certificate)) + { + log.LogError($"Deb package {fileName} must be signed with a LinuxSign certificate."); + } + } else if (fileName.IsNupkg()) { if(isInvalidEmptyCertificate) @@ -550,6 +561,13 @@ private void VerifyAfterSign(FileSignInfo file) } } } + else if (file.IsDeb()) + { + if (!_signTool.VerifySignedDeb(file.FullPath)) + { + _log.LogError($"Deb package {file.FullPath} is not signed properly."); + } + } else if (file.IsPowerShellScript()) { if (!_signTool.VerifySignedPowerShellFile(file.FullPath)) @@ -621,5 +639,7 @@ private void VerifyStrongNameSigning() } private static bool IsVsixCertificate(string certificate) => certificate.StartsWith("Vsix", StringComparison.OrdinalIgnoreCase); + + private static bool IsLinuxSignCertificate(string certificate) => certificate.StartsWith("LinuxSign", StringComparison.OrdinalIgnoreCase); } } diff --git a/src/Microsoft.DotNet.SignTool/src/Configuration.cs b/src/Microsoft.DotNet.SignTool/src/Configuration.cs index 7f133f856f2..5b490996c0d 100644 --- a/src/Microsoft.DotNet.SignTool/src/Configuration.cs +++ b/src/Microsoft.DotNet.SignTool/src/Configuration.cs @@ -418,6 +418,18 @@ private FileSignInfo ExtractSignInfo( _log.LogMessage(MessageImportance.Low, $"File {file.FullPath} is digitally signed."); } } + else if(FileSignInfo.IsDeb(file.FullPath)) + { + isAlreadySigned = VerifySignatures.VerifySignedDeb(file.FullPath); + if (!isAlreadySigned) + { + _log.LogMessage(MessageImportance.Low, $"File {file.FullPath} is not signed."); + } + else + { + _log.LogMessage(MessageImportance.Low, $"File {file.FullPath} is signed."); + } + } else if(FileSignInfo.IsPowerShellScript(file.FullPath)) { isAlreadySigned = VerifySignatures.VerifySignedPowerShellFile(file.FullPath); diff --git a/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs b/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs index 5aa0b17c4af..0caf8dff9ce 100644 --- a/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs +++ b/src/Microsoft.DotNet.SignTool/src/FileSignInfo.cs @@ -21,6 +21,9 @@ internal readonly struct FileSignInfo // optional file information that allows to disambiguate among multiple files with the same name: internal readonly string TargetFramework; + internal static bool IsDeb(string path) + => Path.GetExtension(path) == ".deb"; + internal static bool IsPEFile(string path) => Path.GetExtension(path) == ".exe" || Path.GetExtension(path) == ".dll"; @@ -59,6 +62,8 @@ internal static bool IsPackage(string path) internal static bool IsZipContainer(string path) => IsPackage(path) || IsMPack(path) || IsZip(path) || IsTarGZip(path); + internal bool IsDeb() => IsDeb(FileName); + internal bool IsPEFile() => IsPEFile(FileName); internal bool IsManaged() => ContentUtil.IsManaged(FullPath); diff --git a/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs b/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs index a2fd51992a3..b1e3ca6cc44 100644 --- a/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs +++ b/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs @@ -129,6 +129,11 @@ public override bool VerifyStrongNameSign(string fileFullPath) return process.ExitCode == 0; } + public override bool VerifySignedDeb(string filePath) + { + return VerifySignatures.VerifySignedDeb(filePath); + } + public override bool VerifySignedPowerShellFile(string filePath) { return VerifySignatures.VerifySignedPowerShellFile(filePath); diff --git a/src/Microsoft.DotNet.SignTool/src/SignTool.cs b/src/Microsoft.DotNet.SignTool/src/SignTool.cs index cc7859f3005..8f04e36b7da 100644 --- a/src/Microsoft.DotNet.SignTool/src/SignTool.cs +++ b/src/Microsoft.DotNet.SignTool/src/SignTool.cs @@ -32,6 +32,7 @@ internal SignTool(SignToolArgs args, TaskLoggingHelper log) public abstract bool LocalStrongNameSign(IBuildEngine buildEngine, int round, IEnumerable files); + public abstract bool VerifySignedDeb(string filePath); public abstract bool VerifySignedPEFile(Stream stream); public abstract bool VerifySignedPowerShellFile(string filePath); public abstract bool VerifySignedNugetFileMarker(string filePath); diff --git a/src/Microsoft.DotNet.SignTool/src/SignToolConstants.cs b/src/Microsoft.DotNet.SignTool/src/SignToolConstants.cs index e93522bfb6d..8a55ed8bc28 100644 --- a/src/Microsoft.DotNet.SignTool/src/SignToolConstants.cs +++ b/src/Microsoft.DotNet.SignTool/src/SignToolConstants.cs @@ -31,7 +31,8 @@ internal static class SignToolConstants public const string MsiEngineExtension = "-engine.exe"; /// /// List of known signable extensions. Copied, removing duplicates, from here: - /// https://microsoft.sharepoint.com/teams/codesigninfo/Wiki/Signable%20Files.aspx + /// https://microsoft.sharepoint.com/teams/prss/Codesign/SitePages/Signable%20Files.aspx + /// ".deb" is not in the list linked above, but it is a known signable extension. /// public static readonly HashSet SignableExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { @@ -110,6 +111,8 @@ internal static class SignToolConstants ".py", ".pyd", + + ".deb", }; /// diff --git a/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs b/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs index 2124d604e1c..f4043db580b 100644 --- a/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs +++ b/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs @@ -49,6 +49,9 @@ public override void RemovePublicSign(string assemblyPath) { } + public override bool VerifySignedDeb(string filePath) + => true; + public override bool VerifySignedPEFile(Stream assemblyStream) => true; diff --git a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs index c7bc3220eaf..6c8ed229233 100644 --- a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs +++ b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs @@ -7,7 +7,10 @@ using System; using System.IO; using System.IO.Compression; +using System.Diagnostics; using System.Linq; +using System.Net.Http; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -16,6 +19,53 @@ namespace Microsoft.DotNet.SignTool { internal class VerifySignatures { + internal static bool VerifySignedDeb(string filePath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // We cannot check the signature of a .deb file on Windows. + return true; + } + + string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(tempDir); + + // https://microsoft.sharepoint.com/teams/prss/esrp/info/SitePages/Linux%20GPG%20Signing.aspx + try + { + // Download the Microsoft public key + using (HttpClient client = new HttpClient()) + { + using (Stream stream = client.GetStreamAsync("https://packages.microsoft.com/keys/microsoft.asc").Result) + { + using (FileStream fileStream = File.Create($"{tempDir}/microsoft.asc")) + { + stream.CopyTo(fileStream); + } + } + } + + RunCommand($"ar x {filePath} --output {tempDir}"); + RunCommand($"gpg --import {tempDir}/microsoft.asc"); + RunCommand($"cat {tempDir}/debian-binary {tempDir}/control.tar.gz {tempDir}/data.tar.gz > {tempDir}/combined-contents"); + string output = RunCommand($"gpg --verify {tempDir}/_gpgorigin {tempDir}/combined-contents"); + if (output.Contains("Good signature")) + { + return true; + } + + return false; + } + catch(Exception) + { + return false; + } + finally + { + Directory.Delete(tempDir, true); + } + } + internal static bool VerifySignedPowerShellFile(string filePath) { return File.ReadLines(filePath).Any(line => line.IndexOf("# SIG # Begin Signature Block", StringComparison.OrdinalIgnoreCase) >= 0); @@ -121,5 +171,28 @@ internal static bool IsDigitallySigned(string fullPath) } return certificate.Verify(); } + + private static string RunCommand(string command) + { + var psi = new ProcessStartInfo + { + FileName = "bash", + Arguments = $"-c \"{command}\"", + RedirectStandardOutput = true, + RedirectStandardError = false, + UseShellExecute = false, + CreateNoWindow = true + }; + + using (var process = Process.Start(psi)) + { + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception($"Command '{command}' failed with exit code {process.ExitCode}"); + } + return process.StandardOutput.ReadToEnd(); + } + } } } From 949dafc5e36b5e67834f38469c09e9d1317de040 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Mon, 4 Nov 2024 23:50:47 +0000 Subject: [PATCH 2/8] Set CollisionPriorityId --- src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props b/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props index 1169cb81e7b..aa4c0ff4188 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props @@ -50,7 +50,11 @@ a public key token. The certificate can be overriden using the StrongNameSignInfo or the FileSignInfo item group. --> - + + From 05ecf2c13a54d7d0ddb0aef2ba4a62cbbba19462 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Tue, 5 Nov 2024 23:53:02 +0000 Subject: [PATCH 3/8] Log failing signing validation task --- src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs | 2 +- src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs | 8 ++++---- src/Microsoft.DotNet.SignTool/src/Configuration.cs | 2 +- src/Microsoft.DotNet.SignTool/src/RealSignTool.cs | 4 ++-- src/Microsoft.DotNet.SignTool/src/SignTool.cs | 2 +- .../src/ValidationOnlySignTool.cs | 2 +- src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs | 7 +++++-- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs b/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs index 359c28ed057..aca1cf628c0 100644 --- a/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs +++ b/src/Microsoft.DotNet.SignTool.Tests/FakeSignTool.cs @@ -60,7 +60,7 @@ private static void SignPEFile(string path) } } - public override bool VerifySignedDeb(string filePath) + public override bool VerifySignedDeb(TaskLoggingHelper log, string filePath) { return true; } diff --git a/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs b/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs index 1949f7b3c36..5b591aa8a69 100644 --- a/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs +++ b/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs @@ -84,7 +84,7 @@ internal void Go(bool doStrongNameCheck) // This is a recursive process since we process nested containers. foreach (var file in _batchData.FilesToSign) { - VerifyAfterSign(file); + VerifyAfterSign(_log, file); } if (_log.HasLoggedErrors) @@ -545,7 +545,7 @@ private void VerifyCertificates(TaskLoggingHelper log) } } - private void VerifyAfterSign(FileSignInfo file) + private void VerifyAfterSign(TaskLoggingHelper log, FileSignInfo file) { if (file.IsPEFile()) { @@ -563,7 +563,7 @@ private void VerifyAfterSign(FileSignInfo file) } else if (file.IsDeb()) { - if (!_signTool.VerifySignedDeb(file.FullPath)) + if (!_signTool.VerifySignedDeb(log, file.FullPath)) { _log.LogError($"Deb package {file.FullPath} is not signed properly."); } @@ -600,7 +600,7 @@ private void VerifyAfterSign(FileSignInfo file) continue; } - VerifyAfterSign(zipPart.Value.FileSignInfo); + VerifyAfterSign(_log, zipPart.Value.FileSignInfo); } if (!SkipZipContainerSignatureMarkerCheck) diff --git a/src/Microsoft.DotNet.SignTool/src/Configuration.cs b/src/Microsoft.DotNet.SignTool/src/Configuration.cs index 5b490996c0d..ef684bc61ec 100644 --- a/src/Microsoft.DotNet.SignTool/src/Configuration.cs +++ b/src/Microsoft.DotNet.SignTool/src/Configuration.cs @@ -420,7 +420,7 @@ private FileSignInfo ExtractSignInfo( } else if(FileSignInfo.IsDeb(file.FullPath)) { - isAlreadySigned = VerifySignatures.VerifySignedDeb(file.FullPath); + isAlreadySigned = VerifySignatures.VerifySignedDeb(_log, file.FullPath); if (!isAlreadySigned) { _log.LogMessage(MessageImportance.Low, $"File {file.FullPath} is not signed."); diff --git a/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs b/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs index b1e3ca6cc44..27bd7350f66 100644 --- a/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs +++ b/src/Microsoft.DotNet.SignTool/src/RealSignTool.cs @@ -129,9 +129,9 @@ public override bool VerifyStrongNameSign(string fileFullPath) return process.ExitCode == 0; } - public override bool VerifySignedDeb(string filePath) + public override bool VerifySignedDeb(TaskLoggingHelper log, string filePath) { - return VerifySignatures.VerifySignedDeb(filePath); + return VerifySignatures.VerifySignedDeb(log, filePath); } public override bool VerifySignedPowerShellFile(string filePath) diff --git a/src/Microsoft.DotNet.SignTool/src/SignTool.cs b/src/Microsoft.DotNet.SignTool/src/SignTool.cs index 8f04e36b7da..9029c9f34da 100644 --- a/src/Microsoft.DotNet.SignTool/src/SignTool.cs +++ b/src/Microsoft.DotNet.SignTool/src/SignTool.cs @@ -32,7 +32,7 @@ internal SignTool(SignToolArgs args, TaskLoggingHelper log) public abstract bool LocalStrongNameSign(IBuildEngine buildEngine, int round, IEnumerable files); - public abstract bool VerifySignedDeb(string filePath); + public abstract bool VerifySignedDeb(TaskLoggingHelper log, string filePath); public abstract bool VerifySignedPEFile(Stream stream); public abstract bool VerifySignedPowerShellFile(string filePath); public abstract bool VerifySignedNugetFileMarker(string filePath); diff --git a/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs b/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs index f4043db580b..b3499ef4635 100644 --- a/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs +++ b/src/Microsoft.DotNet.SignTool/src/ValidationOnlySignTool.cs @@ -49,7 +49,7 @@ public override void RemovePublicSign(string assemblyPath) { } - public override bool VerifySignedDeb(string filePath) + public override bool VerifySignedDeb(TaskLoggingHelper log, string filePath) => true; public override bool VerifySignedPEFile(Stream assemblyStream) diff --git a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs index 6c8ed229233..2774b5d3621 100644 --- a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs +++ b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; using NuGet.Common; using NuGet.Packaging; using NuGet.Packaging.Signing; @@ -19,7 +21,7 @@ namespace Microsoft.DotNet.SignTool { internal class VerifySignatures { - internal static bool VerifySignedDeb(string filePath) + internal static bool VerifySignedDeb(TaskLoggingHelper log, string filePath) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -56,8 +58,9 @@ internal static bool VerifySignedDeb(string filePath) return false; } - catch(Exception) + catch(Exception e) { + log.LogMessage(MessageImportance.Low, $"Failed to verify signature of {filePath} with the following error: {e.Message}"); return false; } finally From bb468802cd6a73d7adb9ad0f66d8107bc075e9c8 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Thu, 7 Nov 2024 17:51:27 +0000 Subject: [PATCH 4/8] Don't return true when running on Windows --- src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs | 7 ++++++- src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs b/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs index 5b591aa8a69..b07fb547c0d 100644 --- a/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs +++ b/src/Microsoft.DotNet.SignTool/src/BatchSignUtil.cs @@ -9,6 +9,7 @@ using System.IO; using System.IO.Compression; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using TaskLoggingHelper = Microsoft.Build.Utilities.TaskLoggingHelper; @@ -563,7 +564,11 @@ private void VerifyAfterSign(TaskLoggingHelper log, FileSignInfo file) } else if (file.IsDeb()) { - if (!_signTool.VerifySignedDeb(log, file.FullPath)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + _log.LogMessage(MessageImportance.Low, $"Skipping signature verification of {file.FullPath} on Windows."); + } + else if (!_signTool.VerifySignedDeb(log, file.FullPath)) { _log.LogError($"Deb package {file.FullPath} is not signed properly."); } diff --git a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs index 2774b5d3621..60edbfcbbb7 100644 --- a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs +++ b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs @@ -26,7 +26,8 @@ internal static bool VerifySignedDeb(TaskLoggingHelper log, string filePath) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // We cannot check the signature of a .deb file on Windows. - return true; + log.LogMessage(MessageImportance.Low, $"Skipping signature verification of {filePath} on Windows."); + return false; } string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); From 9752401d66ede30446cd9cf27a28e7258de11060 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Thu, 7 Nov 2024 23:23:39 +0000 Subject: [PATCH 5/8] Remove CollisionPriorityId --- src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props b/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props index aa4c0ff4188..1169cb81e7b 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props +++ b/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.props @@ -50,11 +50,7 @@ a public key token. The certificate can be overriden using the StrongNameSignInfo or the FileSignInfo item group. --> - - + From bd829748cf208fb93cf3c2569fa5a43ec2f81d66 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 8 Nov 2024 18:14:06 +0000 Subject: [PATCH 6/8] PR Feedback --- Directory.Packages.props | 1 + eng/BuildTask.Packages.props | 1 + eng/Version.Details.xml | 4 +++ eng/Versions.props | 1 + .../Microsoft.DotNet.SignTool.csproj | 2 ++ .../src/VerifySignatures.cs | 30 ++++++++++++------- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 416d003221e..93b2e5f4176 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -55,6 +55,7 @@ + diff --git a/eng/BuildTask.Packages.props b/eng/BuildTask.Packages.props index a8fa8326ed4..0ce335e1610 100644 --- a/eng/BuildTask.Packages.props +++ b/eng/BuildTask.Packages.props @@ -15,6 +15,7 @@ + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4be278f16c1..8985f35d1cb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,6 +90,10 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 990ebf52fc408ca45929fd176d2740675a67fab8 + + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime + 990ebf52fc408ca45929fd176d2740675a67fab8 + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime 990ebf52fc408ca45929fd176d2740675a67fab8 diff --git a/eng/Versions.props b/eng/Versions.props index 7de3fec4c45..eb41e734bc5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -47,6 +47,7 @@ 9.0.0-rc.2.24473.5 9.0.0-rc.2.24473.5 9.0.0-rc.2.24473.5 + 9.0.0-rc.2.24473.5 9.0.0-rc.2.24473.5 9.0.0-rc.2.24473.5 9.0.0-rc.2.24473.5 diff --git a/src/Microsoft.DotNet.SignTool/Microsoft.DotNet.SignTool.csproj b/src/Microsoft.DotNet.SignTool/Microsoft.DotNet.SignTool.csproj index 54cd086b534..180af88d557 100644 --- a/src/Microsoft.DotNet.SignTool/Microsoft.DotNet.SignTool.csproj +++ b/src/Microsoft.DotNet.SignTool/Microsoft.DotNet.SignTool.csproj @@ -25,6 +25,8 @@ + + diff --git a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs index 60edbfcbbb7..40c37399c39 100644 --- a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs +++ b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs @@ -3,6 +3,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using Microsoft.Extensions.DependencyInjection; using NuGet.Common; using NuGet.Packaging; using NuGet.Packaging.Signing; @@ -16,11 +17,19 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; +using System.Runtime.Remoting; namespace Microsoft.DotNet.SignTool { internal class VerifySignatures { +#if NETFRAMEWORK + private static IServiceProvider serviceProvider; + private static IHttpClientFactory httpClientFactory; + private static HttpClient client; +#else + private static readonly HttpClient client = new(new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(10) }); +#endif internal static bool VerifySignedDeb(TaskLoggingHelper log, string filePath) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -36,15 +45,17 @@ internal static bool VerifySignedDeb(TaskLoggingHelper log, string filePath) // https://microsoft.sharepoint.com/teams/prss/esrp/info/SitePages/Linux%20GPG%20Signing.aspx try { +#if NETFRAMEWORK + serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); + httpClientFactory = serviceProvider.GetRequiredService(); + client = httpClientFactory.CreateClient(); +#endif // Download the Microsoft public key - using (HttpClient client = new HttpClient()) + using (Stream stream = client.GetStreamAsync("https://packages.microsoft.com/keys/microsoft.asc").Result) { - using (Stream stream = client.GetStreamAsync("https://packages.microsoft.com/keys/microsoft.asc").Result) + using (FileStream fileStream = File.Create($"{tempDir}/microsoft.asc")) { - using (FileStream fileStream = File.Create($"{tempDir}/microsoft.asc")) - { - stream.CopyTo(fileStream); - } + stream.CopyTo(fileStream); } } @@ -55,13 +66,12 @@ internal static bool VerifySignedDeb(TaskLoggingHelper log, string filePath) if (output.Contains("Good signature")) { return true; - } - + } return false; } catch(Exception e) { - log.LogMessage(MessageImportance.Low, $"Failed to verify signature of {filePath} with the following error: {e.Message}"); + log.LogMessage(MessageImportance.Low, $"Failed to verify signature of {filePath} with the following error: {e}"); return false; } finally @@ -190,7 +200,7 @@ private static string RunCommand(string command) using (var process = Process.Start(psi)) { - process.WaitForExit(); + process.WaitForExit(3000); // 3 seconds if (process.ExitCode != 0) { throw new Exception($"Command '{command}' failed with exit code {process.ExitCode}"); From 24c7de55ddd62836a87612771ec615535245b3a9 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 8 Nov 2024 18:58:42 +0000 Subject: [PATCH 7/8] Nit --- src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs index 40c37399c39..694a71b8f37 100644 --- a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs +++ b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs @@ -17,7 +17,6 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; -using System.Runtime.Remoting; namespace Microsoft.DotNet.SignTool { From 0cccccd4dc206959bb1c9f559b35cfe8487e7aa7 Mon Sep 17 00:00:00 2001 From: Ella Hathaway Date: Fri, 8 Nov 2024 22:15:47 +0000 Subject: [PATCH 8/8] Increase timeout to 10 seconds --- src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs index 694a71b8f37..be2a49a6d7f 100644 --- a/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs +++ b/src/Microsoft.DotNet.SignTool/src/VerifySignatures.cs @@ -199,7 +199,7 @@ private static string RunCommand(string command) using (var process = Process.Start(psi)) { - process.WaitForExit(3000); // 3 seconds + process.WaitForExit(10000); // 10 seconds if (process.ExitCode != 0) { throw new Exception($"Command '{command}' failed with exit code {process.ExitCode}");