Finish up code signing fix, hopefully HSM's will work properly now!

This commit is contained in:
Caelan Sayler
2024-02-02 17:05:29 +00:00
parent a3828fc6a6
commit f030a90491
2 changed files with 35 additions and 141 deletions

View File

@@ -74,34 +74,15 @@ public class CodeSign
}
var filesToSignStr = String.Join(" ", filesToSign.Select(f => $"\"{f}\""));
var command = $"/S /C \"\"{HelperFile.SignToolPath}\" sign {signArguments} {filesToSignStr} >> \"{signLogFile}\" 2>&1\"";
var psi = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = command,
UseShellExecute = false,
WorkingDirectory = rootDir,
CreateNoWindow = true
};
var process = Process.Start(psi);
process.WaitForExit();
if (process.ExitCode != 0) {
var cmdWithPasswordHidden = "cmd.exe " + new Regex(@"\/p\s+?[^\s]+").Replace(command, "/p ********");
Log.Debug($"Signing command failed: {cmdWithPasswordHidden}");
var output = File.Exists(signLogFile) ? File.ReadAllText(signLogFile).Trim() : "No output file was created.";
throw new UserInfoException(
$"Signing command failed. Specify --verbose argument to print signing command.\n" +
$"Output was:" + Environment.NewLine + output);
}
var command = $"\"{HelperFile.SignToolPath}\" sign {signArguments} {filesToSignStr}";
RunSigningCommand(command, rootDir, signLogFile);
int processed = totalToSign - pendingSign.Count;
Log.Info($"Code-signed {processed}/{totalToSign} files");
progress((int) ((double) processed / totalToSign * 100));
} while (pendingSign.Count > 0);
Log.Info("SignTool Output: " + Environment.NewLine + File.ReadAllText(signLogFile).Trim());
Log.Debug("SignTool Output: " + Environment.NewLine + File.ReadAllText(signLogFile).Trim());
}
public void SignPEFileWithTemplate(string filePath, string signTemplate)
@@ -111,129 +92,38 @@ public class CodeSign
return;
}
using var _1 = Utility.GetTempFileName(out var signLogFile);
var command = signTemplate.Replace("\"{{file}}\"", "{{file}}").Replace("{{file}}", $"\"{filePath}\"");
var result = Exe.InvokeProcess(command, null, null);
if (result.ExitCode != 0) {
var cmdWithPasswordHidden = new Regex(@"\/p\s+?[^\s]+").Replace(result.Command, "/p ********");
Log.Debug($"Signing command failed: {cmdWithPasswordHidden}");
throw new Exception(
$"Signing command failed. Specify --verbose argument to print signing command.\n\n" +
$"Output was:\n" + result.StdOutput);
}
Log.Info("Sign successful: " + result.StdOutput);
RunSigningCommand(command, Path.GetDirectoryName(filePath), signLogFile);
Log.Debug("SignTool Output: " + Environment.NewLine + File.ReadAllText(signLogFile).Trim());
}
//private static ProcessStartInfo CreateProcessStartInfo(string fileName, string arguments, string workingDirectory = "")
//{
// var psi = new ProcessStartInfo(fileName, arguments);
// psi.UseShellExecute = false;
// psi.WindowStyle = ProcessWindowStyle.Hidden;
// psi.ErrorDialog = false;
// psi.CreateNoWindow = true;
// psi.RedirectStandardOutput = true;
// psi.RedirectStandardError = true;
// psi.WorkingDirectory = workingDirectory;
// return psi;
//}
private void RunSigningCommand(string command, string workDir, string signLogFile)
{
// here we invoke signtool.exe with 'cmd.exe /C' and redirect output to a file, because something
// about how the dotnet tool host works prevents signtool from being able to open a token password
// prompt, meaning signing fails for those with an HSM.
//private void SignPEFile(string filePath, string signParams, string signTemplate)
//{
// try {
// if (AuthenticodeTools.IsTrusted(filePath)) {
// Log.Debug($"'{filePath}' is already signed, skipping...");
// return;
// }
// } catch (Exception ex) {
// Log.Error(ex, "Failed to determine signing status for " + filePath);
// }
string args = $"/S /C \"{command} >> \"{signLogFile}\" 2>&1\"";
// string cmd;
// ProcessStartInfo psi;
// if (!String.IsNullOrEmpty(signParams)) {
// // use embedded signtool.exe with provided parameters
// cmd = $"sign {signParams} \"{filePath}\"";
// psi = CreateProcessStartInfo(HelperFile.SignToolPath, cmd);
// cmd = "signtool.exe " + cmd;
// } else if (!String.IsNullOrEmpty(signTemplate)) {
// // escape custom sign command and pass it to cmd.exe
// cmd = signTemplate.Replace("\"{{file}}\"", "{{file}}").Replace("{{file}}", $"\"{filePath}\"");
// psi = CreateProcessStartInfo("cmd", $"/c {EscapeCmdExeMetachars(cmd)}");
// } else {
// Log.Debug($"{filePath} was not signed. (skipped; no signing parameters)");
// return;
// }
var psi = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = args,
UseShellExecute = false,
WorkingDirectory = workDir,
CreateNoWindow = true,
};
// var processResult = InvokeProcessUnsafeAsync(psi, CancellationToken.None)
// .ConfigureAwait(false).GetAwaiter().GetResult();
var process = Process.Start(psi);
process.WaitForExit();
// if (processResult.ExitCode != 0) {
// var cmdWithPasswordHidden = new Regex(@"/p\s+\w+").Replace(cmd, "/p ********");
// throw new Exception("Signing command failed: \n > " + cmdWithPasswordHidden + "\n" + processResult.StdOutput);
// } else {
// Log.Info("Sign successful: " + processResult.StdOutput);
// }
//}
//private static string EscapeCmdExeMetachars(string command)
//{
// var result = new StringBuilder();
// foreach (var ch in command) {
// switch (ch) {
// case '(':
// case ')':
// case '%':
// case '!':
// case '^':
// case '"':
// case '<':
// case '>':
// case '&':
// case '|':
// result.Append('^');
// break;
// }
// result.Append(ch);
// }
// return result.ToString();
//}
//private class ProcessResult
//{
// public int ExitCode { get; set; }
// public string StdOutput { get; set; }
// public ProcessResult(int exitCode, string stdOutput)
// {
// ExitCode = exitCode;
// StdOutput = stdOutput;
// }
//}
//private static async Task<ProcessResult> InvokeProcessUnsafeAsync(ProcessStartInfo psi, CancellationToken ct)
//{
// var pi = Process.Start(psi);
// await Task.Run(() => {
// while (!ct.IsCancellationRequested) {
// if (pi.WaitForExit(2000)) return;
// }
// if (ct.IsCancellationRequested) {
// pi.Kill();
// ct.ThrowIfCancellationRequested();
// }
// }).ConfigureAwait(false);
// string textResult = await pi.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
// if (String.IsNullOrWhiteSpace(textResult) || pi.ExitCode != 0) {
// textResult = (textResult ?? "") + "\n" + await pi.StandardError.ReadToEndAsync().ConfigureAwait(false);
// if (String.IsNullOrWhiteSpace(textResult)) {
// textResult = String.Empty;
// }
// }
// return new ProcessResult(pi.ExitCode, textResult.Trim());
//}
if (process.ExitCode != 0) {
var cmdWithPasswordHidden = "cmd.exe " + new Regex(@"\/p\s+?[^\s]+").Replace(command, "/p ********");
Log.Debug($"Signing command failed: {cmdWithPasswordHidden}");
var output = File.Exists(signLogFile) ? File.ReadAllText(signLogFile).Trim() : "No output file was created.";
throw new UserInfoException(
$"Signing command failed. Specify --verbose argument to print signing command." + Environment.NewLine +
$"Output was:" + Environment.NewLine + output);
}
}
}

View File

@@ -226,7 +226,11 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
if (!VelopackRuntimeInfo.IsWindows) return;
if (!string.IsNullOrEmpty(signParams)) {
Log.Info($"Preparing to sign {filePaths.Length} files with embedded signtool.exe with parallelism of {signParallel}");
string message = $"Preparing to sign {filePaths.Length} files with embedded signtool.exe";
if (signParallel > 1 && filePaths.Length > 1) {
message += $" with parallelism of {signParallel}";
}
Log.Info(message);
helper.SignPEFilesWithSignTool(rootDir, filePaths, signParams, signParallel, progress);
}
}