EngineeringLast Updated Jan 2, 20258 min read

Code signing: securing against supply chain vulnerabilities

Jacob Schmitt

Senior Technical Content Marketing Manager

A stylized mobile device projects a display of secure code.

To create applications, developers rely on many different tools, programs, and people. This collection of agents and actors in the software development lifecycle (SDLC) is called the software supply chain. Anything that touches or influences applications during development, production, and deployment is considered part of the software supply chain. That includes 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 actors to infiltrate. This assures the security and authenticity of published applications.

Code signing is a critical method of hardening security. Code signing ensures that the final published software is from the original publisher and has not been tampered with by unauthorized parties.

This article explores code signing, how it works, and its importance in hardening application security. It also covers some best practices for you to follow when code signing your own applications.

What is code signing?

Code signing applies digital signatures to applications, scripts, drivers, and other software components to certify that they come from 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. 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. Then, the public key from the public-private key pair decrypts the digest from the bundled signature block. The hash function 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

Keeping software secure is 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. Dependencies increase the ways that vulnerabilities could emerge in your SDLC.

To help reduce the risk of introducing malware and other attacks into source code, you should download third-party software and dependencies only from trusted vendors. Dependency confusion and simple misconfiguration errors can quickly undermine your code signing practices. So, use caution when you implement dependencies.

Attackers may also use typosquatting. This technique targets 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 they are distributed 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 you can publish applications on the Google Play Store, you must sign your code. First, you’ll need to generate a cryptographic key. This key will be checked by every user’s device package manager and the Google Android Package Kit (APK). This is how Google verifies 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, 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 that will help you keep your application code secure.

Keep private keys secure

When a code signing private key gets exposed, lost, or compromised, you are vulnerable to significant security threats. Compromised keys can grant hackers and malicious users a lot of power. These code signing certificate keys are also in demand on the dark web.

Avoid exposing private keys by:

  • 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 code using a code signing certificate, it attaches a timestamp to record the signing time. This timestamp assures 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.

You can use tools like Snyk orb to scan your codebase for vulnerabilities.

Conclusion

Your software supply chain is probably big, complex, and interconnected. That makes it susceptible to vulnerabilities and exploitation. Vulnerabilities could be as innocent and unintentional as misconfigurations or accidentally making typos. Or they could be as 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 securing your software supply and distribution chain; it’s a way of assuring your users of the safety of published applications. 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.

Copy to clipboard