I'm trying to sign an executable using Microsoft's signtool.exe
The private key lives in an HSM and can not be taken out. So, i had to get the "public" part of the certificate in a .cer file and used below command to sign
signtool.exe sign /v /f .\SigningCert.pem /csp "HSM Key Storage Provider" /k "KEYID" /tr http://timestamp.digicert.com /fd sha256 /td sha256 .\App.exe
Since the machine i used for signing did not have the intermediate certificate added to Windows trust store, the signed executable could not be verified.
SignTool Error: WinVerifyTrust returned error: 0x800B010A
A certificate chain could not be built to a trusted root authority.
That being said, I used below command to add the intermediate certificate using /ac switch
signtool.exe sign /v /f .\SigningCert.pem /csp "HSM Key Storage Provider" /k "KEYID" /ac .\Intermediate.pem /tr http://timestamp.digicert.com /fd sha256 /td sha256 .\App.exe
The executable could be verified properly. So far so good.
Now, if my certificate chain has more than one intermediate certs, how could i add them to signatures?
Example chain:
Leaf Cert -> Intermediate 1 -> Intermediate 2 -> Root Cert
I tried merging all the intermediate certs into a single pem file and using it with /ac switch. Apparently, Signtool takes only the first certificate from the pem file and ignores the rest.
Also, If i want to add cross certificates from Microsoft apart from my intermediate certificates, how would i add them?
As far as i read, I can put all the certs into a pfx file and use it with signtool. But, as i mentioned, i don't have access to the private key. I do not think building a pfx file is an option for me.
Related
I followed the tutorial for generating a code-signing certificate using the YubiHSM Key Storage provider available here. After creating the Certificate Signing Request (CSR) with certreq -new sign.inf sign.req a new asymmetric key is created in the YubiHSM together with an association between this key and the certificate in the YubiHSM Key Storage Provider (KSP). After that, I am able to sign my binaries using something like signtool sign /sha1 <certificate hash> <binary name>.
However, when I export this certificate and import it to a different machine the certificate does not have an associated private key. Typing certutil -repairstore my <certificate hash> does not help. As far as I understand, the KSP only stores a link to the YubiHSM, not the actual private key itself. So I suppose I need to somehow create this association in the KSP.
I finally managed to solve the issue as follows:
After installing and configuring the YubiHSM KSP, install your exported certificate. After installing the certificate check its validity with:
certutil -verifystore my <certificate hash>
If you still cannot see the installed certificate try adding it manually using:
certutil -addstore -f "My" "MyCertificate.cer"
Once you can find the imported certificate, you need to manually bind the certificate to the private key. This is because the key is not stored with the certificate and Windows doesn’t automatically create an association between the two.
certutil -repairstore my <certificate hash>
Now you should be able to see the correct key label in the Key Container field using the certutil -verifystore command.
After that you should be able to start signing your binaries with signtool. However, I had to add the /sm flag to make it work.
signtool sign /sm /a /n "<CertificateName>" /fd sha256 path-to-binary-to-sign.exe
How can I enable access to key in HSM when signing as sha256?
When I sign as sha1 sign tool properly pulls the cert key out of the HSM but if I change to "/fd sha256" the key can't be found within the container. I'm sure signtool can access the container, but some policy must be blocking this in the sha256 case.
My Error:
SignTool Error: The specified private key container was not found.
Sha256 command:
signtool.exe sign /f mycert.crt
/csp "Luna Cryptographic Services for Microsoft Windows"
/kc mycontainer /tr http://timestamp.digicert.com /td sha256
/fd sha256 signed-file.exe
Sha256 command, which works:
signtool.exe sign /f mycert.crt
/csp "Luna Cryptographic Services for Microsoft Windows"
/kc mycontainer /tr http://timestamp.digicert.com /td sha256
/fd sha1 signed-file.exe
/debug and /v options offer no additional information.
If I use makecert to generate a new self signed cert it the command generates a container which CSP can use for sha1 or sha256. Luna's CSP\keymap.exe tool allows me to manage containers and keys. I can create new ones for signing or exchange and then associate keys with them.
Generate Cert and upload kes to HSM
# Create Cert and store keys on HSM in a container called "noi1-501706key"
makecert -sk noi1-501706key -sp "Luna Cryptographic Services for Microsoft Windows" -r
-n "CN=noi1- 501706" -ss TestStore noi1-501706.cer
# make self signed
Cert2Spc noi1-501706.cer noi1-501706.spc
Use Program Files\Safenet\Luna Client\CSP\keymap
create new container
associate pub/private with new container
using new container sha1 works and sha256 fails. All attempts to view the two containers show them as identical.
Check the KeyContainer,public and private key objects labels (cmu.exe list or keymap.exe Browse Objects).Public and private key labels should be in following format:
Container name: ContainerName
Private key: S-ContainerName
Public key: S-ContainerName
Use cmu.exe setattribute to change the label.
According to the chapter 7 "Integrating Microsoft HCK (Windows Server 2012) with Luna HSM" I noticed the following which makes me think the creation of the CSR via an HSM tool on linux instead of makecert we are blocked from KSP/CNG.
So, we will never get Luna client to find the key for the cert. We need to either get a new cert or migrate to a new HSM and get a new cert. This is because AWS CloudHSM Classic uses hardware configured to block export of keys regardless of policy. No change to escrow the keys here.
In order to integrate the Luna SA Hardware Security Module with Microsoft HCK, the Luna CSP “Luna Cryptographic Services for Microsoft Windows” must be used to generate the certificate. The
certificate must be signed and the signer certificate must be present in the “Trusted Root Certificate Authority”. You can use the CA signed certificate of self-signed certificate both.
My goal is to sign an unsigned executable file on Windows using a certificate. From my general knowledge I know that I need a public and a private key pair for a digital signature. I have also installed the Windows SDK, which provides signtool.exe and makecert.exe.
I have already obtained a certificate online, comprising a CER, a PEM, and a CRT file.
My question now is how I have to use these tools and the certificate files in order to sign an executable. According to here, the CRT file is the private key. From what I've learned so far, the CER and the PEM file are basically the same but with different encodings. What are the they for? Are they the public key? And how do I sign my executable?
EDIT: I've tried installing the CRT file to a certificate store and then signing using that certificate:
"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe" sign /debug /fd SHA256 /a /n "<Issued_To>" /t http://timestamp.comodoca.com/authenticode <Filename>
Here <Issued_To> was replaced with the data from the certificate and <Filename> is the name of the file I wanted to sign. The output I get from signtool is the following:
The following certificates were considered:
...
Issued to: ...
Issued by: Certum Code Signing CA SHA2
Expires: Thu Oct 12 14:37:04 2017
SHA1 hash: BA081A67D3F2DDDC9268121DCBA04F43D6CD37FB
...
After EKU filter, 1 certs were left.
After expiry filter, 1 certs were left.
After Subject Name filter, 1 certs were left.
After Private Key filter, 0 certs were left.
SignTool Error: No certificates were found that met all the given criteria.
For what it's worth, I purchased Certum Cloud Signing for open source projects and here is how I got it working. (It took me 5 business days of mails, trying and error and using google translate on polish documents, so maybe I save a little time to someone)
You first provide your personal information, Once you receive the activation token, you only have 24 hours to activate it. (even if this info is not specified, dont let time pass as I did), so:
Use the "Secret for regaining access to the SimplySign service" in the link that looks like: https://cloudsign.webnotarius.pl/arc/app/resetseed?token=...
There you will get a new code that you should use on the SimplySign mobile app (Reset button, I believe).
I wasnt able to find SimplySign mobile app on google play. So I used a desktop browser to find the App (which said "This app is not compatible with your device", and/or country...) and downloaded the APK using a chrome extension, then installed manually on my phone.
Once you have the mobile app setup, it should be generating 6 digit tokens every minute or so.
Now install SimplySign Desktop on Windows. Log in using your email and the 6 digits token from your mobile. Once it says "Status: Connected" it has installed a virtual smartcard and your certificate. SimplySign must stay connected for the certificate to work.
signtool.exe sign /n "Open Source Developer, Your Name" /fd SHA256 YourApp.exe
If you don't use /fd SHA256 you will get:
SignTool Error: SignedCode::Sign returned error: 0x80090027
The parameter is incorrect.
SignTool Error: An error occurred while attempting to sign: YourApp.exe
If you don't login into SimplySign, you get:
After EKU filter, 1 certs were left.
After expiry filter, 1 certs were left.
After Subject Name filter, 1 certs were left.
After Private Key filter, 0 certs were left.
SignTool Error: No certificates were found that met all the given criteria.
Note: There is no need to install proCertum SmartSign app.
This solved my question: http://www.anse.de/programming/code-signing-for-open-source-executable
I exported the certificate as a PK2 file using Firefox. Then I installed this certificate in the "Personal" certificate store on Windows. Afterwards I could use the aforementioned command to sign my executable:
signtool sign /fd SHA256 /a /n "<Issued_To>" /t http://timestamp.comodoca.com/authenticode <Filename>
Here <Issued_To> matches the value in the certificate and <Filename> is the name of the file to be signed. Afterwards the executable file is signed.
I'm trying to use SignTool.exe to code sign an executable with a certificate installed into the Windows certificate store. I'm able to get it to work by installing the cert into the Local Machine/Personal section and then running as an administrator, but I can't seem to work out the right place where the certificate needs to be installed to run as the current user.
I've installed the cert into Current User/Personal and when I do:
Get-ChildItem -Path Cert:\CurrentUser\My
the certificate is in the list. But when I try sign with:
& "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\signtool.exe"
sign /v /n "West Wind Technologies"
/s MY
/tr "http://timestamp.digicert.com" /td SHA256 /fd SHA256
".\Builds\CurrentRelease\MarkdownMonsterSetup.exe"
running as a non-admin user it doesn't work. I get:
SignTool Error: No certificates were found that met all the given criteria.
If I add the /sm flag and run run as an administrator and have it in the personal store - it works.
Where do I have to put the certificate in the cert store to get it to run without administrator rights?
For the current user you can use Certmgr to import it to the Personal folder.
I use the signtool /n option.
A bit more difficult is when you use signtool in a automated environment as (if your security is setup correctly) the build agent is running under limited service account. An option could be to use a file then.
How can i include the entire certification path when signing code using signtool?
Older versions of signtool would include the entire certification path in a digital signature. As it is now if i sign an executable with signtool:
signtool.exe" sign /v /f avatar.pfx -t "http://timestamp.verisign.com/scripts/timstamp.dll" app.exe
the signature is not valid:
This is because there is no certification path:
Binaries signed with the older version of signtool worked fine:
How do i tell signcode to include the entire certification path when signing?
What is the proper way to sign a binary?
Update: SignTool version 6.1.7600.16385:
See also
How can I sign an ActiveX control with a code signing certificate and be a verified publisher?
Signing WinForms ClickOnce app with Certificate Chain
ClickOnce: Certificate cannot be validated
Use /ac and pass the filename of the .cer in which your certificate is rooted (for Verisign it was called MSCV-VSClass3.cer last time I checked when signing kernel code or other special code).
signtool.exe sign /v /f "Avatar.pfx"
/ac "Thawte Code Signing CA - G2.cer"
-t "http://timestamp.verisign.com/scripts/timstamp.dll" app.exe
This should be given by your CA. Usually MS offers bundles for the various CAs it accepts within Windows.
See:
Windows root certificate program members 🕗
Cross-Certificates for Kernel Mode Code Signing 🕗
Either way, to my knowledge this is only required for kernel code and very specific other things (e.g. Windows Security Center).
If you use Thawte then download their primaryca.cer.
Download to file primaryca.cer and sign your file with:
signtool sign /f certificate.pfx /p PASSWORD /ac primaryca.cer APP.exe.
Should work.
The documentation for authenticode signing
Windows Authenticode Portable Executable Signature Format (.docx 🕗)
says that the PKCS #7 SignedData structure...
...contains the signer certificate and any intermediate certificates, but typically does not contain the root certificate.
However, as I discovered in a bit of a 'DOH!' moment, signtool.exe must be able to find the certificates to include them.
The leaf certificate is provided on the command line. But the identification of the remaining certificates up the chain does not include where to find the certificates. signtool does check the system certificate store, so if they are found there, they are added to the binary. If they are not found, signtool only puts the leaf certificate into the signed binary.
Note that if the intermediate certificates are not in the signed binary, but are in the system certificate store of the system checking the signature, the binary will still pass verification, because the chain can be resolved.
Also note that the exclusion of the root from the signed binary makes sense, given that the root must independently be on the system checking the signature for it to be trusted, so it would be ignored anyway. (The only real benefit to including the root in the binary would be if someone wanted to import the root cert manually, which is almost always a very bad idea.)