What is the process for signing code with a signing certificate? - code-signing

I am a new developer working on an open source application and I am trying to figure out how one signs a program.
I understand why code signing is a thing, and I know how to get a certificate (from a CA or individually), but I can't find anything explaining the actual process of signing itself once you have your private key.
How does one sign code with a signing certificate? Specifically, do you sign the source code, the built executable, something else entirely? Do you run a specific app, or include something in the code?
related but discrete question: What to do with the code signing certificate?

You have a code signing certificate which contains a private key and a public key.
You calculate a cryptographically save checksum of your code and data, encrypt it with your private key. You add the encrypted checksum and your public key to your code.
Now anyone can calculate the same checksum of your code, decrypt the encrypted checksum with the public key, and compare them. If they match, then it is proven that the code was supplied by someone who has your private key. If they don't match, then it is proven that this code is not the same as the on of which you encrypted the checksum.
To be useful, the operating system would perform this kind of test before any application is allowed to run. And the public key would be signed with well known private key owned by the OS supplier, and would likely be accompanied by data that can be used to identify the owner of the public key.
Obviously EvilHacker could create malware and code sign it. So the fact that it is signed is meaningless. But you would also have the identity of EvilHacker, or the operating system wouldn't start the application. So the operating system will never allow you to run a hacked application or one where the owner of the public key is not known to the creator of the OS.
The second worst a hacker can do successfully is to completely remove the code signing and give you unsigned hacked code - the OS will likely ask you whether you want to run unsigned code or not, or not allow it at all.
The worst a hacker can do is either to con the os owner to accept EvilHacker's code signing certificate, or steal a code signing certificate and create malware that is actually correctly signed.

Related

How to validate a PE file's digital signature in windows and find who signed it? (using c/c++)

Lets say you have a windows executable (driver or usermode app), and you want to :
Verify if the digital signature is OK and file is not corrupted (same as when you go to the digital signature tab and it says the certificate is OK)
Find which company signed the file. Therefore I am not talking about the root of the certificate chain (Which is the CA most of the times), I am talking about the bottom certificate in the chain, which is the company that signed the file, i want to get the name of that company.
I found two APIs, WinVerifyTrust And CertGetCertificateChain, But I'm not sure how to use them for this task, or if they can help me with this or not.
Lets say you already have the handle to the file that you want to check, and have read it in a buffer as well, how do you use these to check the certificate afterwards? The documentations are very vague.
Verify if the digital signature is OK and file is not corrupted
For more details about how to Verifying the Signature of a PE File, I suggest you could refer to the example: https://learn.microsoft.com/en-us/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file
Find which company signed the file.
I suggest you could try to use CryptQueryObject function (wincrypt.h).
For more details I suggest you could refer to the Doc:https://learn.microsoft.com/en-us/troubleshoot/windows/win32/get-information-authenticode-signed-executables
And you could refer to the Thread:Read and validate certificate from executable

Signing ClickOnce application with code signing certificate, but publisher still unknown

I have 2 code signing certificates, for both CSR is created same way, also import and export is done same way. The only difference that I see is that one of certificates Common name contains Quotes, and the other doesn't.
e.g.
some cert and
some "cert"
CSR creation
Request format PKCS #10
disabled "Strong private key encryption"
Entered Common name, Organization, Locality, State, Country
2048 bytes for private key
set private key exportable
Import
place all certificates in Personal store
Export
Include all certificates if possible
Enable certificate privacy
encryption algorithm TripleDES-SHA1
Misleading thing is that this Common name value is NOT taken from the value I entered when I created CSR request
I am using those certificates to sign Winforms applications in Visual Studio. Certificate without Quotes in common name is working correctly (i.e. when I install application user is not getting security warning about unknown publisher), but when I install application which is signed with the other Code signing certificate (with Quotes in Common name) - it does not recognize Publisher. No error when published my application. When I take a look at setup.exe properties in Windows Explorer I see a Digital signatures tab which contains row for my certificate.
I tried to sign files with signtool and then verify - it said that certificate is valid.
I tried to get help from godaddy.com where I bought my certificate, they said that it should work with quotes, too, but didn't offer help to solve the issue. Rekey also didn't help.
I see that there are some suggestions to use Pre Publish, Post Build tasks, but I am not using those for my first certificate which is working.
So, is anyone here using code signing certificate for Winforms application with common name having quotes in it? Or maybe anyone knows about this problem and how to solve it?
Had to revoke (common name which is entered when creating CSR is not taken into account, so rekeying is not enough!) my code signing certificate and create from start without quotes/brackets in company name.
So this means, you will have to wait again for few days, because verification process is made from start again. When you will be contacted by issuer, they will verify / ask you about company name - make sure that they do not include quotes/brackets.
Revoking means that you will basically have to buy your certificate once more, because after you revoke it (at least in godaddy case) in your account you don't have options to create it again. So, you have to contact support (use call center and not chat ;)

