Code signing: securing against supply chain vulnerabilities
Senior Technical Content Marketing Manager
When creating an application, developers often rely on many different tools, programs, and people. This collection of agents and actors involved in the software development lifecycle (SDLC) is called the software supply chain. The software supply chain refers to anything that touches or influences applications during development, production, and deployment — including developers, dependencies, network interfaces, and DevOps practices.
Because you are working with several moving parts — including open source material, APIs, and so on — it is crucial to know just how secure each component of your software supply chain is. Hardening security around the software supply chain ensures that as source code travels through this chain, it leaves no room for cyber attackers or other bad attackers to infiltrate. This assures the security and authenticity of published applications.
A critical method of hardening security is the application of code signing. Code signing ensures that the final published software is from the original publisher and contains no tampering from unauthorized parties.
This article explores code signing, how it works, and its importance in hardening application security. Then, it looks at some best practices when code signing your applications.
What is code signing?
Code signing uses digital signatures for applications, scripts, drivers, and other software components to confirm their original authors. The software’s author signs the code whenever they make changes, ensuring no action is unauthorized.
Organizations often sign code to confirm that all changes are authentic and documented. This course of action guarantees that users are not getting an application with vulnerabilities or security risks.
Code signing is also helpful when working in a team environment. You can use code signing as you exchange source code throughout the SDLC to ensure double authentication, prevent attacks, and even prevent namespace conflicts.
Code signing follows a three-step process: creating a public-private key, hashing, and description and verification.
Step one: creating a unique public-private key
Code signing starts with creating a unique public-private key pair, which can be generated locally via tools like OpenSSL. After that, you send the public key to a trusted certificate authority (CA), verifying your and your organization’s identity. After the CA verifies these identities, it sends back the public key and a digitally signed code signing certificate.
Step two: hashing
Following the return of the code signing certificate and public key, the code goes through a hash function. A hash function is a one-way cryptography method that irreversibly turns text into a mix of values. The private key then encrypts the output (digest) of the hash function and prevents external tampering. Afterward, the hash function, its digest, and code signing certificate get bundled into a signature block and sent to the consumer.
Step three: decryption and verification
After downloading the software, the user’s computer checks the code signing certificate to verify its authenticity. After verification, the public key from the public-private key pair decrypts the digest from the bundled signature block. The hash function then works on the software code and compares the resulting output (digest) with your decrypted digest. If both digests match, the software is confirmed safe for installation.
The importance of hardening your application security
Ensuring software security remains a continuous task throughout the SDLC. Hardening application security through practices like code signing helps reduce the attack surface and decreases the chances of security breaches.
Most often, the SDLC uses dependencies for optimal function. These dependencies usually also require other dependencies, thereby increasing the avenues through which vulnerabilities could emerge in your SDLC.
To help mitigate the risk of introducing malware and other vulnerabilities into source code, you should only download third-party software and dependencies from trusted vendors. Dependency confusion and simple misconfiguration errors can quickly undermine your code signing practices. So, it is important to use caution when implementing dependencies.
Attackers may also employ typosquatting. This technique attackers use to target internet users who enter a wrong or misspelled URL into their web browser. Visiting these websites may download malware into computer systems or allow access to sensitive information.
Code signing with the Apple App Store and Google Play Store
As software distribution platforms, Apple’s App Store and the Google Play Store require developers to code sign applications before commercial distribution to potential users. To see how code signing works in action, and to highlight its security benefits, consider how the Apple App Store and the Google Play Store implement code signing into their mobile application releases and update systems.
Before publishing applications on the Google Play Store, you must sign your code. To do so, you must generate a cryptographic key to be checked by every user’s device package manager and the Google Android Package Kit (APK). This key is Google’s way of verifying the authenticity and source of the application and its updates.
Previously, developers were left to manage the security of these keys. Now, Google offers Play App Signing, which separates the upload key used to upload your artifacts to Google Play from your App Signing Key (which helps sign APKs to distributed devices). With Play App Signing, Google stores the App Signing Key in its secure infrastructure, thereby improving security.
Apple’s App Store employs asymmetric cryptography (public and private keys) to ensure the security of apps published to its platform for its code signing process. First, you (as an application publisher) must create a Certificate Signing Request (CSR) on your local machine. Once you make a CSR, the local device generates a public-private key, attaches the public key to the CSR, and downloads a certSigningRequest used to apply for a certificate with Apple. Remember that certificates only work with the private key generated for them.
Then, you download the certificate and push it to the keychain, which pairs with their private key. Together, the certificate and the private key make up the Code Signing Identity used to publish iOS applications.
Code signing best practices
Here are some code signing best practices to ensure your application code is secure.
Keep private keys secure
A significant security threat occurs when a code signing private key gets exposed, lost, or compromised. Compromised keys grant hackers and malicious users a lot of power. These code signing certificate keys are also in demand on the dark web.
Some common ways to avoid this include:
- Granting only authorized personnel access to keys
- Restricting access to private keys by employing physical security control and limiting the number of computers that have access to such keys
- Using cryptographic hardware products to secure keys
Use strict access roles and permissions
Enforce strict policies and roles to ensure only those with authorized access have access to private keys to limit exposure to risks. Additionally, it would be best if you employed logging to perform audits for incident reporting.
Automating the signing process with CI/CD
The automated code signing process involves an end-to-end centralized approach to code signing workflows while enforcing security policies. This automation process uses granular access control and integrates with CI/CD pipelines without slowing down the SDLC.
You can ensure end-to-end security by automating code signing with CI/CD pipelines using continuous signing (CS). With CS, as code passes through different stages of the SDLC, a centralized certificate manager deploys code signing certificates automatically. This process eliminates the need to stop development cycles to generate code signing certificates, thereby improving development speed.
You can apply CS with CI/CD tools that perform security checks at each stage of the pipeline, such as the CircleCI runner, which helps keep certificates secure and signed during CS. By using CS, you can efficiently enhance the pace of the development lifecycle and ensure your released products are secure while maintaining automated, efficient CI/CD pipelines.
Use time stamps for code
When you sign a code using a code signing certificate, it attaches additional data — namely, a timestamp — to record the signing time. This timestamp helps assure users of the validity of a code signing certificate at the time of use, improves overall security, and allows users to feel secure when using your application.
Scan code for viruses and vulnerabilities before signing
While automation is helpful for general productivity, it also means fewer eyes reviewing the actual code. In some cases, this leaves an opening for vulnerabilities. To prevent this, you can carefully scan software code for viruses and other exposures before committing to the source code. This practice helps detect potential risks and improves code quality. For example, you can use tools like Snyk orb to scan your codebase for vulnerabilities.
Conclusion
Your software supply chain is most likely complex, interconnected, and lengthy. And as a consequence, it is likely susceptible to vulnerabilities and exploitation. Vulnerabilities could be as innocent and unintentional as misconfigurations or accidentally making typos. They could be severe and targeted as attackers injecting malicious code into your software, leading to severe cyber attacks after publishing.
Code signing is an integral part of making your software supply and distribution chain secure and also serves as a way of assuring your users of the safety of published applications. Additionally, you can use code signing for security-related purposes, like protection against malware attacks from vulnerable dependencies.
To ensure your application is secure and keep your code signing efforts thorough and effective, follow best practices such as maintaining safe keys, scanning for vulnerabilities, and using timestamps when signing. When you are ready to accelerate and scale your software build, test, and code signing practices, incorporate continuous integration tooling into your development workflow. You can get started by signing up for a free CircleCI account today.