### Install sigstore-go-signing Example Source: https://github.com/sigstore/sigstore-go/blob/main/docs/signing.md Installs the example command-line tool for sigstore-go signing. Ensure Go 1.21 or later is installed. ```shell go install ./examples/sigstore-go-signing ``` -------------------------------- ### Install sigstore-go Source: https://context7.com/sigstore/sigstore-go/llms.txt Use go get to install the sigstore-go library. ```bash go get github.com/sigstore/sigstore-go ``` -------------------------------- ### Build Sigstore Go Examples Source: https://github.com/sigstore/sigstore-go/blob/main/examples/sigstore-go-verification/README.md Builds all example executables for Sigstore Go tools. The built binaries are placed in the 'examples/' subdirectory. ```shell make build-examples go build -C ./examples/oci-image-verification -o oci-image-verification . go build -C ./examples/sigstore-go-signing -o sigstore-go-signing . go build -C ./examples/sigstore-go-verification -o sigstore-go-verification . ``` ```shell find examples -type f -perm -u+x | sort ``` -------------------------------- ### Install sigstore-go CLI Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Installs the sigstore-go verification CLI using the go tool. ```shell go install ./examples/sigstore-go-verification ``` -------------------------------- ### Verify Example Bundle with Signing Key Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Verifies an example bundle signed with a specific key. This requires loading the public key from a file and configuring the verifier with trusted root material. Ensure the path to the public key file and the bundle are correct. This snippet depends on 'crypto', 'encoding/hex', 'encoding/json', 'encoding/pem', 'fmt', 'os', 'time', 'github.com/sigstore/sigstore/pkg/signature', 'github.com/sigstore/sigstore-go/pkg/bundle', 'github.com/sigstore/sigstore-go/pkg/root', and 'github.com/sigstore/sigstore-go/pkg/verify'. ```go package main import ( "crypto" _ "crypto/sha256" "crypto/x509" "encoding/hex" "encoding/json" "encoding/pem" "fmt" "os" "time" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore-go/pkg/bundle" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/verify" ) type verifyTrustedMaterial struct { root.TrustedMaterial keyTrustedMaterial root.TrustedMaterial } func (v *verifyTrustedMaterial) PublicKeyVerifier(hint string) (root.TimeConstrainedVerifier, error) { return v.keyTrustedMaterial.PublicKeyVerifier(hint) } func main() { b, err := bundle.LoadJSONFromPath("./examples/bundle-publish.json") if err != nil { panic(err) } // This bundle uses public good instance with an added signing key trustedRoot, err := root.FetchTrustedRoot() if err != nil { panic(err) } keyData, err := os.ReadFile("examples/publish_key.pub") if err != nil { panic(err) } block, _ := pem.Decode(keyData) if block == nil { panic("unable to PEM decode provided key") } pubKey, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { panic(err) } verifier, err := signature.LoadVerifier(pubKey, crypto.SHA256) if err != nil { panic(err) } newExpiringKey := root.NewExpiringKey(verifier, time.Time{}, time.Time{}) trustedMaterial := &verifyTrustedMaterial{ TrustedMaterial: trustedRoot, keyTrustedMaterial: root.NewTrustedPublicKeyMaterial(func(_ string) (root.TimeConstrainedVerifier, error) { return newExpiringKey, nil }), } sev, err := verify.NewVerifier(trustedMaterial, verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1)) if err != nil { panic(err) } digest, err := hex.DecodeString("76176ffa33808b54602c7c35de5c6e9a4deb96066dba6533f50ac234f4f1f4c6b3527515dc17c06fbe2860030f410eee69ea20079bd3a2c6f3dcf3b329b10751") if err != nil { panic(err) } result, err := sev.Verify(b, verify.NewPolicy(verify.WithArtifactDigest("sha512", digest), verify.WithKey())) if err != nil { panic(err) } fmt.Println("Verification successful!\n") marshaled, err := json.MarshalIndent(result, "", " ") if err != nil { panic(err) } fmt.Println(string(marshaled)) } ``` -------------------------------- ### Build the OCI Image Verification Example Source: https://github.com/sigstore/sigstore-go/blob/main/docs/oci-image-verification.md Clone the repository and navigate to the example directory to build the CLI tool. This tool wraps the Go API for OCI image verification. ```shell go build . ``` -------------------------------- ### Verify Example Bundle with Identity Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Verifies an example bundle using identity-based verification. Ensure the bundle path and artifact digest are correct for your use case. This snippet requires the 'sigstore-go/pkg/bundle', 'sigstore-go/pkg/root', 'sigstore-go/pkg/tuf', and 'sigstore-go/pkg/verify' packages. ```go package main import ( "encoding/hex" "encoding/json" "fmt" "github.com/sigstore/sigstore-go/pkg/bundle" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/tuf" "github.com/sigstore/sigstore-go/pkg/verify" ) func main() { opts := tuf.DefaultOptions() client, err := tuf.New(opts) if err != nil { panic(err) } trustedMaterial, err := root.GetTrustedRoot(client) if err != nil { panic(err) } sev, err := verify.NewVerifier(trustedMaterial, verify.WithSignedCertificateTimestamps(1), verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1)) if err != nil { panic(err) } digest, err := hex.DecodeString("76176ffa33808b54602c7c35de5c6e9a4deb96066dba6533f50ac234f4f1f4c6b3527515dc17c06fbe2860030f410eee69ea20079bd3a2c6f3dcf3b329b10751") if err != nil { panic(err) } certID, err := verify.NewShortCertificateIdentity("https://token.actions.githubusercontent.com", "", "", "^https://github.com/sigstore/sigstore-js/") if err != nil { panic(err) } b, err := bundle.LoadJSONFromPath("./examples/bundle-provenance.json") if err != nil { panic(err) } result, err := sev.Verify(b, verify.NewPolicy(verify.WithArtifactDigest("sha512", digest), verify.WithCertificateIdentity(certID))) if err != nil { panic(err) } marshaled, err := json.MarshalIndent(result, "", " ") if err != nil { panic(err) } fmt.Println(string(marshaled)) } ``` -------------------------------- ### Verify Sigstore Bundle Source: https://github.com/sigstore/sigstore-go/blob/main/examples/sigstore-go-verification/README.md Verifies a Sigstore bundle using the CLI tool. This example demonstrates specifying artifact digest, algorithm, expected issuer, and expected SAN, along with the path to the bundle file. ```shell ./sigstore-go-verification \ -artifact-digest 76176ffa33808b54602c7c35de5c6e9a4deb96066dba6533f50ac234f4f1f4c6b3527515dc17c06fbe2860030f410eee69ea20079bd3a2c6f3dcf3b329b10751 \ -artifact-digest-algorithm sha512 \ -expectedIssuer https://token.actions.githubusercontent.com \ -expectedSAN https://github.com/sigstore/sigstore-js/.github/workflows/release.yml@refs/heads/main \ ../bundle-provenance.json Verification successful! { "version": 20230823, "statement": { "_type": "https://in-toto.io/Statement/v0.1", "predicateType": "https://slsa.dev/provenance/v0.2", "subject": ... }, ... } ``` -------------------------------- ### Fetch and Select Signing Service Endpoints Source: https://context7.com/sigstore/sigstore-go/llms.txt Use `root.FetchSigningConfig` to get the `signing_config.v0.2.json` which lists available Fulcio, Rekor, and TSA services. `root.SelectService` or `root.SelectServices` can then be used to find the best matching endpoint for a desired API version and current time. ```go package main import ( "fmt" "log" "time" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/sign" ) func main() { sc, err := root.FetchSigningConfig() if err != nil { log.Fatal(err) } // Select the best Fulcio endpoint for API v1 fulcioService, err := root.SelectService(sc.FulcioCertificateAuthorityURLs(), sign.FulcioAPIVersions, time.Now()) if err != nil { log.Fatal(err) } fmt.Printf("Fulcio URL: %s (API v%d)\n", fulcioService.URL, fulcioService.MajorAPIVersion) // Select all available Rekor endpoints (API v1 or v2) rekorServices, err := root.SelectServices( sc.RekorLogURLs(), sc.RekorLogURLsConfig(), sign.RekorAPIVersions, // []uint32{1, 2} time.Now(), ) if err != nil { log.Fatal(err) } for _, svc := range rekorServices { fmt.Printf("Rekor URL: %s (API v%d, operator: %s)\n", svc.URL, svc.MajorAPIVersion, svc.Operator) } // Select TSA endpoints tsaServices, err := root.SelectServices( sc.TimestampAuthorityURLs(), sc.TimestampAuthorityURLsConfig(), sign.TimestampAuthorityAPIVersions, time.Now(), ) if err != nil { log.Fatal(err) } for _, svc := range tsaServices { fmt.Printf("TSA URL: %s\n", svc.URL) } } ``` -------------------------------- ### Example Commit Message Format Source: https://github.com/sigstore/sigstore-go/blob/main/CONTRIBUTING.md Follow this format for commit messages to ensure clarity for reviewers and assist in automated release note generation. The first line is a concise summary, followed by a blank line and a more detailed explanation. ```git Summarize changes in around 50 characters or less More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of the commit and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); various tools like `log`, `shortlog` and `rebase` can get confused if you run the two together. Explain the problem that this commit is solving. Focus on why you are making this change as opposed to how (the code explains that). Are there side effects or other unintuitive consequences of this change? Here's the place to explain them. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here If you use an issue tracker, put references to them at the bottom, like this: Resolves: #123 See also: #456, #789 ``` -------------------------------- ### Example Successful Verification Result (JSON) Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md A sample JSON output representing a successful verification result, including media type, statement details, signature information, and verified timestamps. ```json { "mediaType": "application/vnd.dev.sigstore.verificationresult+json;version=0.1", "statement": { "_type": "https://in-toto.io/Statement/v0.1", "predicateType": "https://slsa.dev/provenance/v0.2", "subject": [ { "name": "pkg:npm/sigstore@1.3.0", "digest": { "sha512": "76176ffa33808b54602c7c35de5c6e9a4deb96066dba6533f50ac234f4f1f4c6b3527515dc17c06fbe2860030f410eee69ea20079bd3a2c6f3dcf3b329b10751" } } ], "predicate": "omitted for brevity" }, "signature": { "certificate": { "certificateIssuer": "CN=sigstore-intermediate,O=sigstore.dev", "subjectAlternativeName": { "type": "URI", "value": "https://github.com/sigstore/sigstore-js/.github/workflows/release.yml@refs/heads/main" }, "issuer": "https://token.actions.githubusercontent.com", "githubWorkflowTrigger": "push", "githubWorkflowSHA": "dae8bd8eb433a4147b4655c00fe73e0f22bc0fb1", "githubWorkflowName": "Release", "githubWorkflowRepository": "sigstore/sigstore-js", "githubWorkflowRef": "refs/heads/main", "buildSignerURI": "https://github.com/sigstore/sigstore-js/.github/workflows/release.yml@refs/heads/main", "buildSignerDigest": "dae8bd8eb433a4147b4655c00fe73e0f22bc0fb1", "runnerEnvironment": "github-hosted", "sourceRepositoryURI": "https://github.com/sigstore/sigstore-js", "sourceRepositoryDigest": "dae8bd8eb433a4147b4655c00fe73e0f22bc0fb1", "sourceRepositoryRef": "refs/heads/main", "sourceRepositoryIdentifier": "495574555", "sourceRepositoryOwnerURI": "https://github.com/sigstore", "sourceRepositoryOwnerIdentifier": "71096353", "buildConfigURI": "https://github.com/sigstore/sigstore-js/.github/workflows/release.yml@refs/heads/main", "buildConfigDigest": "dae8bd8eb433a4147b4655c00fe73e0f22bc0fb1", "buildTrigger": "push", "runInvocationURI": "https://github.com/sigstore/sigstore-js/actions/runs/4735384265/attempts/1" } }, "verifiedTimestamps": [ { "type": "Tlog", "uri": "TODO", "timestamp": "2023-04-18T13:45:12-04:00" } ], "verifiedIdentity": { "subjectAlternativeName": { ``` -------------------------------- ### Example Verification Result Bundle Source: https://github.com/sigstore/sigstore-go/blob/main/docs/oci-image-verification.md This JSON represents a constructed bundle for an image at a specific point in time, followed by a successful verification result. It includes details about the media type, verification material, x509 certificates, and Tlog entries. ```json { "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.1", "verificationMaterial": { "x509CertificateChain": { "certificates": [ { "rawBytes": "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 } ] }, "tlogEntries": [ { "logIndex": "53194260", "logId": { "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" }, "kindVersion": { "kind": "hashedrekord", "version": "0.0.1" }, "integratedTime": "1701205628", "inclusionPromise": { "signedEntryTimestamp": "MEYCIQCOvYr8ezbNfJMGw0CIT4krwy2fSnIVMUfWJ4Xjn7ZsOQIhAMROYirqcbs76Y4B4I/wDlqdDavbx3OB6/YPezB46npD" } } ] } } ``` -------------------------------- ### Extend Certificate Authority Verification with Revocation Checks Source: https://context7.com/sigstore/sigstore-go/llms.txt Implement custom validation logic by wrapping `root.CertificateAuthority` and `root.TrustedMaterial`. This example adds a check for revoked certificate serial numbers before proceeding with the default verification. Ensure the `revokedSerials` list is populated with the serial numbers of certificates to be considered revoked. ```go package main import ( "crypto/x509" "fmt" "log" "math/big" "time" "github.com/sigstore/sigstore-go/pkg/bundle" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/verify" ) type ValidatingCertificateAuthority struct { root.CertificateAuthority revokedSerials []*big.Int } func (ca *ValidatingCertificateAuthority) Verify(leafCert *x509.Certificate, ts time.Time) ([][]*x509.Certificate, error) { for _, sn := range ca.revokedSerials { if leafCert.SerialNumber.Cmp(sn) == 0 { return nil, fmt.Errorf("certificate %v is revoked", sn) } } return ca.CertificateAuthority.Verify(leafCert, ts) } type TrustedMaterialWithRevocation struct { root.TrustedMaterial revokedSerials []*big.Int } func (tm *TrustedMaterialWithRevocation) FulcioCertificateAuthorities() []root.CertificateAuthority { cas := tm.TrustedMaterial.FulcioCertificateAuthorities() wrapped := make([]root.CertificateAuthority, len(cas)) for i, ca := range cas { wrapped[i] = &ValidatingCertificateAuthority{ca, tm.revokedSerials} } return wrapped } func main() { trustedRoot, err := root.FetchTrustedRoot() if err != nil { log.Fatal(err) } // Revoke a specific certificate serial number revokedSN, _ := new(big.Int).SetString("123456789", 10) trustedMaterial := &TrustedMaterialWithRevocation{ TrustedMaterial: trustedRoot, revokedSerials: []*big.Int{revokedSN}, } verifier, err := verify.NewVerifier(trustedMaterial, verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1), ) if err != nil { log.Fatal(err) } b, err := bundle.LoadJSONFromPath("./bundle.sigstore.json") if err != nil { log.Fatal(err) } certID, _ := verify.NewShortCertificateIdentity("https://token.actions.githubusercontent.com", "", "", "^https://github.com/myorg/") result, err := verifier.Verify(b, verify.NewPolicy(verify.WithoutArtifactUnsafe(), verify.WithCertificateIdentity(certID))) if err != nil { log.Fatal("verification failed:", err) // will fail if cert is in revocation list } _ = result } ``` -------------------------------- ### Sigstore Go Signing CLI Help Source: https://github.com/sigstore/sigstore-go/blob/main/examples/sigstore-go-verification/README.md Displays the help text for the Sigstore Go signing CLI, outlining options for signing content and including transparency log entries. ```shell ./sigstore-go-signing -h Usage of ./sigstore-go-signing: -id-token string OIDC token to send to Fulcio -in-toto Content to sign is in-toto document -rekor Including transparency log entry from Rekor -tsa Include signed timestamp from timestamp authority ``` -------------------------------- ### TUF Client Initialization Source: https://context7.com/sigstore/sigstore-go/llms.txt Demonstrates how to create a Sigstore TUF client, either using default public-good options or with custom configurations for a private repository. ```APIDOC ## `tuf.New` / `tuf.DefaultOptions` — TUF client for fetching trust material `tuf.New` creates a Sigstore TUF client for fetching targets (trusted root, signing config) from a TUF repository. `DefaultOptions` pre-configures the Sigstore public-good instance with an embedded root. ### Usage ```go package main import ( "fmt" "log" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/tuf" ) func main() { // Default public-good client client, err := tuf.DefaultClient() if err != nil { log.Fatal(err) } // Fetch trusted_root.json target trustedRoot, err := root.GetTrustedRoot(client) if err != nil { log.Fatal(err) } fmt.Printf("Rekor logs: %d\n", len(trustedRoot.RekorLogs())) fmt.Printf("Fulcio CAs: %d\n", len(trustedRoot.FulcioCertificateAuthorities())) // Custom TUF repository (private Sigstore deployment) customRootJSON, _ := tuf.DefaultOptions().Root, nil // or load from file opts := &tuf.Options{ Root: customRootJSON, RepositoryBaseURL: "https://tuf.mycompany.com", CachePath: "/var/cache/sigstore-tuf", CacheValidity: tuf.MaxCache, // use cache until metadata expires } customClient, err := tuf.New(opts) if err != nil { log.Fatal(err) } // Get arbitrary TUF target data, err := customClient.GetTarget("trusted_root.json") if err != nil { log.Fatal(err) } fmt.Printf("Got %d bytes of trusted root JSON\n", len(data)) } ``` ``` -------------------------------- ### Create Sigstore TUF Client with Default Options Source: https://context7.com/sigstore/sigstore-go/llms.txt Use `tuf.DefaultClient()` to create a client for the public-good Sigstore instance. This client fetches trusted root and signing configuration. For custom repositories, use `tuf.New` with `tuf.Options` to specify the repository URL, cache path, and root configuration. ```go package main import ( "fmt" "log" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/tuf" ) func main() { // Default public-good client client, err := tuf.DefaultClient() if err != nil { log.Fatal(err) } // Fetch trusted_root.json target trustedRoot, err := root.GetTrustedRoot(client) if err != nil { log.Fatal(err) } fmt.Printf("Rekor logs: %d\n", len(trustedRoot.RekorLogs())) fmt.Printf("Fulcio CAs: %d\n", len(trustedRoot.FulcioCertificateAuthorities())) // Custom TUF repository (private Sigstore deployment) customRootJSON, _ := tuf.DefaultOptions().Root, nil // or load from file opts := &tuf.Options{ Root: customRootJSON, RepositoryBaseURL: "https://tuf.mycompany.com", CachePath: "/var/cache/sigstore-tuf", CacheValidity: tuf.MaxCache, // use cache until metadata expires } customClient, err := tuf.New(opts) if err != nil { log.Fatal(err) } // Get arbitrary TUF target data, err := customClient.GetTarget("trusted_root.json") if err != nil { log.Fatal(err) } fmt.Printf("Got %d bytes of trusted root JSON\n", len(data)) } ``` -------------------------------- ### Create Sigstore Bundle Verifier Source: https://context7.com/sigstore/sigstore-go/llms.txt Use `verify.NewVerifier` to create a `Verifier` instance. Configure it with a `TrustedMaterial` and policy options like SCT requirements, transparency log inclusion, and observer timestamps. This is essential for verifying bundles signed with Fulcio certificates, Rekor, and SCTs, or for bundles signed with long-lived keys. ```go package main import ( "log" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/verify" ) func main() { trustedRoot, err := root.FetchTrustedRoot() if err != nil { log.Fatal(err) } // For bundles signed with Fulcio certificates + Rekor + SCTs verifier, err := verify.NewVerifier(trustedRoot, verify.WithSignedCertificateTimestamps(1), // require ≥1 SCT in Fulcio cert verify.WithTransparencyLog(1), // require ≥1 Rekor inclusion proof verify.WithObserverTimestamps(1), // require ≥1 observer timestamp (TSA or Rekor) ) if err != nil { log.Fatal(err) } _ = verifier // For bundles signed with long-lived keys (no certificate, no timestamp) keyVerifier, err := verify.NewVerifier(trustedRoot, verify.WithNoObserverTimestamps(), ) if err != nil { log.Fatal(err) } _ = keyVerifier // For private deployments with long-lived certificates certVerifier, err := verify.NewVerifier(trustedRoot, verify.WithCurrentTime(), // use wall clock instead of observer timestamp ) if err != nil { log.Fatal(err) } _ = certVerifier } ``` -------------------------------- ### Get RFC 3161 Signed Timestamp Source: https://context7.com/sigstore/sigstore-go/llms.txt Use `sign.NewTimestampAuthority` to contact an RFC 3161 Timestamp Authority and embed a signed timestamp in the bundle. This proves certificate validity at signing time, enabling verification without live log lookups. ```go package main import ( "log" "time" "github.com/sigstore/sigstore-go/pkg/sign" ) func main() { tsa := sign.NewTimestampAuthority(&sign.TimestampAuthorityOptions{ URL: "https://timestamp.githubapp.com/api/v1/timestamp", Timeout: 30 * time.Second, Retries: 2, }) keypair, _ := sign.NewEphemeralKeypair(nil) content := &sign.PlainData{Data: []byte("data to sign")} bundle, err := sign.Bundle(content, keypair, sign.BundleOptions{ TimestampAuthorities: []*sign.TimestampAuthority{tsa}, }) if err != nil { log.Fatal(err) } _ = bundle } ``` -------------------------------- ### Create Verifier with SCT and Transparency Options Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Initializes a verifier with options for Signed Certificate Timestamps (SCT), transparency log entries, and observer timestamps. This ensures a single transparency log entry and performs online verification. ```go sev, err := verify.NewVerifier(trustedMaterial, verify.WithSignedCertificateTimestamps(1), verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1)) if err != nil { panic(err) } ``` -------------------------------- ### Load Bundle and Perform Verification Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Loads a JSON bundle from a specified path and performs verification using the prepared verifier, artifact digest, and certificate identity. The verification is successful if no error is returned. ```go b, err := bundle.LoadJSONFromPath("./examples/bundle-provenance.json") if err != nil { panic(err) } result, err := sev.Verify(b, verify.NewPolicy(verify.WithArtifactDigest("sha512", digest), verify.WithCertificateIdentity(certID))) if err != nil { panic(err) } ``` -------------------------------- ### Sign Content into a Sigstore Bundle Source: https://context7.com/sigstore/sigstore-go/llms.txt Use sign.Bundle to create a Sigstore bundle from content, a keypair, and optional configurations for TSA and Rekor. Ensure a trusted root is fetched for self-verification. ```go package main import ( "encoding/json" "fmt" "log" "time" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/sign" "github.com/sigstore/sigstore-go/pkg/tuf" "google.golang.org/protobuf/encoding/protojson" ) func main() { // 1. Create an ephemeral ECDSA P-256 keypair (default) keypair, err := sign.NewEphemeralKeypair(nil) if err != nil { log.Fatal(err) } // 2. Define content to sign (plain bytes) content := &sign.PlainData{Data: []byte("hello world")} // 3. Fetch trusted root via TUF for bundle self-verification trustedRoot, err := root.FetchTrustedRoot() if err != nil { log.Fatal(err) } // 4. Configure a Timestamp Authority (RFC 3161) tsaOpts := &sign.TimestampAuthorityOptions{ URL: "https://timestamp.githubapp.com/api/v1/timestamp", Timeout: 30 * time.Second, Retries: 1, } // 5. Configure Rekor transparency log (v1) rekorOpts := &sign.RekorOptions{ BaseURL: "https://rekor.sigstore.dev", Timeout: 90 * time.Second, Retries: 1, Version: 1, } // 6. Sign – bundle includes signature, TSA timestamp, and Rekor entry bundle, err := sign.Bundle(content, keypair, sign.BundleOptions{ TimestampAuthorities: []*sign.TimestampAuthority{sign.NewTimestampAuthority(tsaOpts)}, TransparencyLogs: []sign.Transparency{sign.NewRekor(rekorOpts)}, TrustedRoot: trustedRoot, }) if err != nil { log.Fatal(err) } bundleJSON, _ := protojson.Marshal(bundle) fmt.Println(string(bundleJSON)) // To sign an in-toto DSSE attestation instead: dsseContent := &sign.DSSEData{ Data: []byte(`{"_type":"https://in-toto.io/Statement/v0.1"}`), PayloadType: "application/vnd.in-toto+json", } _ = dsseContent // use in place of content above } ``` -------------------------------- ### Run Tests with Makefile Source: https://github.com/sigstore/sigstore-go/blob/main/README.md Invokes tests using the standard Go testing framework via a Makefile helper. ```shell make test ``` -------------------------------- ### sign.Bundle Source: https://context7.com/sigstore/sigstore-go/llms.txt The primary signing entry point. It takes content, a keypair, and optional configurations for Fulcio, Rekor, and a Timestamp Authority to create a Sigstore bundle. ```APIDOC ## sign.Bundle — Sign content into a Sigstore bundle `sign.Bundle` is the primary signing entry point. It takes a `Content` (what to sign), a `Keypair` (how to sign), and `BundleOptions` (optional Fulcio certificate provider, Rekor transparency log, and/or timestamp authority). It returns a `*protobundle.Bundle` ready for serialization. ### Parameters - **content** (`sign.Content`): The data to be signed. Can be `sign.PlainData` or `sign.DSSEData`. - **keypair** (`sign.Keypair`): The signing keypair. - **options** (`sign.BundleOptions`): Optional configurations including `TimestampAuthorities`, `TransparencyLogs`, and `TrustedRoot`. ### Returns - `*protobundle.Bundle`: A Sigstore bundle containing the signature, timestamp, and transparency log entry. - `error`: An error if the signing process fails. ### Example ```go package main import ( "encoding/json" "fmt" "log" "time" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/sign" "github.com/sigstore/sigstore-go/pkg/tuf" "google.golang.org/protobuf/encoding/protojson" ) func main() { // 1. Create an ephemeral ECDSA P-256 keypair (default) keypair, err := sign.NewEphemeralKeypair(nil) if err != nil { log.Fatal(err) } // 2. Define content to sign (plain bytes) content := &sign.PlainData{Data: []byte("hello world")} // 3. Fetch trusted root via TUF for bundle self-verification trustedRoot, err := root.FetchTrustedRoot() if err != nil { log.Fatal(err) } // 4. Configure a Timestamp Authority (RFC 3161) tsaOpts := &sign.TimestampAuthorityOptions{ URL: "https://timestamp.githubapp.com/api/v1/timestamp", Timeout: 30 * time.Second, Retries: 1, } // 5. Configure Rekor transparency log (v1) rekorOpts := &sign.RekorOptions{ BaseURL: "https://rekor.sigstore.dev", Timeout: 90 * time.Second, Retries: 1, Version: 1, } // 6. Sign – bundle includes signature, TSA timestamp, and Rekor entry bundle, err := sign.Bundle(content, keypair, sign.BundleOptions{ TimestampAuthorities: []*sign.TimestampAuthority{sign.NewTimestampAuthority(tsaOpts)}, TransparencyLogs: []sign.Transparency{sign.NewRekor(rekorOpts)}, TrustedRoot: trustedRoot, }) if err != nil { log.Fatal(err) } bundleJSON, _ := protojson.Marshal(bundle) fmt.Println(string(bundleJSON)) // To sign an in-toto DSSE attestation instead: dsseContent := &sign.DSSEData{ Data: []byte(`{\"_type\":\"https://in-toto.io/Statement/v0.1\"}`), PayloadType: "application/vnd.in-toto+json", } _ = dsseContent // use in place of content above } ``` ``` -------------------------------- ### Prepare Certificate Identity for Verification Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Creates a short certificate identity for verification. Use `WithoutIdentitiesUnsafe` if you understand the implications of not verifying against a specific identity. For key-signed bundles, use `WithKey` instead. ```go certID, err := verify.NewShortCertificateIdentity("https://token.actions.githubusercontent.com", "", "", "^https://github.com/sigstore/sigstore-js/") if err != nil { panic(err) } ``` -------------------------------- ### Configure Artifact Verification Policy with NewPolicy Source: https://context7.com/sigstore/sigstore-go/llms.txt Use `verify.NewPolicy` to create a verification policy by combining artifact verification options (digest, file, skip) and identity verification options (certificate identity, key, skip). Multiple identities can be OR-ed together. ```go package main import ( "encoding/hex" "log" "os" "github.com/sigstore/sigstore-go/pkg/verify" ) func main() { // Policy 1: verify artifact by digest + certificate identity digest, _ := hex.DecodeString("abcdef1234567890") certID, _ := verify.NewShortCertificateIdentity("https://accounts.google.com", "", "user@example.com", "") policy1 := verify.NewPolicy( verify.WithArtifactDigest("sha256", digest), verify.WithCertificateIdentity(certID), ) // Policy 2: verify artifact file + multiple allowed identities f, err := os.Open("my-artifact.bin") if err != nil { log.Fatal(err) } defer f.Close() certID2, _ := verify.NewShortCertificateIdentity("https://token.actions.githubusercontent.com", "", "", "^https://github.com/myorg/") policy2 := verify.NewPolicy( verify.WithArtifact(f), verify.WithCertificateIdentity(certID), // first allowed identity verify.WithCertificateIdentity(certID2), // second allowed identity (OR semantics) ) // Policy 3: verify bundle signed with a long-lived key (no certificate) policy3 := verify.NewPolicy( verify.WithArtifactDigest("sha256", digest), verify.WithKey(), // require key-based signing, not certificate ) // Policy 4: DSSE envelope – skip artifact check (envelope is self-describing) policy4 := verify.NewPolicy( verify.WithoutArtifactUnsafe(), // only valid for DSSE bundles verify.WithCertificateIdentity(certID), ) _, _, _, _ = policy1, policy2, policy3, policy4 } ``` -------------------------------- ### Load Trusted Root with Go API Source: https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md Loads the trusted root from the Sigstore TUF repository. Ensure the client is initialized with default options. ```go opts := tuf.DefaultOptions() client, err := tuf.New(opts) if err != nil { panic(err) } trustedMaterial, err := root.GetTrustedRoot(client) if err != nil { panic(err) } ``` -------------------------------- ### Signing Service Discovery Source: https://context7.com/sigstore/sigstore-go/llms.txt Explains how to fetch the signing configuration and select appropriate service endpoints for Fulcio, Rekor, and TSA. ```APIDOC ## `root.FetchSigningConfig` / `root.SelectService` — Discover signing service endpoints `FetchSigningConfig` retrieves the `signing_config.v0.2.json` from TUF, which lists available Fulcio, Rekor, and TSA service endpoints with their API versions and validity periods. `SelectService` picks the best matching endpoint for the desired API version. ### Usage ```go package main import ( "fmt" "log" "time" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/sign" ) func main() { sc, err := root.FetchSigningConfig() if err != nil { log.Fatal(err) } // Select the best Fulcio endpoint for API v1 fulcioService, err := root.SelectService(sc.FulcioCertificateAuthorityURLs(), sign.FulcioAPIVersions, time.Now()) if err != nil { log.Fatal(err) } fmt.Printf("Fulcio URL: %s (API v%d)\n", fulcioService.URL, fulcioService.MajorAPIVersion) // Select all available Rekor endpoints (API v1 or v2) rekorServices, err := root.SelectServices( sc.RekorLogURLs(), sc.RekorLogURLsConfig(), sign.RekorAPIVersions, // []uint32{1, 2} time.Now(), ) if err != nil { log.Fatal(err) } for _, svc := range rekorServices { fmt.Printf("Rekor URL: %s (API v%d, operator: %s)\n", svc.URL, svc.MajorAPIVersion, svc.Operator) } // Select TSA endpoints tsaServices, err := root.SelectServices( sc.TimestampAuthorityURLs(), sc.TimestampAuthorityURLsConfig(), sign.TimestampAuthorityAPIVersions, time.Now(), ) if err != nil { log.Fatal(err) } for _, svc := range tsaServices { fmt.Printf("TSA URL: %s\n", svc.URL) } } ``` ```