Closed tresf closed 4 years ago
Using the Visual Studio signtool
command, I was able to generate the following signatures examples... (click to expand)
Thank you for the suggestion Tres, I wasn't aware VBScript and JScript files could also be signed. PowerShell script signing has just been implemented. I guess we could extend it to support the other types of files.
Just tried signtool on an XML file, it doesn't recognize a mere .xml
file, but if the extension is changed to .ps1xml
the following block is appended at the end of the file:
<!-- SIG # Begin signature block -->
<!-- MIIEmwYJKoZIhvcNAQcCoIIEjDCCBIgCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB -->
<!-- gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR -->
<!-- AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUYglJp0ak80SxvLGkWVSR4bR9 -->
<!-- yQugggLAMIICvDCCAaSgAwIBAgIJAP9OZxamrmcQMA0GCSqGSIb3DQEBCwUAMCAx -->
<!-- HjAcBgNVBAMMFUpzaWduIENvZGUgU2lnbmluZyBDQTAeFw0xNzA2MTUxOTU1NTZa -->
<!-- Fw0zNzA2MTAxOTU1NTZaMC4xLDAqBgNVBAMMI0pzaWduIENvZGUgU2lnbmluZyBU -->
<!-- ZXN0IENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaMIoK -->
<!-- K5Hk0xKFpNqJAfPU37WYKLJ1A5G6qHZias6Ub6VYGSbgZ5KLIpq9+/U6hlXjJGEB -->
<!-- rX9Y5aB/vsb3cm/MV9q9G/ilooIFsFs4Jp9EIJEABJHFPRpo1iZ3nfAhPiL1FlDH -->
<!-- phdTkAmwN1CPzl7poyV7qAh3517TNbiRjyMW7QIDAQABo28wbTAJBgNVHRMEAjAA -->
<!-- MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUKe9f -->
<!-- HJxmCiML1BRgdczt0cV16R0wHwYDVR0jBBgwFoAUFqIGcZGo1ChElx+V5xpfjJu+ -->
<!-- K+AwDQYJKoZIhvcNAQELBQADggEBAIjNRVnxdn8QkUSwFONiIdEW+DvupbciSzMD -->
<!-- bjvVUTeyKV92ibOpBOfqxuBYu2lyk7ZpAEV1aNaZG9C/2GPOHoUyz6JTHm3mZema -->
<!-- WgQ3lYJA5BIDwr5pqyxg82bpHw2FzcqDljWlmkerlj+orOpn7j/rq9wOXWNQbX2a -->
<!-- jqspebyQnYyM/VxFyEdZ4XZswJNSYFTvRSwbxjXrR+icwJCJyBk3g+A+2TXWYIWn -->
<!-- AscXTCvbewplUcL+va34nW3JwMWmdic/fkxTiv1eHleKMBPnUAjuL2U/gePbh6mR -->
<!-- qb1FY7BHwOJDoyuXLXP54J7qHtJu/tfmB+6QzSEThgw7WwozARkxggFFMIIBQQIB -->
<!-- ATAtMCAxHjAcBgNVBAMMFUpzaWduIENvZGUgU2lnbmluZyBDQQIJAP9OZxamrmcQ -->
<!-- MAkGBSsOAwIaBQCgcDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYK -->
<!-- KwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG -->
<!-- 9w0BCQQxFgQUxUqHLsf6C63ELQCTso2fsCFCLJAwDQYJKoZIhvcNAQEBBQAEgYAc -->
<!-- 5sLhwuhq5hwa0B63iBaU7Tz0VyXQYcRj5477sP4bswP4lAHH3zJvEdHiC1nJr8VE -->
<!-- RC4PzN26jyAiT+e2cqbWzVaQ4rxffM3H5VPdOcrbmExBtAWrr7iQVunUxWHL5VSg -->
<!-- RCPNY5qojWXObSuf4GD7CxwvHBahSbeEgozZXJFqNQ== -->
<!-- SIG # End signature block -->
I've played a bit with VBScript and JScript files, it looks like the hashing method is different from the PowerShell scripts. For PowerShell the content is converted to UTF-16LE before being hashed. For VB and JS it doesn't work, the hash generated differs from the one computed by signtool. I tried various encodings (UTF-8, UTF-16BE, UTF-32BE/LE, with or without byte order marks) but it still doesn't match.
I've pushed my work on VB/JS signing to the vbscript-jscript-support branch. If someone figures out how to hash the files I'll merge it for the next release.
An expert on Windows signing is Chilkatsoft, a commercial project that provides modern signing algorithms to languages like Classic ASP (and many others). I've used and recommended chilkat many times, perhaps he has some input on this.
@chilkatsoft, I hope you don't mind me asking, are you aware of how VBScript or JScript files are hashed in order to create the digital signature?
The topic of signing VBScript files is pretty dark on the internet. Lately, I've been using GitHub's search for code that Google doesn't index and I've found quite a bit. I'm struggling to find anything on GitHub for this topic, probably because of the lack of a unique keyword to search for. I'll keep digging.
I've also posted the question to stackoverflow.
@ebourg something very peculiar... if I add newlines to the bottom of the file, it still generates the same signature. If I leave the signature block at the bottom of the file, it's still generating the same signature. Is there a chance that it's doing some form of trimming before signing?
Scratch that... still investigating.
@ebourg why would the signature change each time I use jsign
, but remain the same each subsequent call when using signtool.exe
? I'm viewing the file with a hex-editor and I don't see any obvious bytes being added.
jsign
java -jar jsign.jar --keystore my-key.p12 --storepass password --alias my-alias my-script.vbs
signtool
signtool.exe sign /f my-key.p12 /p password my-script.vbs
@ebourg why would the signature change each time I use jsign,
Answering my own question.... There seems to be a slight bug when --replace
command line option isn't provided, the signature changes each time it's called. Using --replace
, the signature value is reproducible... Still investigating...
So it turns out Windows has a pretty decent signature viewer for debugging this... (Properties, Digital Signatures, Details, Advanced)...
Differences:
jsign:
SHA-256
1.3.6.1.4.1.311.2.1.12
(SPC_SP_OPUS_INFO_OBJID)1.3.6.1.4.1.311.2.1.11
(SPC_STATEMENT_TYPE_OBJID)1.2.840.113549.1.9.52
(CMSAlgorithmProtection)signtool:
SHA-1
1.3.6.1.4.1.311.2.1.12
(SPC_SP_OPUS_INFO_OBJID)Interestingly, Windows 10 recognizes the SHA-256 signature just fine. My attempts to mimic the signtool.exe
behavior were somewhat successful:
start += 44
/ start + 44
SPC_STATEMENT_TYPE_OBJID
--alg SHA-1
command line flagCMSAlgorithmProtection
by removing it explicitly from FilteredAttributeTableGenerator
, BouncyCastle seems to add it by default.What I'm still unable to remove is the CMSAlgorithmProtection
property, which I believe will aid in yielding an identical signature value.
Edit: I was able to remove CMSAlgorithmProtection
by removing it explicitly from FilteredAttributeTableGenerator
:
for (ASN1ObjectIdentifier identifier : removedAttributes) {
attributes = attributes.remove(identifier);
}
+
+ attributes = attributes.remove(CMSAttributes.cmsAlgorithmProtect);
@tresf thank you for looking into this. The issue is the hash that goes into the SpcIndirectData structure, I have no idea how it is computed. For PowerShell the text in converted to UTF-16 and then hashed with the algorithm selected, but for VB/JS it's a mystery.
I've used and recommended chilkat many times, perhaps he has some input on this.
Did they implement Authenticode for VB/JS?
Cosmetic: Modify signature block wrapping to start += 44 / start + 44 Signature Calculation: Comment out the addition of SPC_STATEMENT_TYPE_OBJID
I don't think this makes a difference.
Signature Calculation: Remove CMSAlgorithmProtection
I'm aware Jsign puts an extra CMSAlgorithmProtection attributes compared to signtool, but it doesn't cause any issue. AFAIK it even strengthens the signature.
Sorry.. I've been extremely busy today. I'm curious and will have a look sometime soon..
Best Regards, Matt Fausey Chilkat Software, Inc.
On 12/16/2019 5:08 PM, Emmanuel Bourg wrote:
@tresf thank you for looking into this. The issue is the hash that goes into the SpcIndirectData structure, I have no idea how it is computed. For PowerShell the text in converted to UTF-16 and then hashed with the algorithm selected, but for VB/JS it's a mystery.
I've used and recommended chilkat many times, perhaps he has some input on this.
Did they implement Authenticode for VB/JS?
Cosmetic: Modify signature block wrapping to start += 44 / start + 44 Signature Calculation: Comment out the addition of SPC_STATEMENT_TYPE_OBJID
I don't think this makes a difference.
Signature Calculation: Remove CMSAlgorithmProtection
I'm aware Jsign puts an extra CMSAlgorithmProtection attributes compared to signtool, but it doesn't cause any issue. AFAIK it even strengthens the signature.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
@tresf thank you for looking into this. The issue is the hash that goes into the SpcIndirectData structure, I have no idea how it is computed. For PowerShell the text in converted to UTF-16 and then hashed with the algorithm selected, but for VB/JS it's a mystery.
I spent quite a bit of time on this myself. I tried UTF-8
, ISO-8859-1
, Cp1252
and the encodings methods you've mentioned to no avail.
The only unit test that I have is to try to match the signature exactly, which I was unable to do, is there a better unit test I should be using? I've seen other (unrelated) programs use undocumented or poorly documented obfuscation techniques... it'd be nice if we could crack it.
signtool.exe
does have a verify
flag that can be used to check for validity of a signature. Did you have any luck?
Did some more digging, I haven't found anything, but I wanted to share my failures, if nothing else.
signcode
would have .vbs|.js
support, but it appears VBScript support in general is largely abandoned by the Mono team.osslsigncode
, I can't find any references to supporting .vbs
or .js
script files in the source.<<<Obsolete>>>
. This occurs in both Microsot's 2008 Windows Authenticode Portable Executable Signature Format document as well as in Mono's signing class. I don't know if this data goes into the signed hash or if it's part of the content that's not signed, but it stood out to me as peculiar so I wanted to mention it.Set-AuthenticodeSignature
hasn't been ported to non-Windows platforms yet.Edit: More digging... still no answers:
signtool
WinVerifyTrust
I was hoping that Mono's signcode would have .vbs|.js support, but it appears VBScript
signcode works with PE files only (.exe, .dll)
Same goes for osslsigncode
It supports PE , MSI and CAB files, but not scripts.
Probably unrelated, but one peculiar item I found digging was a strange string value called <<
>>
This is mentioned in the Authenticode specification, it doesn't affect the content hash.
PowerShell's Set-AuthenticodeSignature hasn't been ported to non-Windows platforms yet.
Like signtool it delegates the actual work to the registered SIPs anyway, so the code won't help.
The best hope is probably to debug the SIP for VB/JS scripts, but I haven't figured out which dll implements it yet.
The DLL implementing VB/JS signing is C:\Windows\System32\wshext.dll
...and more specifically the HashFile method in this DLL.
Looking at the DLL it appears that Windows Script Files (.wsf
) can also be signed. A signed wsf file look like this:
<?xml version="1.0" ?>
<job>
<script language="VBScript">
<![CDATA[
WScript.echo "Hello World!"
]]>
</script>
<signature>
** SIG ** MIIH4AYJKoZIhvcNAQcCoIIH0TCCB80CAQExCzAJBgUr
** SIG ** DgMCGgUAMGcGCisGAQQBgjcCAQSgWTBXMDIGCisGAQQB
[...]
** SIG ** BSdshFkEZt2VUvJbXF+Wd6RSVKGt0Bnv8HXXv1kIh2Vk
** SIG ** VlR6x2X/Huuo9JTfDux8rEfWPQDDxZK575CkhCXYRjtQ
** SIG ** 13lhbkRJsQ==
</signature>
</job>
I got it, the script is indeed hashed in UTF-16LE, but the size of the unsigned file encoded as a 4 bytes little endian integer is added to the hash.
@tresf the hash is now implemented on the vbscript-jscript-support branch. Let me know how it works for you.
@ebourg thanks for this, it's greatly appreciated.
So I'm testing ant
integration using the DigiCert code signing certificate we have and signtool verify
is erroring. This same error occurs for .exe
s which are distributed on mass, so I assume I'm not using the verify command properly.
I'd like to try to raise the Windows security prompt, but I'm having trouble doing so.
The signature is timestamped: Tue Dec 17 13:52:28 2019
Timestamp Verified by:
Issued to: DigiCert Assured ID Root CA
Issued by: DigiCert Assured ID Root CA
Expires: Sun Nov 09 19:00:00 2031
SHA1 hash: 0563B8630D62D75ABBC8AB1E4BDFB5A899B24D43
Issued to: DigiCert Assured ID CA-1
Issued by: DigiCert Assured ID Root CA
Expires: Tue Nov 09 19:00:00 2021
SHA1 hash: 19A09B5A36F4DD99727DF783C17A51231A56C117
Issued to: DigiCert Timestamp Responder
Issued by: DigiCert Assured ID CA-1
Expires: Mon Oct 21 19:00:00 2024
SHA1 hash: 614D271D9102E30169822487FDE5DE00A352B01D
- SignTool Error: A certificate chain processed, but terminated in a root
- certificate which is not trusted by the trust provider.
I think it's working. Here's my first unit test:
Unsigned
.js
Signed
.js
Found it per https://stackoverflow.com/q/11230091/3196753:
signtool.exe verify /pa path/to/file.js
Quoting:
The
/pa
option to tells it to use the Default Authentication Verification Policy instead of the Windows Driver Verification Policy
This produces:
Successfully verified: path/to/file.js
Unit tests for .js
pass.
I finally had a chance to try to get up to speed.
My first big question was: How to compute the hash? It seems you already found the solution to that -- by converting to UTF16-LE and adding the 4-byte length.. That's probably the most difficult hurdle. The remaining hurdles are tedious and time-consuming tasks, and I don't think I'd be of much help.
The reason is that my approach would be to use the internal infrastructure within Chilkat to solve each problem. In other words, the Chilkat proprietary code for PKCS*, ASN.1, etc., whereas your solution would be using the API's provided by Java, BounceyCastle, or something else, and I'm not actually super familiar with those API's.
Best Regards, Matt Fausey Chilkat Software, Inc.
On 12/17/2019 1:52 PM, Tres Finocchiaro wrote:
Found it per https://stackoverflow.com/q/11230091/3196753:
signtool.exe verify /pa path/to/file.js
Quoting:
The /pa option to tells it to use the Default Authentication Verification Policy instead of the *Windows Driver Verification Policy
This produces:
Successfully verified: path/to/file.js
Unit tests for .js pass.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.
It seems you already found the solution to that -- by converting to UTF16-LE and adding the 4-byte length..
Yes, that was the missing puzzle piece.
Does
JSign
support VBScript.vbs
or JScript.js
files?Reference: https://stackoverflow.com/a/34244366/3196753
Windows will show a warning if a script file is not digitally signed. I assume the technique can be extended to other scriptable languages, such as PowerShell
.ps1
, etc.