Code Signing Best Practices
Code signing and the use of digital certificates underpin the concept of trust in the modern technological landscape.
Code signing, in particular, is used to authenticate the identity of the developer of a program and where it came from. Like many X.509 certificates, code signing certificates come in both standard and Extended Validation (EV) forms.
By code-signing a program, a developer is simply attaching their digital certificate. Code signing certificates use public-key cryptography, which is the same technology that is used with other types of digital certificates. This method can be used across operating systems in many types of platforms, from mobile to desktop. You can find them used in Windows by Microsoft, Mac OS X by Apple, Linux, and even iOS and Android. They can even be found in IoT devices. Embedding these certificates into a program’s source code is a crucial aspect of security and trust in any software development.
How To Implement Code Signing
To implement, a unique private key is required – one that is properly hashed, so the encryption/decryption handshake is not easily defeated. Within public-key cryptography, the public and private key combination is the heart of the process, allowing communication without access.
After generating the new key pair using public key infrastructure (PKI), the public key is sent to a certificate authority (CA), which verifies the identity of the developer and affixes its own public key to the code signing certificate. The certificate and code are sent back to the original developer that requested the certificate.
Now that the developer is in possession of a signed code certificate and an encryption key pair, they must hash the software’s code before they can encrypt and sign it. Hashing is a procedure in which a hash function is used to convert code into an arbitrary fixed value. The output of hashing, called a digest, is then encrypted using the private key. Next, the developer combines this digest with the code signing certificate and the hash function to create something called a signature block, which is essentially all of the above items combined into a piece of code that can be conveniently inserted into the software.
Importance of Protection
The biggest issue with code signing is the protection of the private code signing key associated with the certificate. If a key is compromised, the certificate loses trust and value, jeopardizing the software that you have signed.
Many organizations protect themselves using secure vaults and Hardware Security Modules (HSMs) to increase the degree of security their private keys get. Others use certificate managers made to automate and secure the lifecycle management of all code signing certificates. An example of one is the Sectigo Certificate Manager. The use of a certificate manager goes a long way towards promoting the integrity of private keys and other encryption assets.
What Does Code Signing Prevent?
Simply, code signing prevents malware and other malicious code from being introduced to an end-user's system under the disguise of a benign file or event such as a Windows update. It accomplishes this by allowing users to authenticate that the file being downloaded does come from the originator rather than a malicious actor. This reinforces the concept of trust within the system, allowing developers to assure the end-users downloading the software that the source can be trusted and is safe.
EV Code Signing Certificates offer additional assurances of security. They require that the key be stored in a high assurance, FIPS 140-2 or above standard-compliant hardware. There are USB tokens that meet this requirement and add another layer of protection with a PIN. Alternatively, you could store the key(s) in your organization’s Hardware Security Module (HSM) on-premises.
Research from Georgia Tech’s Cyber Forensics Innovation Lab shows that issuance and use of Extended Validation (EV) TLS/SSL certificates results in 99.99% likeliness to be free of phishing attacks and abuse. The white paper, which was sponsored by Sectigo, can be downloaded here.
Easy Methods for Protecting Keys
There are a number of ways to protect code signing keys, including:
Separating your test and release signing keys
Test environments are messy and busy, but, since they are internal, test signing keys usually do not need to be as deeply protected as your release signing keys. In fact, many organizations use self-signed certificates or non-trusted certificate authorities in test environments for this reason. Separating test and release signing keys prevents developers from using one code signing key in the development phase and releasing the software with it. However, using separate test and release keys requires that any test install package is clearly marked as such to avoid it being pushed to customers.
Take revocation seriously
Revoking certificates is one of the most important parts of tracking code signing keys. If a vulnerability is discovered in the code signing process or a private key is exposed, the keys and certificates associated with them will need to be revoked and reissued to properly ensure trust in the system.
Time is your friend
Code signing certificates expire just like any other digital certificate. That does not mean that the information signed with that certificate is invalid, but it does mean that when a system checks the code signature to compare, it will identify it as out of date and give the end-user an error message. These alerts occur whenever a timestamp is out of date and can be bypassed, but they can damage customer reputation and trust in the brand. These expiration dates enforce the discipline to continually renew certificates, ensuring that certificates in released code are hashed using the most up-to-date encryption methods and have not been compromised through a cryptographic vulnerability.
Code Signing Best Practices
Code signing does not render software completely immune to misuse, tampering, or malicious intent. There is a significant human factor involved with the handling of private keys. Code signing should be a collaborative responsibility between security and development teams to achieve mutual goals and protect keys without disruption.
Following some industry-standard best practices can contribute towards this method being as effective as possible. Here are the top 10 best practices for code signing that Sectigo recommends everyone adopt.
1. Secure your code with code signing certificates
The most important recommendation of all is simply to use code signing certificates whenever possible. These verify the source and authenticity of code to end-users and increase customer confidence in their personal security. By properly signing your code, you can imbue your application or program with trust managed by a trusted public certificate authority like Sectigo. For additional security, you can use an EV Code Signing Certificate.
2. Avoid creating bad habits
Properly using the certificates within your system is essential, but if behavioral habits are not enforced to properly maintain and use them, then any other practices you employ will be for naught. Instituting a culture that understands the use and importance of digital certificates can only improve your organization as a whole.
3. Minimize access to private keys
Any good IT expert will institute access control measures whenever possible; that includes restricting access to private keys and base root certificates. You should only allow a very small number of individuals to have access to your organization's private keys, and those individuals should have an express reason for needing access. Instituting a role-based access (rbac) policy within your organization will help limit possible exposure.
4. Protect private keys with cryptographic hardware
Using cryptographic hardware allows you to protect your private keys with the most up-to-date encryption algorithms. This type of hardware should be at least a FIPS 140 Level 2-certified product. Products like hardware security modules (HSMs) will protect your private keys from falling into the hands of malicious actors.
5. Time-stamp code
Time-stamping your code allows you to understand when code was written in comparison to the certificate that it uses. This allows for it to be reverified as legitimate once the certificate has expired or is otherwise revoked. This is an important relationship to understand since as technology and cryptographic threats evolve, current protections can be weakened or outright broken.
6. Test-signing and release-signing differences
As described above, it is important to separate and understand the difference between test-signing and release-signing keys/certificates. Test signing certificates and keys require less security and can be self-signed by a private internal test CA. They must also chain to a different root certificate from the released signed product, and best practices include setting up completely different code signing infrastructure for release and pre-release signing. This will allow you to set up proper access controls for your test environment and production code.
7. Authenticate code
Code signing does not specifically identify code as safe; it just states who wrote it. As such, the code still needs to be fully authenticated before it can be released to the public in good faith. Doing so allows you to make sure that you are not accidentally spreading incorrect or malicious code that could harm customers and damage your reputation. All authentication of code signing activities should be recorded for posterity in case some type of investigation or incident response is required.
8. Virus scan code
In addition to authenticating that no modifications have been made to your code, it is important to scan it for viruses or other malicious code. Malicious code can often be inserted inadvertently by developers who are reusing or introducing existing code from outside projects. It is much easier to catch and change mistakes before the code is released.
9. Limit repeated key use
Reusing private keys to code sign multiple times creates increased risk for you. If a key is compromised, all code signed with that key marked for that date will be invalid and need to be updated with a new code signing certificate. Keeping a habit of cycling through different keys and certificates will allow you to distribute the risk and will lower the effort and impact when reissuing certificates.
10. Revoke compromised certificates
Revocation is one of the most important tasks to ensure the safety of the code. Certificate authorities take revocation more seriously than anyone, which is why we recommend best practices such as time-stamping your code.
However, it is incumbent on the development organization to report any compromised code, keys, or certificates to your certificate authority so that they can take appropriate actions. In the case of any possible problems, a CA will require the code signing certificate to be revoked. If you time-stamp your code, only code whose revocation date is after the incident will be impacted.
Learn about the different types of code signing certificates that Sectigo offers, or reach out to our expert team for further information.