https://www.youtube.com/watch?v=jvh9WHtUiW0 Introduction Ensuring the integrity of the software supply chain is …
Cryptographic keys are essential to software supply chain security, but managing them can be complex and time-consuming. This is especially true for long-lived cryptographic keys stored on disk. These keys are generally used for signing artifacts or authenticating user accounts.
The recent security incident at CircleCI resulting in the compromise of DataDogs RPM package signing key has brought attention to the importance of effective key management practices. Long-lived keys stored on disk can easily be compromised by attackers, allowing them to impersonate official packages and leave customers and users vulnerable to supply chain attacks. This was tragically demonstrated in the SolarWinds hack, where officially signed packages for their flagship product caused a devastating supply chain attack.
An alternative approach is to use short-lived, ephemeral keys that are generated on-the-fly for each signature operation, making them more difficult for an attacker to compromise. However, verifying keyless signatures is more complex than traditional signatures, as the corresponding certificate used to validate the signature may no longer be valid when the signature needs to be verified.
This article will discuss how to verify keyless signatures and how we implement keyless signing in Witness.
Keyless signatures are more difficult for an attacker to compromise.
What is a Keyless Signature, and How Can We Trust It?
A keyless signature is a digital signature that allows for the secure authentication of a digital message without the need to manage long-lived private keys. When a message is signed using a keyless signature, an ephemeral key is generated and used for signing. In the case of Sigstore, the corresponding certificate is then automatically generated and signed by the Fulcio root certificate authority (CA), and the certificate is published in a certificate transparency log. When using SPIRE to generate ephemeral keys, we do not have a transparency log to verify against so we need another way to verify when the signature was created. We accomplish this by multi-signing with one or more timestamping authorities (TSA).
Multi-signature, or multi-sig, is a method of digital signing where multiple signatures are required to authorize a transaction or action. This can be useful when multiple parties need to approve a transaction, such as in a corporate or decentralized organization. A transaction can only be executed in a multi-sig setup if a specific number of signatures are provided, often set in advance. This provides an additional layer of security by ensuring that a transaction can only be executed if a certain number of parties agree.
Multisig is a method of digital signing where multiple signatures are required to authorize a transaction or action
In the case of keyless signatures, the ephemeral key used to sign the message is not long-lived, so it’s impossible to verify the signature’s authenticity based on the traditional certificate chain model. Therefore, one way to achieve this is by using multi-signing to sign the signature created with the ephemeral key with one or more timestamping authorities (TSA). The TSA(s) will sign the message with their key, and create a timestamp, thus providing proof that the signature was created within the validity period of the certificate. Furthermore, by using multi-sig with multiple TSA(s), it increases the security level of the process, as the signature can only be authenticated if a quorum the TSA(s) confirm that the signature was created within the validity period.
Signed Certificate Timestamp (SCT)
Sigstore does not use multi-sig to verify when a signature happened, instead a signed certificate timestamp (SCT), which is a promise for inclusion into the CT Log, is embedded within the ephemeral certificate then the certificate is signed again by Fulcio. This creates a final certificate that contains the embedded SCT and can be used by clients to verify the authenticity and integrity of the certificate. The code used to generate the SCT is located in the certifcate-transparency-go repository.
This transparent and auditable process allows for the secure authentication of the digital signature without the need for long-lived private keys, which cause damage if leaked. Using keyless signatures can improve the security and reduce the complexity of digital signatures by eliminating the need to secure long-lived private keys. It can also make the revocation process easier since the root CA can simply stop signing the ephemeral keys used for signing if the user or system requesting a certificate for their key is no longer trusted.
In the case of the Witness project, we support keyless signatures created using the Sigstore key provider or the SPIRE key provider. The attestation is signed by the ephemeral keys and then multi-signed by one or more TSA(s). The Witness command-line tool implements both Sigstore and SPIRE libraries to provide users with flexibility in how they manage their keyless signatures.
We do not currently support checking the SCT embedded by Fulcio. However, we do plan on supporting verifying with SCTs in the future. However, signing with multiple TSAs allows users to trust ephemeral certificates while also providing a robust air-gap capability.
Signing with multiple TSAs allows users to trust ephemeral certificates while also providing a robust air-gap capability.
Technical Description of Sigstore Keyless signatures
Sigstore is a platform for creating and verifying keyless digital signatures for software artifacts. The keyless signing flow in Sigstore involves three main components: a certificate authority (Fulcio), a transparency log (Trillian), and client API for signing and verifying artifacts. Witness implements the Fulcio client API to obtain signed certificates from the Fulcio CA. Witness does not currently validate the embedded SCT.
Fulcio is a free, automatic certificate authority (CA) that issues short-lived certificates for signing code. These certificates include a subject identity, such as an email address, and special Sigstore-specific ASN.1 object identifiers. One of these objects is a signed certificate timestamp (SCT), which serves as proof of the time at which the certificate was issued.
Fulcio publishes all issued certificates to a certificate transparency log (CT) for verifiers to check if their identity has been compromised or mis-issued. However, Sigstore clients only check the validity of the SCT, which is embedded in the certificate. The SCT acts as a promise for inclusion in the CT log but Cosign does not use the timestamp from the CT log. Instead, Cosign verifies that the SCT is valid, then it gets the inclusion time for the record it creates in Rekor corresponding to the artifact it signs and uses it to verify the signature happened within the validity period. We discuss Rekor later in this article.
Trillian (Certificate Transparency Log)
Trillian is a tamper-proof append-only log. It provides an immutable, verifiable history of activity and is used at a global scale by certificate issuers for certificate transparency. For example, Fulcio uses Trillian for transparency and for providing the SCT.
Fulcio Client API
Sigstore has a client API that allows users to easily sign and verify software artifacts without the need to manage keys. The API simplifies the process of using digital signatures to ensure the integrity and authenticity of the software. It is intended to be used by individual users, open-source communities, and organizations to improve the security of their software supply chain. There is an example of using the Fulcio API in the Fulcio GitHub Repo.
The process involves several parties, including the software producer, OIDC (OpenID Connect), Fulcio, the CT Log (Trillian), and the consumer.
- The process starts with the producer generating a private key, a unique digital code that is kept secret. The producer then authenticates with Sigstore through OIDC and sends the corresponding public key to Fulcio.
- Fulcio then publishes the certificate to the certificate transparency log, which records the certificate and provides a promise for inclusion as a signed timestamp (SCT).
- Fulcio provides a short-lived code signing certificate that includes an SCT (Signed Certificate Timestamp). The SCT is proof of inclusion in the certificate transparency log.
- The producer uses their private key to sign the software artifact’s meta-data. Finally, the signed meta-data is sent along with the software artifact to the consumer. Tools such as cosign rely on OCI (Open Container Initiative) repositories to distribute this signed meta-data.
- The consumer can then check with the CT Log to verify the authenticity and integrity of the certificate used to sign the software artifact. The consumer can also do an offline verification using the SigStore Trust root. Finally, the consumer checks the timestamp in the signed certificate for certificate validity.
Note: The TUF trust root is online, but it can be cached by the consumer, so updates are only required every seven days. However, there is currently no way to completely do offline verification unless the consumer chooses to ignore expired timestamps, which would leave the system vulnerable to man-in-the-middle (MITM) attacks, so it is not recommended.
The SPIFFE/SPIRE Project
SPIFFE is a specification that enables the distribution of identity (SVID) in the form of x.509 certificates or JWTs. Its reference implementation is called SPIRE. SPIRE allows administrators to distribute private keys based on inventory data such as machine identity and workload identity. However, this added flexibility comes at the cost of increased configuration complexity and maintenance. Our next article will explore how SPIRE can provide robust authentication mechanisms beyond those used in Fulcio’s OIDC verification.
Overview of the Witness project and its use of keyless signatures for attestations
Witness is an open-source tool developed by TestifySec to secure software development practices and ensure compliance. First, it generates evidence about the software development process, such as test results, artifacts created, and user interactions. Then, it allows users to enforce policy based on the attributes of the evidence collected and the users or machines involved in the creation of the evidence.
The evidence or attestations created by Witness must be trusted and attached to a functionary (authorized user). Witness policy enables administrators to enforce the steps used to create an artifact and who or what ran those steps.
Witness policy enables administrators to enforce the steps used to create an artifact and who or what ran those steps.
Benefits of using MultiSig for Verification
Witness uses multi-sig with trusted timestamp authorities (TSAs) for verifying timestamps included in our attestations. This implementation allows users to verify attestations created with ephemeral keys if they trust the TSAs and the issuer of the short-lived certificate. Using ephemeral keys in combination with a TSA significantly reduces the damage an attacker can cause if a private signing key is compromised. For instance, with Fulcio, the default certificate validity period is 20 minutes, but using a TSA can reduce this period to less than a minute. Additionally, attestation data can be verified across an air gap if the roots of trust (CA) for both the ephemeral keys and TSAs are present on both sides of the air gap. Most organizations requiring air-gapped capability have a method to distribute these root certificates.
Overview of the Witness Signing and Verification Flow
Witness verification is designed to function without an internet connection or any centralized service, and as such, we implemented timestamping via RFC 3161 before transparency log verification. This process differs from the reference Cosign verification. Here is a step-by-step breakdown of the flow:
- The producer generates a private key, a unique digital code that is kept secret.
- The producer authenticates with Sigstore through OIDC and sends the corresponding public key to Fulcio.
- Fulcio provides a short-lived code signing certificate to the producer.
- The producer uses the private key to sign the software attestation and includes the code signing certificate and signature in an envelope.
- The producer sends the signature’s hash to a TSA (Timestamping Authority) for signing.
- The TSA timestamps the signature, and this timestamp response is added to the envelope.
- The producer provides the signed software attestation to the consumer. The public key or CA of Fulcio and TSAs are provided to the consumer through a Witness policy.
- The consumer verifies the authenticity and integrity of the software attestation by checking the public key was issued by Fulcio CA, the signature matches the attestation data, a trusted TSA timestamped the signature, the signature was timestamped within the certificate validity period, and the attestation data meets policy constraints. The consumer can also query for the software attestation via Archivista’s API.
What about Rekor, Cosign, and Transparency?
It’s worth noting that currently, the Witness verification process does not verify the SCT or publish the signed secure hash of the attestation to the Rekor transparency log. This would provide a transparent and auditable record of the signing process.
Rekor and transparency are closely related in the context of Cosign. Cosign uses Rekor as an additional layer of verification by storing a hashed record of the artifacts it signs. Rekor is an append-only transparency log that uses Trillian as its store. It stores signed artifact meta-data and their corresponding certificates. This allows users to verify the authenticity and integrity of the artifacts by checking the signatures against the entries in the log.
This design allows for public auditing of artifacts without exposing their details, but it does give a signal about internal processes that might not be intended for public consumption. It also adds complexity when trying to verify artifacts across security boundaries. With this in mind, we plan to implement transparency as an option in Witness to provide more auditability of the attestations created in addition to the current flow which allows for verification using the time stamping protocol (TSP). You can learn more about how certificate transparency works at https://certificate.transparency.dev/howctworks/.
Example: Use Witness and Fulcio to Create and Verify an Attestation
First, download the Witness binary from the releases page on GitHub. You can also use the following bash/curl command to download, extract, verify the shasum of the binary, then install it at
bash <(curl -s https://raw.githubusercontent.com/testifysec/witness/main/install-witness.sh)
Create the Signed Attestation
Next, run a build step and record the attestation. In this example, we will remove a test file if it exists, init a git repo, and make a commit. Witness runs a
git attestor by default and needs a valid commit. Then use the
witness run command to record the attestation. The
-s flag specifies the step name, the
-o flag specifies the output file,
--fulcio flag specifies the URL of the Fulcio server,
--fulcio-oidc-client-id flag specifies the OIDC client ID,
--fulcio-oidc-issuer flag specifies the OIDC issuer, and
--timestamp-servers flag specifies the timestamp servers.
echo "hello"> test.txt is the command we will create an attestation for. The Sigstore public good instance and FreeTSA are used in this example.
git init || true touch README.md || true git add README.md && git commit -m "init" || true rm test.txt || true
Now you are ready to run the command to create the attestation.
witness run -s test -o test.json --fulcio https://v1.fulcio.sigstore.dev --fulcio-oidc-client-id https://oauth2.sigstore.dev/auth --fulcio-oidc-issuer sigstore --timestamp-servers https://freetsa.org/tsr -- echo "hello" > test.txt
This command will run the command
echo "hello"> test.txt and record the attestation of the command in a file called
View the attestation data in the signed DSSE Envelope. You can do this by running the following command:
cat test.json | jq -r .payload | base64 -d | jq
Create the Artifact Policy
Download the Fulcio Root CA. The Fulcio Root CA is used to verify the Fulcio certificate chain. It is available at https://fulcio.sigstore.dev/api/v2/trustBundle
Download the FreeTSA CA Certificate on their website.
Create a policy file that defines the attestations required for a build step to be considered valid. Next, add the base64 encoded TSA certs, Fulcio Root, and Intermediate certificates to the policy file and as a functionary on the build step.
- Make sure you replace my email with one associated with the account you used to sign the attestation.
- Notice the name and identifier in the
stepssection of the policy file. This corresponds with the
stepname indicated in the
witness runcommand and the
payloadsection of the attestation.
- You can also specify Rego constraints for each attestation which is evaluated against the attestation payload.
- Save the policy below at policy.json. These files are also available in our example repo
Sign the policy file
Policies need to be signed to ensure the authenticity and integrity of the policy. Signing the policy ensures that the policy has not been tampered with or modified by an unauthorized party. It also verifies that the intended author or organization indeed created the policy. This ensures that the policy can be trusted as a legitimate and accurate representation of the intended build or supply chain process. Signing the policy also enables the policy to be verified and authenticated by third-party consumers or auditors.
Create a keypair to sign the policy with.
openssl genrsa -out testkey.pem 2048 openssl rsa -in testkey.pem -outform PEM -pubout -out testpub.pem
Sign the policy file with the keypair.
witness sign -k testkey.pem -o policy-signed.json -f policy.json
Currently, we only support signing and verifying policy with long-lived file-based keypairs. Work is in progress to help users distribute, manage, and trust policy using TUF and additional key providers.
Verify The Attestation
witness verify -p policy-signed.json -a test.json -k testpub.pem -f test.txt
Keyless signatures provide a secure way to authenticate digital messages without the need to manage long-lived private keys. However, verifying the authenticity of these signatures can be more complex than traditional signatures.
The Witness project uses keyless signatures to authenticate digital messages without the need to manage long-lived private keys. We use timestamping authorities (TSAs) to add a timestamp to the signature created by the ephemeral key. This timestamp proves that the signature was created within the certificate’s validity period and allows us to verify the authenticity of the keyless signature even when the device or system is offline or disconnected from the internet. This ensures that attestations created with Witness can be trusted and verified across an air gap
If you want to enhance the security of your software supply chain, we encourage you to explore our Witness and Archivista GitHub repositories. Our team offers support and services, and we are developing a Software as a Service (SaaS) platform. If you are interested in learning more about how we can assist you in implementing keyless signatures in your organization, please don’t hesitate to contact us.