Overview of Gitsign
mainsmimesign but utilizes Sigstore's keyless infrastructure to sign Git commits using your existing GitHub or OIDC identity.repository·main·Indexed 22 days ago
https://github.com/sigstore/gitsignA tool for keyless Git signing using Sigstore, enabling users to sign Git commits and tags using GitHub or OIDC identities without managing long-lived cryptographic keys. It includes gitsign-credential-cache for in-memory credential caching and gitsign-attest for experimental commit and tree attestations.
smimesign but utilizes Sigstore's keyless infrastructure to sign Git commits using your existing GitHub or OIDC identity.The gitsign-attest tool is an experimental demo used to add attestations to the latest commit SHA in your Git working directory. It stores data as a commit under refs/attestations/commits or refs/attestations/trees, ensuring the original commit remains unmodified.
For each attested commit SHA, a folder is created containing:
.sig).Currently, only public Sigstore is supported.
The gitsign-credential-cache is an optional helper binary that allows users to cache signing credentials in memory. This is useful for performing multiple signing operations in rapid succession without re-authenticating.
gitsign will automatically use those. You do not need the cache in these environments.When using offline mode, Gitsign stores a HashedRekord in Rekor. This record contains the following data for both commits and tags:
In online Rekor storage mode, Gitsign does not persist all Rekor log details directly in the Git commit. Instead, it stores the Git commit SHA in Rekor.
Signing Process:
HashedRekord of the commit SHA to Rekor.Verification Process: Verification ensures the signature matches the commit and that the commit exists in the Rekor transparency log:
NotAfter time).commit SHA + certificate (this step requires internet access).Gitsign stores data in two primary locations:
rekorMode = online (default): Data is written to the public Rekor instance as a HashedRekord containing a SHA256 hash of the commit SHA and the code signing certificate. Note that certificates may contain sensitive information like user emails or repo identifiers.rekorMode = offline: This mode is currently experimental. It allows for local/private transparency log usage.Gitsign stores signatures in the git gpgsig header using the Cryptographic Message Syntax (CMS/PKCS7) format. However, the wider Sigstore ecosystem and the sigstore-go libraries use the Sigstore bundle format.
To maintain compatibility, Gitsign performs a conversion between these two formats. The key insight is that the actual artifact being signed is not the git commit/tag body itself, but rather the marshaled SignedAttrs (CMS signed attributes). This structure contains the content type, the message digest (sha256 of the git object), and the signing time.
Because the signature is computed over these attributes, the messageDigest in a Sigstore bundle corresponds to the sha256(DER(SignedAttrs)) in CMS.
During signing, Gitsign performs the inverse operation to ensure the resulting CMS object is compatible with git's expectations.
Workflow:
BuildSignedAttributes(body) $\rightarrow$ (SignedAttrs, marshaled-for-signing)sign.Bundle(PlainData{marshaled}, ...) $\rightarrow$ bundle (signature + cert + tlog)BundleToSignedData(body, SignedAttrs, b) $\rightarrow$ cms.SignedData (the final stored signature)Implementation Details:
fulcio.Identity (adapted to sign.Keypair and sign.CertificateProvider). The OIDC/Fulcio flow and credential caching remain unchanged; sigstore-go only handles the signing and Rekor upload.SignerInfo is assembled around the signature using internal fork helpers. The result is byte-for-byte equivalent to what a native CMS signer would produce.sigstore-go.In offline Rekor storage mode, Gitsign stores a HashedRekord in Rekor that corresponds to the commit or tag content. Because this is complex to query manually, the Rekor log entry fields and inclusion proof are stored within the PKCS7 object as unauthenticated attributes (meaning they are not part of the cryptographic signature itself).
For Commits:
Rekor LogEntry from the signature.NotAfter time).Rekor LogEntry inclusion offline.For Tags:
Rekor LogEntry from the signature.NotAfter time).Rekor LogEntry inclusion offline.Both commits and tags store the following in their signatures:
sha256)Rekor TransparencyLogEntrysha256(der(sort(system time | commit data | content type)))During verification, Gitsign parses the stored CMS and projects each signer onto a bundle.
Workflow:
ParseSignaturePEM(sig) $\rightarrow$ cms.SignedDataSignerInfoToBundle(sd, signer) $\rightarrow$ { Bundle, Artifact }Important Notes:
Artifact is the marshaled SignedAttrs. Callers must pass this as the verification artifact because the bundle's messageSignature only contains the digest, not the full attributes.SignedDataToBundle returns one bundle per signer.sigstore-go cannot verify if the SignedAttrs actually describe the specific git object from the bundle alone, Gitsign performs a manual check: it compares sha256(git object) against the SignedAttrs message-digest attribute.Gitsign can be configured to verify that the identity in the Fulcio certificate matches your local Git configuration (user.name and user.email).
Verification works by matching the certificate's Subject Alternative Name (SAN) against your Git config in this priority order:
EmailAddresses SAN value matches user.email. This is the standard method for human users.URI SAN value matches user.name. This is the standard method for automated workloads.If multiple SAN values are present in the certificate, verification succeeds if at least one matches.
git config gitsign.matchCommitter trueThe sigstore-go conversion path is enabled by default for both signing and verification. If you need to fall back to the legacy CMS + Rekor path, you can disable it using either a git configuration or an environment variable.
Note that the on-disk CMS signature format remains identical regardless of this setting; only the internal implementation of signing and verification changes.
# Via git config
git config gitsign.enableSigstoreGo false
# Via environment variable
export GITSIGN_ENABLE_SIGSTORE_GO=false