Keyless Signing With Witness and SigStore

author image

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 counter signing with one or more timestamping authorities (TSA).

Counter signing

Countersigning, also known as counter signing or counter signature, is the act of adding an additional signature to a document or agreement that has already been signed by another party. The countersignature is added as a way of providing additional authentication and verification that the original signature is valid and legitimate.

Counter signing with a timestamp provides proof that a digital signature existed at a specific time.

In the context of digital signatures, the term “counter signature” refers to the act of adding a different signature, generated by a different signer, to a digital signature. Typically, this is used to provide a signature on a signature, allowing for a proof that a signature existed at a given time (i.e., a timestamp).

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 counter signing to sign the signature created with the ephemeral key with one or more timestamping authorities (TSAs). The TSAs 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 multiple TSAs, it increases the security level of the process, as the signature can only be authenticated if a quorum of the TSAs confirm that the signature was created within the validity period.

Overall, countersigning provides a useful tool for adding an additional layer of security and verification to digital signatures and other types of content, allowing for additional authentication and verification that the original signature is valid and legitimate.

Signed Certificate Timestamp (SCT)

Sigstore does not use counter signing 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.

Update: Cosign now supports the timestamping and verifying timestamps.

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 counter 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.

  1. 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.
  2. 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).
  3. 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.
  4. 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.
  5. 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.

Sigstore Keyless Sequence Diagram
Sigstore Keyless Sequence Diagram


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 Counter Signing for Verification

Witness uses counter signing 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:

  1. The producer generates a private key, a unique digital code that is kept secret.
  2. The producer authenticates with Sigstore through OIDC and sends the corresponding public key to Fulcio.
  3. Fulcio provides a short-lived code signing certificate to the producer.
  4. The producer uses the private key to sign the software attestation and includes the code signing certificate and signature in an envelope.
  5. The producer sends the signature’s hash to a TSA (Timestamping Authority) for signing.
  6. The TSA timestamps the signature, and this timestamp response is added to the envelope.
  7. 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.
  8. 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.
Witness Keyless Sequence Diagram
Witness Keyless Sequence Diagram

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

Example: Use Witness and Fulcio to Create and Verify an Attestation

Download Witness

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 /usr/local/bin/witness.

bash <(curl -s

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 || true
git add && 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 --fulcio-oidc-client-id --fulcio-oidc-issuer sigstore --timestamp-servers -- 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 test.json.

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

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 steps section of the policy file. This corresponds with the step name indicated in the witness run command and the payload section 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
  "expires": "2030-12-17T23:57:40-05:00",
  "steps": {
    "test": {
      "name": "test",
      "attestations": [
          "type": ""
      "functionaries": [
          "type": "root",
          "certConstraint": {
            "commonname": "*",
            "dnsnames": ["*"],
            "emails": [""],
            "organizations": ["*"],
            "uris": ["*"],
            "roots": [
  "roots": {
    "3ba7b6cc4e95469d4d334b49cb257ad8537076fa84b0ca87ff4ecfe6a54680c1": {
      "intermediates": [
  "timestampauthorities": {
    "freetsa": {

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

I want to thank Andrew Block and Hayden Blauzvern from the SigStore project for their help with the editing of this article.

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.

Related Articles

Contact Us For Early Access to the Platform

TestifySec Judge Provides Visibility into the Security of Your Inventory

Learn More