static void SignFilesWithSignTool( IReadOnlyCollection<string> files, string certificatePath, string certificatePassword, string display = "", string displayUrl = "") { if (!File.Exists(certificatePath)) throw new Exception($"The code-signing certificate was not found at {certificatePath}"); Log.Information("Signing {FilesCount} files using certificate at '{CertificatePath}'...", files.Count, certificatePath); TrySignTaskWithEachTimestampUrlUntilSuccess(url => SignToolTasks.SignTool(_ => _.SetFileDigestAlgorithm(SignToolDigestAlgorithm.SHA256) .SetFile(certificatePath) .SetPassword(certificatePassword) .SetDescription(display) .SetUrl(displayUrl) .SetRfc3161TimestampServerUrl(url) .SetTimestampServerDigestAlgorithm(SignToolDigestAlgorithm.SHA256) .AddFiles(files))); Log.Information("Finished signing {FilesCount} files", files.Count); }
public static void SignAssemblies(string password, params string[] fileNames) { SignToolSettings settings = new SignToolSettings() .SetFileDigestAlgorithm("SHA256") .SetFile(CertFileName) .SetFiles(fileNames) .SetPassword(password) .SetTimestampServerDigestAlgorithm("SHA256") .SetRfc3161TimestampServerUrl("http://timestamp.digicert.com"); SignToolTasks.SignTool(settings); }
void SignWithSignTool(IEnumerable <string> files, string url) { Logger.Info("Signing files using signtool."); SignToolTasks.SignToolLogger = LogStdErrAsWarning; SignToolTasks.SignTool(_ => _ .SetFile(SigningCertificatePath) .SetPassword(SigningCertificatePassword) .SetFiles(files) .SetProcessToolPath(RootDirectory / "certificates" / "signtool.exe") .SetTimestampServerDigestAlgorithm("sha256") .SetDescription("Octopus CLI") .SetUrl("https://octopus.com") .SetRfc3161TimestampServerUrl(url)); }
private void SignFilesIfRequirementsMet(string filePath = null) { if (string.IsNullOrWhiteSpace(CodeSigningCertBase64)) { Logger.Normal("Skipping file signing due to no certificate being provided"); return; } var filesToSign = filePath == null // If no file path is specified, we sign all *.exe and *.dll files // in the output directory that have 'OpenProject' in their filename ? GlobFiles(OutputDirectory, "**/*OpenProject*.exe") .Concat(GlobFiles(OutputDirectory, "**/*OpenProject*.dll")) .Where(file => !_alreadySignedFiles.Contains(file)) .Distinct() .ToList() // In case a file path is given directly, we're using that : new[] { filePath }.ToList(); filesToSign.ForEach(f => _alreadySignedFiles.Add(f)); if (filesToSign.Any()) { var certFilePath = OutputDirectory / $"{Guid.NewGuid()}-cert.pfx"; var certContent = Convert.FromBase64String(CodeSigningCertBase64); WriteAllBytes(certFilePath, certContent); Logger.Normal($"Signing files:{Environment.NewLine}{filesToSign.Aggregate((c, n) => c + Environment.NewLine + n)}"); try { SignToolTasks .SignTool(c => c .SetFileDigestAlgorithm("SHA256") .SetFile(certFilePath) .SetFiles(filesToSign) .SetPassword(CodeSigningCertPassword) .SetTimestampServerDigestAlgorithm("SHA256") .SetRfc3161TimestampServerUrl("http://timestamp.digicert.com") ); } finally { DeleteFile(certFilePath); } } }
async Task SignFiles(IEnumerable <AbsolutePath> filesToSign) { // To create a pfx certificate for local testing, use powershell and run: // $outputLocation = "test_cert.pfx" // $cert = New-SelfSignedCertificate -DnsName sample.contoso.com -Type CodeSigning -CertStoreLocation Cert:\CurrentUser\My // $CertPassword = ConvertTo-SecureString -String "Passw0rd" -Force –AsPlainText // Export-PfxCertificate -Cert "cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath $outputLocation -Password $CertPassword var tempFileName = Path.GetTempFileName(); const string timestampServer = "http://timestamp.digicert.com/"; try { var(certPath, certPassword) = UseTestPfxCertificate ? (@"test_cert.pfx", "Passw0rd") : await GetSigningMaterial(tempFileName); Logger.Info("Signing material retrieved"); var binaries = filesToSign .Where(x => !x.ToString().EndsWith(".nupkg")) .ToList(); if (binaries.Any()) { Logger.Info("Signing binaries..."); binaries.ForEach(file => SignBinary(certPath, certPassword, file)); Logger.Info("Binary signing complete"); } var nupkgs = filesToSign .Where(x => x.ToString().EndsWith(".nupkg")) .ToList(); if (nupkgs.Any()) { Logger.Info("Signing NuGet packages..."); nupkgs.ForEach(file => SignNuGet(certPath, certPassword, file)); Logger.Info("NuGet signing complete"); } } finally { File.Delete(tempFileName); } return; void SignBinary(string certPath, string certPassword, AbsolutePath binaryPath) { Logger.Info($"Signing {binaryPath}"); SignToolTasks.SignTool( x => x .SetFiles(binaryPath) .SetFile(certPath) .SetPassword(certPassword) .SetTimestampServerUrl(timestampServer) ); } void SignNuGet(string certPath, string certPassword, AbsolutePath binaryPath) { Logger.Info($"Signing {binaryPath}"); // nuke doesn't expose the sign tool try { NuGetTasks.NuGet( $"sign \"{binaryPath}\"" + $" -CertificatePath {certPath}" + $" -CertificatePassword {certPassword}" + $" -Timestamper {timestampServer} -NonInteractive", logOutput: false, logInvocation: false, logTimestamp: false); // don't print to std out/err } catch (Exception) { // Exception doesn't say anything useful generally and don't want to expose it if it does // so don't log it Logger.Error($"Failed to sign nuget package '{binaryPath}"); } } async Task <(string CertificateFilePath, string Password)> GetSigningMaterial(string keyFile) { // Get the signing keys from SSM var pfxB64EncodedPart1 = await GetFileValueFromSsmUsingAmazonSdk("keygen.dd_win_agent_codesign.pfx_b64_0"); var pfxB64EncodedPart2 = await GetFileValueFromSsmUsingAmazonSdk("keygen.dd_win_agent_codesign.pfx_b64_1"); var pfxPassword = await GetFileValueFromSsmUsingAmazonSdk("keygen.dd_win_agent_codesign.password"); var pfxB64Encoded = pfxB64EncodedPart1 + pfxB64EncodedPart2; Logger.Info($"Retrieved base64 encoded pfx. Length: {pfxB64Encoded.Length}"); var pfxB64Decoded = Convert.FromBase64String(pfxB64Encoded); Logger.Info($"Writing key material to temporary file {keyFile}"); File.WriteAllBytes(keyFile, pfxB64Decoded); Logger.Info("Verifying key material"); var file = new X509Certificate2(keyFile, pfxPassword); file.Verify(); return(CertificateFilePath : keyFile, Password : pfxPassword);