I am using using signtool.exe v6.2.9200.20527 for /tr and /td switch support. In the following examples 0961...35d2 is the SHA1 thumbprint of a SHA256 Code Signing certificate in the current user's Personal > Certificates store.
Example 1: Code signing with a SHA256 digest, no timestamp.
c:signtool.exe sign /fd sha256 /sha1 0961...35d2 CertificateCheck.exe
c:signtool.exe verify /all /pa CertificateCheck.exe
File: CertificateCheck.exe
Index Algorithm Timestamp
========================================
0 sha256 None
Successfully verified: CertificateCheck.exe
Example 2: Code signing with a SHA1 digest, no timestamp.
c:signtool.exe sign /fd sha1 /sha1 0961...35d2 CertificateCheck.exe
c:signtool.exe verify /all /pa CertificateCheck.exe
File: CertificateCheck.exe
Index Algorithm Timestamp
========================================
0 sha1 None
Successfully verified: CertificateCheck.exe
Example 3: Double-signing with a SHA256 digest and a SHA1 digest and with timestamping.
c:signtool.exe sign /fd sha256 /sha1 0961...35d2 /tr http://timestamp.globalsign.com/scripts/timstamp.dll /td sha256 CertificateCheck.exe
c:signtool.exe sign /as /fd sha1 /sha1 0961...35d2 /tr http://timestamp.globalsign.com/scripts/timstamp.dll /td sha1 CertificateCheck.exe
c:signtool.exe verify /all /pa CertificateCheck.exe
File: CertificateCheck.exe
Index Algorithm Timestamp
========================================
0 sha256 RFC3161
1 sha1 RFC3161
Using signtool verify /v I can also see the certificate details and certificate trust chain...
c:signtool.exe verify /all /pa /v CertificateCheck.exe
Verifying: CertificateCheck.exe
Signature Index: 0 (Primary Signature)
Hash of file (sha256): 6774...B2D1
Signing Certificate Chain:
Issued to: GlobalSign
Issued by: GlobalSign
Expires: Sun Mar 18 20:00:00 2029
SHA1 hash: D69B...76AD
Issued to: GlobalSign CodeSigning CA - SHA256 - G2
Issued by: GlobalSign
Expires: Fri Aug 02 20:00:00 2019
SHA1 hash: 4E34...36FF
Issued to: Example Company Pty Ltd
Issued by: GlobalSign CodeSigning CA - SHA256 - G2
Expires: Fri May 11 02:17:24 2018
SHA1 hash: 0961...35D2
The signature is timestamped: Wed May 06 13:51:05 2015
Timestamp Verified by:
Issued to: GlobalSign Root CA
Issued by: GlobalSign Root CA
Expires: Fri Jan 28 22:00:00 2028
SHA1 hash: B1BC...829C
Issued to: GlobalSign Timestamping CA - G2
Issued by: GlobalSign Root CA
Expires: Fri Jan 28 22:00:00 2028
SHA1 hash: C0E4...5B71
Issued to: GlobalSign TSA for Standard - G2
Issued by: GlobalSign Timestamping CA - G2
Expires: Tue Mar 03 10:00:00 2026
SHA1 hash: 19E1...65B6
Signature Index: 1
Hash of file (sha1): CFA4...7863
Signing Certificate Chain:
Issued to: GlobalSign
Issued by: GlobalSign
Expires: Sun Mar 18 20:00:00 2029
SHA1 hash: D69B...76AD
Issued to: GlobalSign CodeSigning CA - SHA256 - G2
Issued by: GlobalSign
Expires: Fri Aug 02 20:00:00 2019
SHA1 hash: 4E34...36FF
Issued to: Example Company Pty Ltd
Issued by: GlobalSign CodeSigning CA - SHA256 - G2
Expires: Fri May 11 02:17:24 2018
SHA1 hash: 0961...35D2
The signature is timestamped: Wed May 06 13:51:06 2015
Timestamp Verified by:
Issued to: GlobalSign Root CA
Issued by: GlobalSign Root CA
Expires: Fri Jan 28 22:00:00 2028
SHA1 hash: B1BC...829C
Issued to: GlobalSign Timestamping CA - G2
Issued by: GlobalSign Root CA
Expires: Fri Jan 28 22:00:00 2028
SHA1 hash: C0E4...5B71
Issued to: GlobalSign TSA for Standard - G2
Issued by: GlobalSign Timestamping CA - G2
Expires: Tue Mar 03 10:00:00 2026
SHA1 hash: 19E1...65B6
Successfully verified: CertificateCheck.exe
Number of signatures successfully Verified: 2
Number of warnings: 0
Number of errors: 0
We also double-sign our ClickOnce .application and .manifest files using a combination of Mage.exe and SignTool.exe but SignTool Verify doesn't seem to work with .application and .manifest files:
c:signtool.exe verify /all /pa /v CertificateCheck.application
Verifying: CertificateCheck.application
SignTool Error: This file format cannot be verified because it is not recognized.
Number of signatures successfully Verified: 0
Number of warnings: 0
Number of errors: 1
c:signtool.exe verify /all /pa /v CertificateCheck.exe.manifest
Verifying: CertificateCheck.exe.manifest
SignTool Error: This file format cannot be verified because it is not recognized.
Number of signatures successfully Verified: 0
Number of warnings: 0
Number of errors: 1
We can open the .manifest and .application files in an XML-capable editor to see that the base64-encoded signatures have actually been added but is there an equivalent to SignTool Verify that allows me to see the signatures and/or certificate trust chains attached from the command line? Or am I just driving it wrong? I'd like to do this so that we can add a testing step to our build scripts.
More information...
Ok, this seems to be a version-related issue.
I've gathered up a few different versions of SignTool to try various things. The v5 series had various Verify /manifest switches whereas none of the v6 series I've encountered do. On the other hand the v6 series support SHA2 certificates and algorithms whereas the v5 series do not like them particularly much.
Using signtool.exe v5.2.3790.2568 I can check the strong name (application identity) with this:
signtool verify /manifest /snonly /v CertificateChecker.application
Successfully verified: CertificateChecker.application
Number of files successfully Verified: 1
Number of warnings: 0
Number of errors: 0
But if I try to show the certificate trust chain (and there's a SHA256 certificate in it) it will error:
signtool verify /manifest /pa /v CertificateChecker.application
SignTool Error: CryptVerifyManifestFile returned error: 0x800B0004
The subject is not trusted for the specified action.
Signing Certificate Chain:
Issued to: GlobalSign
Issued by: GlobalSign
Expires: 2029-03-18 8:00:00 PM
SHA1 hash: D69B...76AD
Issued to: GlobalSign CodeSigning CA - SHA256 - G2
Issued by: GlobalSign
Expires: 2019-08-02 8:00:00 PM
SHA1 hash: 4E34...A36FF
Issued to: Example Pty Ltd
Issued by: GlobalSign CodeSigning CA - SHA256 - G2
Expires: 2018-05-11 2:17:24 AM
SHA1 hash: 0961...A35D2
File is not timestamped.
SignTool Error: File not valid: CertificateChecker.application
Number of files successfully Verified: 0
Number of warnings: 0
Number of errors: 1
So I'm left with a variant of my original question: Is there a SignTool Verify replacement for ClickOnce .application and .manifest files... and supports SHA256?
mage.exe
Manifest Generation and Editing Tool
mage -s CertificateCheck.application
I'm not aware yet of way to verify from CLI.
Use this code to verify ClickOnce manifests:
// based on tip from http://www.pcreview.co.uk/threads/tool-for-clickonce-maifest-and-application-signature-validation.3308405/#post-11299058
private static ManifestSignatureInformationCollection GetClickOnceManifestSignature(string manifestPath)
{
bool isApplicationManifest;
if (manifestPath.EndsWith(".exe.manifest"))
{
isApplicationManifest = true;
}
else if (manifestPath.EndsWith(".application"))
{
isApplicationManifest = false;
}
else
{
throw new InvalidOperationException("Unrecognized manifest type, expected either application manifest (.exe.manifest) or deployment manifest (.application)");
}
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1");
XElement assemblyIdentityXml = XDocument.Load(manifestPath).XPathSelectElement("/asmv1:assembly/asmv1:assemblyIdentity", namespaceManager);
string applicationIdentityPart = string.Format(
"{0}, Version={1}, Culture={2}, PublicKeyToken={3}, processorArchitecture={4}",
assemblyIdentityXml.Attribute("name").Value,
assemblyIdentityXml.Attribute("version").Value,
assemblyIdentityXml.Attribute("language").Value,
assemblyIdentityXml.Attribute("publicKeyToken").Value,
assemblyIdentityXml.Attribute("processorArchitecture").Value);
if (isApplicationManifest)
{
applicationIdentityPart += ", type=" + assemblyIdentityXml.Attribute("type").Value;
}
return ManifestSignatureInformation.VerifySignature(
ActivationContext.CreatePartialActivationContext(new ApplicationIdentity(applicationIdentityPart + "/" + applicationIdentityPart),
new[] { manifestPath, manifestPath }),
isApplicationManifest ? ManifestKinds.Application : ManifestKinds.Deployment);
}
private static void Main(string[] args)
{
ManifestSignatureInformationCollection resultDeployment = GetClickOnceManifestSignature(@"path\to\DeploymentManifest.application");
ManifestSignatureInformationCollection resultApplication = GetClickOnceManifestSignature(@"path\to\ApplicationManifest.exe.manifest");
Console.WriteLine("Deployment manifest is trusted: ");
Console.WriteLine(resultDeployment[0].AuthenticodeSignature.TrustStatus == TrustStatus.KnownIdentity || resultDeployment[0].AuthenticodeSignature.TrustStatus == TrustStatus.Trusted);
Console.WriteLine("Application manifest is trusted: ");
Console.WriteLine(resultApplication[0].AuthenticodeSignature.TrustStatus == TrustStatus.KnownIdentity || resultApplication[0].AuthenticodeSignature.TrustStatus == TrustStatus.Trusted);
}
Not that I know of. The idiocy of Microsoft still astounds me sometimes.
Old signtool.exes don't support SHA256. New versions do but don't support signing of manifests (why the hell did M$ remove that functionality?!). mage.exe doesn't support HSM certificate servers unless you know the private key (which is the whole point of using such servers to secure the certs). It's really amazing.
User contributions licensed under CC BY-SA 3.0