Public Key signing/verification

I'm developing an application to manage file and email encryption using (primarily) PKI. I have a Public Keyring with a list of contacts and their Public Keys.
Referring back to the olden days when I used PGP, I recall a requirement to sign public keys with your Private Key.
Is this a necessity on PKI and if so, what does this signing achieve? Is it bad practice to simply hold a list/database of people's names (and email) and their Public Key? Surely if their public key is - in any way - tampered with the encryption would fail and as you choose who you're sending or sharing the encrypted data with, even if a 'successful tamper' went unnoticed, the encrypted data wouldn't end up in the wrong hands anyway?
The whole thing about signing a public key with a private key is useful when you have a dedicated key-pair that you use only for signing, and then other key-pairs that you use for encrypting. This dedicated key-pair is your "trusted" key-pair that is somehow known to be legitimately attached to you (often by having it signed by a certificate authority or by having many trusted people sign that they have verified it's connection to you.)
You use this "trusted" private key to sign your not-quite-as-trusted public key. This way, people can un-sign/decrypt your new public-key with your trusted public-key. This is only mathematically possible if it was signed by your trusted private-key.
This process helps people to be sure that this new public-key actually belongs to you.

Duplicating Digital Signatures?

From what I understand about digital signatures, when code-signing exe's it the "signer" modifies the PE itself. I noticed that it adds the certificate content to the end of the PE and also (obviously) adds some kind of reference to the headers.
My question is: How secure is this ? Wouldn't someone capable of reverse engineering the executable be able to forge that onto his own executable thereby forging a digital signature ?
Code signing is a public-private key operation. The signing operation calculates a hash of the .exe file (minus the bits where the signature is stored), then encrypts the hash with the signer's private key.
On client-side validation, the client will redo the hash calculation, and decrypt the stored signature using the public key. If the two hashes match, then the exe has not been tampered with.
The only bits of the file are are encrypted are the signature - everythign else is stored in the clear. Nothing stops you from ripping apart the exe and stuff it (or parts of it) into another .exe.
Signing is not there to prevent theft - it's there to detect tampering.

Validate signature on EXE with CertGetCertificateChain

I would like to verify a signed executable. The requirement is to validate that the executable itself is valid and where it came from (probably from the subject of the cert). The cert type is PKCS.
I found a similar posting here,
Validate Authenticode signature on EXE - C++ without CAPICOM
The Microsoft documentation, among others, appears to point to CertGetCertificateChain, but the examples tend to work with certificates that are in a store. Does anyone know how to validate a signed executable using CertGetCertificateChain and related API's?
I asked this question some time ago. I had your exact requirements. There's sample code in there that will help you. Have fun!!
Can you elaborate? the question you linked to seems to provide all of the answers you should need.
You state that "the examples tend to work with certificates that are in a store", which I take to mean that the executable needs to be signed with a certificate that chains to a root certificate in the machine's trusted store.
This is true; there's no way around that, otherwise there is no way way to trust that the signer is who he says he is, and no way for the provider to revoke the certificate if it's being fraudulently used.
So, WinVerifyTrust is the right way to validate a signed executable. It's a terrible API so be careful. CryptQueryObject and related apis will give you more information such as the name of the person or company that the certificate was issued to.

Resources