Secure Code Signing For The Enterprise

As software delivery accelerates and DevOps becomes standard across industries, secure code signing is more important than ever. Code signing ensures the authenticity and integrity of software, preventing attackers from injecting malicious code into applications, scripts, containers, firmware, and more.

Enterprises, however, face a major challenge: how do you build a secure code signing system that protects high-value keys without slowing down development teams or requiring custom integrations?

In January 2018, NIST provided a great high-level overview of code signing, its threats, and some best practices to follow. This blog post extends on NIST’s overview with suggestions on how an enterprise can build such a system. In particular, we’ll focus on the signing aspect of a code signing system.

For additional information on this topic, see this post on automated hash validation, a technique for ensuring that the code being signed matches the code in the source code repository, and this post on preventing malware injections.

Who Needs Secure Code Signing?

If your organization produces any software, you should be signing it. And most companies—tech or not—produce software without realizing it:

  • Mobile apps

  • Internal applications and tools

  • PowerShell scripts, Bash scripts, and automation utilities

  • Excel macros

  • Firmware or embedded code

  • Deployment packages and installers

Whether software is used internally or shipped externally, unsigned code is a security liability. Attackers actively target build systems and signing workflows to insert malware, steal credentials, and compromise downstream users.

Code Signing in Real Enterprise Environments

Every enterprise is unique, with multiple teams that sign code for different reasons—and using different workflows.

DevOps Teams

  • Sign frequently and automatically

  • Emphasize performance

  • Often use non-production keys

  • Require authentication methods compatible with automation

Release Engineering / Production Teams

  • Sign less frequently

  • Use high-value production keys

  • Require the strongest possible authentication and oversight

  • Often require approvals and change control

A secure code signing system must support both extremes—fast and automated DevOps workflows and slow, tightly controlled release processes—without compromising security or introducing bottlenecks.

14 Best Practices for Secure Enterprise Code Signing

Below are the key principles for designing a modern, scalable code signing environment.

1. Use a Hardware Security Module (HSM) for All Keys

All code signing keys should be generated, stored, and used in a nonexportable manner in an approved hardware security module. This applies to all signing keys, not just the production ones. 

All signing keys—production and non-production—must be:

  • Generated in the HSM

  • Stored in the HSM

  • Used in a non-exportable manner

Avoid renewing certificates for legacy software-based keys. Instead, migrate keys into the HSM, back them up, and replace them with properly generated HSM-resident keys.

2. Centralize the HSM

Never distribute private keys to users or build systems.

Centralizing key storage enables:

 

  • Permission control

  • Auditability

  • Revocation

  • Enforcement of security policies

3. Require Proxied Access to the HSM

HSMs provide excellent key protection but do not natively enforce enterprise authentication or authorization.

Introducing an HSM proxy allows you to:

  • Add MFA

  • Enforce device restrictions

  • Trigger approval workflows

  • Apply per-key policies

  • Centralize auditing

  • Simplify revocation

This proxy becomes the policy decision point for all cryptographic operations.

4. Implement Strict Access Control

Users should only access:

  • The keys they are authorized to use

  • During the timeframes they are authorized

  • Under the conditions defined by policy

Fine-grained, per-key access control is essential.

5. Require Strong, Flexible Authentication

A modern system must support:

  • MFA

  • OAuth2

  • Kerberos

  • SSO

  • Client-certificate authentication

  • Tamper-resistant local credentials for automation

Production keys should require MFA per signing request. Automated systems should have strict machine-to-machine authentication policies.

6. Authenticate Devices, Not Just Users

User identity alone is insufficient. Validate:

  • The device is enterprise-owned or approved

  • It has an unspoofable identity (TPM, Secure Enclave, etc.)

  • It meets security and patch compliance requirements

IP address checks alone are not adequate.

Device authentication should make use of tamper resistant secure enclaves (e.g., Trusted Platform Modules) wherever possible.

7. Define Per-Key Usage Policies

Policies should specify:

  • Allowed algorithms

  • Required authentication methods

  • Required approvals

  • Device restrictions

  • JIT access rules

  • Allowed geolocations

  • Notification rules

  • Key usage windows

This makes each key self-governing under centralized policy.

8. Support Approval Workflows

High-value keys should require quorum-based approvals prior to use.

Workflows should be:

  • Automatic

  • Logged

  • Enforced by the signing proxy

  • Impossible to bypass

9. Use Client-Side Hashing (Hash Signing)

To improve performance:

  • Compute the hash locally

  • Send only the hash to the signing service

  • Sign the hash within the HSM

This dramatically reduces network load and signing latency.

10. Adopt Reproducible Builds + Automated Hash Validation

Reproducible builds ensure the output is deterministic. Wherever possible, compile your code deterministically so that the output is always the same for the same source code.

Combined with automated hash validation:

  • The signing service checks the hash against your source repository

  • Unauthorized code modifications are detected

  • Attackers must compromise both source control and signing systems

This significantly increases security.

The most effective way to perform this digital hash signing check is with a technology called automated hash validation.

Using this approach, an attacker would now need to commit malicious code to the source code repository and gain access to the code signing system, instead of just gaining access to the code signing system. This is a harder attack to pull off and one that is much easier to detect since the source control’s history is tough to alter and constantly monitored by the developers.

11. Integrate with Native Signing Tools

Always sign using:

  • signtool

  • codesign

  • jarsigner

  • productsign

  • Linux package signing tools (RPM, Debian, GPG)

Avoid reverse-engineering or custom formats. Native tooling ensures compatibility and prevents breakage during vendor updates.

12. Make All Signing Activity Auditable

Record:

  • Administrative actions

  • Signing actions

  • Approval events

  • Policy changes

  • Authentication details

Provide configurable notifications to approved personnel.

13. Support Multi-Tenancy

Large enterprises require:

  • Delegated administration

  • Subdomains

  • Hierarchical permissions

  • Per-team policies

  • Isolation between business units

A robust code signing system must scale organizationally as well as technically.

14. Ensure Cryptographic Agility

Your signing system must easily support:

  • SHA-2, SHA-3

  • RSA, ECDSA, EdDSA

  • Post-quantum algorithms (once finalized by NIST)

  • Stateful and stateless signature schemes

Now, NIST is expected to make its final recommendations for post-quantum signature algorithms within the next year (technically, XMSS and HSS/LMS have already been recommended as stateful signature algorithms).

This means that a proper secure code signing system needs to be agile with respect to the cryptographic algorithms it supports. The code signing system needs to be flexible enough to introduce new algorithms that may not fit the same model as the previous algorithms (e.g., no longer hash then sign or may require state management).

Cryptography evolves—your signing infrastructure must evolve with it.

Secure Code Signing Conclusion

Building a code signing system that:

  • Integrates with every platform

  • Supports native signing tools

  • Protects all private keys in HSMs

  • Enforces strong security controls

  • Supports approval workflows

  • Scales across the enterprise

  • Maintains cryptographic agility

…is complex and resource-intensive.

That’s why we built GaraTrust.

With GaraTrust:

  • Code signing keys stay secured inside your HSMs

  • Performance stays high using client-side hashing

  • Policies, approvals, authentication, and device checks are managed centrally

  • Integrations exist for Windows, macOS, Linux, GPG, RPM, Debian, Java, and more

If you’re interested in learning more about GaraTrust or setting up a demo, get in touch with the Garantir team.

Share this post with your network.

LinkedIn
Reddit
Email