## 1. Project Overview & Quickstart (sigstore/cosign_download_attestation)

# Technical Documentation: sigstore/cosign_download_attestation

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/sigstore/cosign_download_attestation)

# cosign_download_attestation

### Agent Skills & Rules
- Discovered 21 agent rule(s) and prompt configurations.



--- METRICS ---
- Files Extracted: 1
- Estimated Token Budget: ~29 tokens
- Canonical Reference: https://codewiki.google/github.com/sigstore/cosign_download_attestation


## 2. Official Technical Reference & Guides (sigstore/docs)

## File: archetypes/docs/lorem/ipsum/index.md

---
title: "Ipsum"
lead: ""
date: 2022-01-25T14:41:39+01:00
lastmod: 2022-01-25T14:41:39+01:00
draft: false
images: []
type: docs
menu:
  {{ .Section }}:
    parent: "lorem"
    identifier: "{{ .Name }}-{{ delimit (shuffle (split (md5 .Name) "" )) "" }}"
weight: 100
toc: true
---

---

## File: archetypes/docs/lorem/_index.md

---
title: "Lorem"
lead: ""
date: 2022-01-25T14:41:21+01:00
lastmod: 2022-01-25T14:41:21+01:00
draft: false
images: []
type: docs
---

---

## File: archetypes/docs/_index.md

---
title: "Docs"
lead: ""
date: 2022-01-25T14:40:56+01:00
lastmod: 2022-01-25T14:40:56+01:00
draft: false
images: []
type: docs
---

---

## File: content/en/logging/CLI.md

---
type: docs
category: Transparency Log
title: CLI
weight: 1825
---

The following guide is targeted towards developers / software maintainers who would like to make a provenance entry into the Rekor transparency log.

The steps outlined below will show how to sign your software and use the Rekor CLI to make and verify an entry. It uses GPG to demonstrate, but other types are outlined in the [Signing and Uploading Other Types]({{< relref "logging/sign-upload">}}) page.

## Prerequisites

You need to have Rekor CLI installed. See the [Installation]({{< relref "logging/installation">}}) page for instructions.

## Sign your release

Before using Rekor, you are required to sign your release. The following example illustrates this using GPG.

You may use either armored or plain binary:

```bash
gpg --armor -u jdoe@example.com --output mysignature.asc --detach-sig myrelease.tar.gz
```

You will also need to export your public key

```bash
gpg --export --armor "jdoe@example.com" > mypublickey.key
```

## Upload an entry to Rekor

The `upload` command sends your public key / signature and artifact URL to the Rekor transparency log.

```bash
rekor-cli upload --rekor_server https://rekor.sigstore.dev --signature <artifact_signature> --public-key <your_public_key> --artifact <url_to_artifact>|<local_path_artifact>
```

The Rekor command will first verify your public key and signature and download a local copy of the artifact. Then it will validate the artifact signing (no access to your private key is required).

If the validations above pass correctly, the entry will be made to Rekor and an entry URL will be returned:

```bash
Created entry at: https://rekor.sigstore.dev/api/v1/log/entries/b08416d417acdb0610d4a030d8f697f9d0a718024681a00fa0b9ba67072a38b5
```

This URL contains the UUID entry / merkle tree hash (in the above case `b08416d417acdb0610d4a030d8f697f9d0a718024681a00fa0b9ba67072a38b5`).

## Verify Proof of Entry

The `verify` command allows you to send a public key / signature and artifact to the Rekor transparency log for verification of entry.

You would typically use this command as a means to verify an 'inclusion proof' showing that your artifact is stored within the transparency log.

```bash
rekor-cli verify --rekor_server <rekor_url> --signature <artifact-signature> --public-key <your_public_key> --artifact <url_to_artifact>|<local_path_artifact>
```

> Note that alternatively you can use a local artifact path with `--artifact`.

## Get Entry

An entry in the log can be retrieved by using the `get` command with either the log index or the artifact UUID:

```bash
rekor-cli get --rekor_server https://rekor.sigstore.dev --log-index <log-index>
```

```bash
rekor-cli get --rekor_server https://rekor.sigstore.dev --uuid <uuid>
```

## Log Info

The `loginfo` command retrieves the public key of the transparency log (unless already declared within the client `~/.rekor/rekor.yaml`) and then uses this public key to verify the signature on the signed tree head.

```bash
rekor-cli loginfo --rekor_server https://rekor.sigstore.dev
```

## Search

If running a redis instance within Rekor, the `search` command performs a redis lookup using a file or a public key.

This command requires one of an artifact, a public key, or a SHA hash (should be prefixed by `sha256:`).

```bash
rekor-cli search --rekor_server https://rekor.sigstore.dev --[artifact|public-key|sha]
```

For example:

```bash
rekor-cli search --rekor_server https://rekor.sigstore.dev --sha sha256:e2e90d1a25f90a3156a27f00f3a4179578e3132ed4f010dc3498d09175b6071a
```

---

## File: content/en/logging/event_stream.md

---
type: docs
category: Transparency Log
menuTitle: Event Stream
title: Using the Rekor Event Stream
weight: 1850
---

The public Rekor instance provides an event stream of new entries added to the transparency log using GCP Pub/Sub. This can be used to monitor the log in real-time for events you are interested in.

## Pub/Sub details

> **Important:** Pub/Sub usage is not free. Please familiarize yourself with the [pricing](https://cloud.google.com/pubsub/pricing) before proceeding.

> **Tip:** You can avoid paying egress network costs by placing the workload that processes events from the subscription in the same region as the topic.

The details needed to subscribe to the topic are below. Any authenticated GCP principal can create subscriptions to the topic.

| Item                 | Value           |
|----------------------|-----------------|
| GCP Project ID       | `project-rekor` |
| Pub/Sub Topic ID     | `new-entry`     |
| Pub/Sub Topic Region | `us-central1`   |

## Event format

The events are published in both the [JSON](https://github.com/cloudevents/spec/blob/main/cloudevents/formats/json-format.md) and [Protobuf](https://github.com/cloudevents/spec/blob/main/cloudevents/formats/protobuf-format.md) formats of the CloudEvents specificaion. The `data` field is always a serialized [`TransparencyLogEntry`](https://github.com/sigstore/protobuf-specs/blob/b46b842040854ceab8f3a42547ae6e991793d0ef/protos/sigstore_rekor.proto#L92) proto message. For JSON formatted events, this follows the JSON serialization [specification](https://protobuf.dev/programming-guides/proto3/#json) for Protobufs.

All published events have attributes attached to them. Attributes that are custom to Rekor and not a part of the CloudEvents specification are prefixed by `rekor_`. You can add [server-side filters](https://cloud.google.com/pubsub/docs/subscription-message-filter) based on these attributes to automatically acknowledge messages you are not interested in to reduce costs.

| Attribute                | Value                                                                   |
|--------------------------|-------------------------------------------------------------------------|
| `datacontenttype`        | `application/json` or `application/protobuf`                            |
| `id`                     | The unique identifier for the entry in the Rekor log.                   |
| `rekor_entry_kind`       | The kind of the Rekor entry (`hashedrekord`, `intoto`, etc.)            |
| `rekor_signing_subjects` | A sorted, comma-delimeted list of the principals that signed the entry. |
| `source`                 | `/createLogEntry`                                                       |
| `specversion`            | `1.0`                                                                   |
| `time`                   | The timestamp the entry was added to the log.                           |
| `type`                   | `dev.sigstore.rekor.events.v1.NewEntry`                                 |

## Example usage

In this example scenario, we want to monitor all log entries added by GitHub Actions CI workers in the Sigstore GitHub org. We do this to verify that all CI runs that upload entries to Rekor are from the `main` branch only. Uploads from other branches could indicate a GitHub Actions misconfiguration that allowed a malicious actor to submit a pull request which triggered a CI run that allowed them to sign their artifacts using our identity.

### Setting up the subscription

> **Note:** To perform the steps below, you will need the [gcloud CLI](https://cloud.google.com/sdk/docs/install).

First, define some environment variables. You may pick any value you like for `SUBSCRIPTION_PROJECT_ID` and `SUBSCRIPTION_ID`. The value for `SUBSCRIPTION_PROJECT_ID` must be globally unique among all GCP projects. 

```sh
export SUBSCRIPTION_PROJECT_ID="your-gcp-project-id"
export SUBSCRIPTION_ID="new-entry-subscription"
export SUBSCRIPTION_CONTENT_TYPE="application/protobuf"
```

If the project does not exist, you can create it with the command below.

```sh
gcloud projects create $SUBSCRIPTION_PROJECT_ID
```

Then, you can create the subscription, filtering on the content type and the signing subjects we want to receive messages about.

```sh
export SUBSCRIPTION_FILTER='attributes.datacontenttype = "$SUBSCRIPTION_CONTENT_TYPE" AND hasPrefix(attributes.rekor_signing_subjects, "https://github.com/sigstore/")'
```

```sh
gcloud pubsub subscriptions create \
    $SUBSCRIPTION_ID \
    --project $SUBSCRIPTION_PROJECT_ID \
    --topic new-entry \
    --topic-project project-rekor \
    --message-filter $SUBSCRIPTION_FILTER
```

The subscription is now set up and we can pull the events 

### Processing log entries

The first step is to create a program that pulls all messages from the subscription indefinitely. It passes all received messages to a `handleMsg` function. The code examples below omit imports from Go's standard library for brevity.

```go
import (
	"cloud.google.com/go/pubsub"
)

func main() {
	ctx, done := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
	defer done()

	// Bootstrap the PubSub client.
	client, err := pubsub.NewClient(ctx, os.Getenv("SUBSCRIPTION_PROJECT_ID"))
	if err != nil {
		log.Fatal(err)
	}
	sub := client.Subscription(os.Getenv("SUBSCRIPTION_ID"))

	// Continuously read messages into a channel.
	msgs := make(chan *pubsub.Message)
	go func() {
		for {
			err := sub.Receive(ctx, func(_ context.Context, msg *pubsub.Message) {
				msgs <- msg
			})
			if err != nil {
				log.Print(err)
			}
		}
	}()

	// Handle each message received until the process is terminated.
	for {
		select {
		case msg := <-msgs:
			if err := handleMsg(msg); err != nil {
				log.Print(err)
			}
			msg.Ack()
		case <-ctx.Done():
			return
		}
	}
}
```

The `handleMsg` function deserializes the event and then checks the signing subjects.

```go
import (
	"google.golang.org/protobuf/proto"
	eventspb "github.com/sigstore/protobuf-specs/gen/pb-go/events/v1"
)

func handleMsg(msg *pubsub.Message) error {
	event := new(eventspb.CloudEvent)
	if err := proto.Unmarshal(msg.Data, event); err != nil {
		return fmt.Errorf("unmarshal msg %q: %w", msg.ID, err)
	}

	// In a real implementation, you should verify the entry before proceeding!

	attr, ok := event.Attributes["rekor_signing_subjects"]
	if !ok {
		return fmt.Errorf("entry %q is missing rekor_signing_subjects", event.GetId())
	}
	subjects := strings.Split(attr.GetCeString(), ",")
	for _, subject := range subjects {
		if !strings.HasSuffix(subject, "@refs/heads/main") {
			return fmt.Errorf("entry %q was not run from the main branch: %s", event.GetId(), subject)
		}
	}

	return nil
}
```

---

## File: content/en/logging/installation.md

---
type: docs
category: Transparency Log
title: Installation
weight: 1805
---

There are several ways to install both the `rekor-cli` and `rekor-server`.

## Using Go install

If you have [Go](https://go.dev/doc/install) installed, you can use Go to retrieve the `rekor-cli` binaries

```bash
go install -v github.com/sigstore/rekor/cmd/rekor-cli@latest
```

You may also do the same for `rekor-server`, but **please note** that the Rekor server also requires Trillian and a database. (see below for setup instructions).

```bash
go install -v github.com/sigstore/rekor/cmd/rekor-server@latest
```

## From the release page

Rekor releases are available on the [Release page](https://github.com/sigstore/rekor/releases).

Releases are available for both `rekor-server` and `rekor-cli`.

Review [Verifying Binaries]({{< relref "logging/verify-release">}}) for details on how to verify Rekor release binaries.

## Build Rekor CLI manually

```bash
git clone https://github.com/sigstore/rekor.git rekor-cli
cd rekor-cli
make rekor-cli
cp rekor-cli /usr/local/bin/
```

## Deploy a Rekor Server manually

There are a few ways you can deploy a Rekor Server:

1. We have a [docker-compose](https://github.com/sigstore/rekor/blob/main/docker-compose.yml) file available.
2. Alternatively, you can build a Rekor server yourself.

Note: The Rekor server manually creates a new Merkle tree (or shard) in the Trillian backend every time it starts up, unless an existing one is specified in via the `--trillian_log_server.tlog_id` flag. If you are building the server yourself and do not need [sharding]({{< relref "logging/sharding">}}) functionality, you can find the existing tree's TreeID by issuing this client command while the server is running:

`CURRENT_TREE_ID=$(rekor-cli loginfo --format json | jq -r .TreeID)`

Then pass in this TreeID at the next server startup to tell Rekor to use the same existing tree:

`rekor-server serve --trillian_log_server.tlog_id=$CURRENT_TREE_ID`

Setting this flag isn't necessary in an environment like `docker-compose`.

### Prerequisites

You will need golang version 1.16 or greater and a `$GOPATH` set.
You will also need a MySQL compatible database and, if you want to perform fast queries, an instance of redis running.
Otherwise you must pass the `--enable_retrieve_api=false` flag when running `rekor-server` in the later steps of this page.

### Get Rekor

Grab the Rekor source:

`go get -u -t -v github.com/sigstore/rekor/cmd/rekor-server`

> Should you prefer, you can also `git clone https://github.com/sigstore/rekor.git`

### Create database and populate tables

Rekor requires a database. We use MariaDB for now (others to be explored later). Install and set up MariaDB on your machine.

```bash
dnf install mariadb mariadb-server
systemctl start mariadb
systemctl enable mariadb
mysql_secure_installation
```

The Rekor directory has a `scripts/createdb.sh` file that will set up a test database (default user: test; default password: zaphod) and populate the needed tables for Trillian. If you’re just trying out Rekor, keep the DB user name and password the same as in the script (test/zaphod). If you change these, you need to make the changes on Trillian’s side (visit the [Trillian repo](https://github.com/google/trillian) for details).

```bash
cd $GOPATH/pkg/mod/github.com/sigstore/rekor@v0.4.0/scripts/
sh createdb.sh
```

### Build Trillian

You also need to build Trillian, an append-only log:

```bash
go get -u -t -v github.com/google/trillian
cd $GOPATH/src/github.com/google/trillian/cmd/trillian_log_server
go build
cp trillian_log_server /usr/local/bin/

cd $GOPATH/src/github.com/google/trillian/cmd/trillian_log_signer
go build
cp trillian_log_signer /usr/local/bin/

cd $GOPATH/src/github.com/google/trillian/cmd/createtree
go build
cp createtree /usr/local/bin/
```

Next, run the Trillian log server:

```bash
trillian_log_server --logtostderr ...
```

Run the signer:

```bash
trillian_log_signer --logtostderr --force_master --rpc_endpoint=localhost:8190 -http_endpoint=localhost:8191  --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms
```

> Note: you can log both to files and to stderr using `--alsologtostderr`

Create the tree:

```bash
createtree --admin_server=localhost:8090
```

#### Build the Rekor Server

With Trillian and MariaDB set up, you can now build the Rekor Server:

```bash
cd $GOPATH/pkg/mod/github.com/sigstore/rekor@v0.4.0/cmd/rekor-server
go build -v -o rekor-server
cp rekor-server /usr/local/bin/
```

#### Start the Rekor Server

```bash
rekor-server serve --enable_retrieve_api=false

2020-09-12T16:32:22.705+0100  INFO  cmd/root.go:87  Using config file: /Users/lukehinds/go/src/github.com/sigstore/rekor-server/rekor-server.yaml
2020-09-12T16:32:22.705+0100  INFO  app/server.go:55  Starting server...
2020-09-12T16:32:22.705+0100  INFO  app/server.go:61  Listening on 127.0.0.1:3000
```

> If you have a redis server running to enable searching your Rekor server, remove the `enable_reprieve_api` flag

#### Next Steps

Congratulations! Your local Rekor server is now running. You can interact with it using the [Rekor CLI]({{< relref "logging/cli">}}).

---

## File: content/en/logging/overview.md

---
type: docs
category: Transparency Log
menuTitle: Overview
title: Rekor
weight: 1800
---



Rekor aims to provide an immutable, tamper-resistant ledger of metadata generated within a software project’s supply chain.

It enables software maintainers and build systems to record signed metadata to an immutable record. Other parties can then query this metadata, enabling them to make informed decisions on trust and non-repudiation of an object’s lifecycle.

The Rekor project provides a restful API-based server for validation, and a transparency log for storage. A CLI application is available to make and verify entries, query the log for inclusion proof, integrity verification of the log or retrieval of entries (either by a public key or an artifact).

Rekor fulfils the signature transparency role of Sigstore’s software signing infrastructure. It can also be run on its own, and it’s designed to be extendable to working with different manifest schemas and PKI tooling.

## Usage and installation

You can download and setup the Rekor Server and Rekor CLI by following the instructions on the [Installation]({{< relref "logging/installation">}}) page.

A public instance of Rekor can be found at [rekor.sigstore.dev](https://rekor.sigstore.dev). The public instance offers an SLO of 99.5% availability and is monitored by an oncall team.

## Auditing the Public Instance

Rekor is built on top of a [verifiable data structure](https://transparency.dev/verifiable-data-structures/). Auditors can monitor the log for consistency, meaning that the log remains append-only and entries are never mutated or removed.
Verifiers can also monitor the log for their identities.
Learn more about transparency logs [here](https://transparency.dev/), and about binary transparency [here](https://binary.transparency.dev/).

There are few options for auditing and monitoring the Rekor log. We've built a monitor that runs on GitHub Actions,
[Rekor monitor](https://github.com/sigstore/rekor-monitor). Follow the instructions to set up a new repository and use the [provided reusable workflow](https://github.com/sigstore/rekor-monitor/blob/main/.github/workflows/reusable_monitoring.yml) to audit the log. You can also monitor the log for specified identities, though this feature is a work in progress and supports a limited set of identities and entry types.

You can also run [omniwitness](https://github.com/transparency-dev/witness/tree/main/cmd/omniwitness) to
audit the log, built by the team who created Trillian, which provides Rekor's verifiable log.

---

## File: content/en/logging/pluggable-types.md

---
type: docs
category: Transparency Log
title: Pluggable Types
weight: 1830
---

Rekor supports pluggable types (aka different schemas) for entries stored in the transparency log. This will allow you to develop your own manifest type in your preferred formatting style (json|yaml|xml).

## Currently supported types

The list of currently supported types and their schema is [maintained in the repository](https://github.com/sigstore/rekor/tree/main/pkg/types#currently-supported-types).

## Base schema

The base schema for all types is modeled off of the schema used by Kubernetes and can be found in `openapi.yaml` as `#/definitions/ProposedEntry`:

```bash
definitions:
  ProposedEntry:
    type: object
    discriminator: kind
    properties:
      kind:
        type: string
    required:
      - kind
```

The `kind` property is a [discriminator](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-13) that is used to differentiate between different pluggable types. Types can have one or more versions of the schema supported concurrently by the same Rekor instance; an example implementation can be seen in `rekord.go`.

## Adding support for a new type

To add a new type (called `newType` in this example):

1. Add a new definition in `openapi.yaml` that is a derived type of ProposedEntry (expressed in the `allOf` list seen below); for example:

    ```yaml
    newType:
      type: object
      description: newType object
      allOf:
        - $ref: "#/definitions/ProposedEntry"
        - properties:
            version:
              type: string
            metadata:
              type: object
              additionalProperties: true
            data:
              type: object
              $ref: "pkg/types/newType/newType_schema.json"
          required:
            - version
            - data
          additionalProperties: false
    ```

    > Note: the `$ref` feature can be used to refer to an externally defined JSON schema document; however it is also permitted to describe the entirety of the type in valid Swagger (aka OpenAPI) v2 format within `openapi.yaml`.

2. Create a subdirectory under `pkg/types/` with your type name (e.g. `newType`) as a new Go package

3. In this new Go package, define a struct that implements the `TypeImpl` interface as defined in `pkg/types/types.go`:

    ```go
    type TypeImpl interface {
      CreateProposedEntry(context.Context, version string, ArtifactProperties) (models.ProposedEntry, error)
        DefaultVersion() string
        SupportedVersions() []string
        IsSupportedVersion(version string) bool
        UnmarshalEntry(pe models.ProposedEntry) (EntryImpl, error)
    }
    ```

    - `CreateProposedEntry` creates an instance of a proposed entry based on the specified API version and the provided artifact properties
    - `DefaultVersion` returns the default API version string across all types (to be used if a caller does not specify an explicit version)
    - `SupportedVersions` returns the list of all API version strings that can currently be inserted into the log.
    - `IsSupportedVersion` returns a boolean denoting whether the specified version could be inserted into the log
    - `UnmarshalEntry` will be called with a pointer to a struct that was automatically generated for the type defined in `openapi.yaml` by the [go-swagger](http://github.com/go-swagger/go-swagger) tool used by Rekor
      - This struct will be defined in the generated file at `pkg/generated/models/newType.go` (where `newType` is replaced with the name of the type you are adding)
      - This method should return a pointer to an instance of a struct that implements the `EntryImpl` interface as defined in `pkg/types/types.go`, or a `nil` pointer with an error specified

    Also, the `Kind` constant must return the _exact_ same string as you named your new type in `openapi.yaml` (e.g. "`newType`")

4. Also in this Go package, provide an implementation of the `EntryImpl` interface as defined in `pkg/types/entries.go`:

    ```go
    type EntryImpl interface {
      APIVersion() string                                 // the supported versions for this implementation
        IndexKeys() ([]string, error)                     // the keys that should be added to the external index for this entry
        Canonicalize(ctx context.Context) ([]byte, error) // marshal the canonical entry to be put into the tlog
        Unmarshal(e models.ProposedEntry) error           // unmarshal the abstract entry into the specific struct for this versioned type
        CreateFromArtifactProperties(context.Context, ArtifactProperties) (models.ProposedEntry, error)
        Verifier() (pki.PublicKey, error)
        Insertable() (bool, error) // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log
    }
    ```

   - `APIVersion` should return a version string that identifies the version of the type supported by the Rekor server
   - `IndexKeys` should return a `[]string` containing the keys that are stored in the search index that should map to this log entry's ID.
   - `Canonicalize` should return a `[]byte` containing the canonicalized contents representing the entry. The canonicalization of contents is important as we should have one record per unique signed object in the transparency log.
   - `Unmarshal` will be called with a pointer to a struct that was automatically generated for the type defined in `openapi.yaml` by the [go-swagger](http://github.com/go-swagger/go-swagger) tool used by Rekor
     - This method should validate the contents of the struct to ensure any string or cross-field dependencies are met to successfully insert an entry of this type into the transparency log
   - `CreateFromArtifactProperties` returns a proposed entry of this specific entry implementation given the provided artifact properties
   - `Verifier` returns the verification material that was used to verify the digital signature
   - `Insertable` introspects the entry and determines if the object is sufficiently hydrated to make a new entry into the log. Entry instances that are created by reading the contents stored in the log may not be sufficiently hydrated.

5. In the Go package you have created for the new type, be sure to add an entry in the `TypeMap` in `github.com/sigstore/rekor/pkg/types` for your new type in the `init` method for your package. The key for the map is the unique string used to define your type in `openapi.yaml` (e.g. `newType`), and the value for the map is the name of a factory function for an instance of `TypeImpl`.

    ```go
    func init() {
        types.TypeMap.Set("newType", NewEntry)
    }
    ```

6. Add an entry to `pluggableTypeMap` in `cmd/server/app/serve.go` that provides a reference to your package. This ensures that the `init` function of your type (and optionally, your version implementation) will be called before the server starts to process incoming requests and therefore will be added to the map that is used to route request processing for different types.

7. After adding sufficient unit & integration tests, submit a pull request to `sigstore/rekor` for review and addition to the codebase.

## Adding a new version of the `Rekord` type

To add new version of the default `Rekord` type:

1. Create a new subdirectory under `pkg/types/rekord/` for the new version

2. If there are changes to the Rekord schema for this version, create a new JSON schema document and add a reference to it within the `oneOf` clause in `rekord_schema.json`. If there are no changes, skip this step.

3. Provide an implementation of the `EntryImpl` interface as defined in `pkg/types/types.go` for the new version.

4. In your package's `init` method, ensure there is a call to `SemVerToFacFnMap.Set()` which provides the link between the valid _semver_ ranges that your package can successfully process and the factory function that creates an instance of a struct for your new version.

5. Add an entry to `pluggableTypeMap` in `cmd/server/app/serve.go` that provides a reference to the Go package implementing the new version. This ensures that the `init` function will be called before the server starts to process incoming requests and therefore will be added to the map that is used to route request processing for different types.

6. After adding sufficient unit & integration tests, submit a pull request to `sigstore/rekor` for review and addition to the codebase.

---

## File: content/en/logging/sharding.md

---
type: docs
category: Transparency Log
title: Sharding
weight: 1820
---

**NOTE**: The suggestions on this page are no longer recommended. This page only covers Rekor v1, aka `rekor.sigstore.dev`.
New Rekor deployments should use [Rekor v2](https://github.com/sigstore/rekor-tiles/) only. We recommend creating
new log instances periodically depending on the growth of the log. Each log instance should be accessible via a unique
URL.

For the public infrastructure, we aim to create a new log every year, publishing the new log's URL in the
[TUF-distributed signing configuration file](https://github.com/sigstore/root-signing/blob/main/targets/signing_config.v0.2.json)
and its key in the [trusted root file](https://github.com/sigstore/root-signing/blob/main/targets/trusted_root.json).

---------------

This document covers what Rekor log sharding is and how to shard the log.

## What is sharding?

When Rekor is started for the first time, its backend is a transparency log built on a single [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree).
This log can grow indefinitely as entries are added, which can present issues over time.
To resolve some of these issues the log can be "sharded" into multiple Merkle Trees.

## Why do we shard the log?

Sharding the log allows for:

* Freezing the current log and rotating signing keys if needed
* Easier and faster querying for entries from the tree
* Easier scaling and platform migrations

## How does this impact user experience?

It shouldn't!
End users shouldn't notice any difference in their experience.
They can still query via UUID, and Rekor will find the correct entry from whichever shard it's in.
Querying by log index works as well, since log indices are distinct and increase across shards.

## More Details

For more details around sharding, see the original [design doc](https://docs.google.com/document/d/1QBTyK-wquplNdeUB5_aqztQHigJOepCvd-4FL4H-zl8/edit?resourcekey=0-grdVbSltkTvpNvhj03laCQ#heading=h.al4txfo7pxwl)!

_Note: You'll need to join the [sigstore-dev@googlegroups.com](https://groups.google.com/g/sigstore-dev/about) Google group for access to the doc._

## How do I shard the Rekor log?

**Sharding the Rekor log will require some downtime in your Rekor service.**
This is necessary because you'll need the length of the current shard later on, so new entries can't be added while sharding is in progress.

Follow these steps to shard the log:

1. Stop all traffic to Rekor so new entries can't be added to the log
2. Store the tree ID and length of the current active shard:

    ```bash
    CURRENT_TREE_ID=$(rekor-cli loginfo --format json | jq -r .TreeID)
    CURRENT_SHARD_LENGTH=$(rekor-cli loginfo --format json | jq -r .ActiveTreeSize)
    ```

3. Connect to the production cluster. Port-forward the running `trillian_logserver` container and run the [createtree](https://github.com/google/trillian/blob/master/cmd/createtree/main.go) script.
This will create a new Merkle Tree which will become the new active shard.

    ```bash
    kubectl port-forward -n trillian-system deploy/trillian-log-server 8090:8090
    # This is the Tree ID of the new active shard
    NEW_TREE_ID=$(createtree --admin_server localhost:8090)
    ```
    > **Note:** Sigstore Helm Charts use port 8091 for gRPC

4. Update the Rekor `sharding-config` ConfigMap with details of the inactive shard:

    ```bash
    kubectl edit configmap sharding-config -n rekor-system
    ```

    Append the following onto the `sharding-config.yaml` key (it will be empty if this is the first shard):

    ```yaml
    - treeID: $CURRENT_TREE_ID
      treeLength: $CURRENT_SHARD_LENGTH
    ```

5. In your rekor-server [Deployment](https://github.com/sigstore/rekor/blob/main/config/rekor.yaml), update the `--trillian_log_server.tlog_id` flag to point to the new Tree ID.

    ```bash
    "--trillian_log_server.tlog_id=$NEW_TREE_ID",
    ```

6. Redeploy Rekor to the cluster with these changes.

7. Restart traffic to your Rekor service.

8. Congratulations, you've successfully sharded the log!

## Identifier Definitions: EntryID, UUID, LogID, Log Index

An **EntryID** is the unique identifier for an artifact in Rekor. It is made up of two parts, the TreeID and UUID:

  `EntryID = TreeID (8 byte hex) + UUID (32 byte hex)`

The **TreeID** refers to the specific trillian tree (also known as log or shard) where the artifact can be found. Rekor uses Trillian to implement each transparency log.

The **UUID** refers to the specific artifact within a specified tree.

The **LogIndex** of an artifact identifies the index or order in which the artifact was entered into a specific tree.

---

## File: content/en/logging/sign-upload.md

---
type: docs
category: Transparency Log
title: Signing and Uploading Other Types
weight: 1835
---

This documentation contains information on how to sign and upload data in different [pluggable types]({{< relref "logging/pluggable-types">}}).

The following are covered:

- [Minisign](#minisign)
- [SSH](#ssh)
- [PKIX/X509](#pkixx509)
- [RPM](#rpm)
- [Alpine](#alpine)
- [RPM](#rpm-1)
- [TSR](#tsr)
- [TUF](#tuf)

## Minisign

Create a keypair with something like:

```console
$ minisign -G
Please enter a password to protect the secret key.

Password:
Password (one more time):
Deriving a key from the password in order to encrypt the secret key... done

The secret key was saved as /Users/dlorenc/.minisign/minisign.key - Keep it secret!
The public key was saved as minisign.pub - That one can be public.

Files signed using this key pair can be verified with the following command:

minisign -Vm <file> -P RWSzQI7+S6M0c4yReOwcDZ2petL8pAZsrNfkdyqr0V7j/HGafpjdKZQm
```

Sign a file:

```console
$ minisign -S -m README.md
Password:
Deriving a key from the password and decrypting the secret key... done
```

Upload to Rekor:

```console
$ rekor-cli upload --artifact README.md --signature README.md.minisig --pki-format=minisign --public-key=minisign.pub
Created entry at index 5895, available at: https://rekor.sigstore.dev/api/v1/log/entries/008bfbbaa8f473a0b17cba5f8078d2c08410bca55f01d2ec71860795ef823b36
```

Look at the entry with:

```console
$ ./rekor-cli get --uuid=008bfbbaa8f473a0b17cba5f8078d2c08410bca55f01d2ec71860795ef823b36
LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 5895
IntegratedTime: 2021-07-14T01:39:50Z
UUID: 008bfbbaa8f473a0b17cba5f8078d2c08410bca55f01d2ec71860795ef823b36
Body: {
  "RekordObj": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "3d80236772ca7c5405e398a4d685e715859260a8733070b86de7322e233c68d2"
      }
    },
    "signature": {
      "content": "dW50cnVzdGVkIGNvbW1lbnQ6ClJXU3pRSTcrUzZNMGMrNUcxbVZzcmw2dmgvYi91VjlxclJySWpxd21abDFKYjZhTGJ2U1NWUzdObDNvUmpVTUdHUWpLVlEyd2JnMnJxNDZxdDdPTHE3L1c3Z2liMlo5Rzh3az0=",
      "format": "minisign",
      "publicKey": {
        "content": "akpGNDdCd05uYWw2MHZ5a0JteXMxK1IzS3F2Ulh1UDhjWnArbU4wcGxDWT0="
      }
    }
  }
}
```

## SSH

Generate a keypair with:

```console
$ ssh-keygen -C test@rekor.dev -t ed25519 -f id_ed25519
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_ed25519.
Your public key has been saved in id_ed25519.pub.
The key fingerprint is:
SHA256:73u0etmm2h7BehcLbjrwXqXe193k5R5Uz0Lnl83nTt4 test@rekor.dev
The key's randomart image is:
+--[ED25519 256]--+
|                 |
|                 |
|              . o|
|           . . ==|
|        S   + +oO|
|        .. o.=.==|
|         oo.B+o=B|
|         .oB=+o+X|
|         .BO=o.oE|
+----[SHA256]-----+
```

Sign a file with:

```console
$ ssh-keygen -Y sign -n file -f id_ed25519 README.md
Enter passphrase:
Signing file README.md
Write signature to README.md.sig
```

Upload it to Rekor with:

```console
$ rekor-cli upload --artifact README.md --signature README.md.sig --pki-format=ssh --public-key=id_ed25519.pub
Created entry at index 5896, available at: https://rekor.sigstore.dev/api/v1/log/entries/0e81b4d9299e2609e45b5c453a4c0e7820ac74e02c4935a8b830d104632fd2d
```

Look at the entry with:

```console
$ rekor-cli get --uuid=0e81b4d9299e2609e45b5c453a4c0e7820ac74e02c4935a8b830d104632fd2d1
LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 5896
IntegratedTime: 2021-07-14T01:45:06Z
UUID: 0e81b4d9299e2609e45b5c453a4c0e7820ac74e02c4935a8b830d104632fd2d1
Body: {
  "RekordObj": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "3d80236772ca7c5405e398a4d685e715859260a8733070b86de7322e233c68d2"
      }
    },
    "signature": {
      "content": "LS0t...",
      "format": "ssh",
      "publicKey": {
        "content": "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUkrc1RWNmxiVVQ2R3pZY2ZUTElKc1FvbDltZTAxOGdNTmc3NHV5T2UrMjUK"
      }
    }
  }
}
```

## PKIX/X509

Generate a keypair with:

```console
$ openssl ecparam -genkey -name prime256v1 > ec_private.pem
$ openssl ec -in ec_private.pem -pubout > ec_public.pem
read EC key
writing EC key
```

Sign the file with:

```console
openssl dgst -sha256 -sign ec_private.pem -out README.md.sig README.md
```

Upload it to Rekor with:

```console
$ ./rekor-cli upload --artifact README.md --signature README.md.sig --pki-format=x509 --public-key=ec_public.pem
Created entry at index 5897, available at: https://rekor.sigstore.dev/api/v1/log/entries/31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
```

View the entry with:

```console
$ rekor-cli get --uuid=31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 5897
IntegratedTime: 2021-07-14T01:49:54Z
UUID: 31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
Body: {
  "RekordObj": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "3d80236772ca7c5405e398a4d685e715859260a8733070b86de7322e233c68d2"
      }
    },
    "signature": {
      "content": "MEUCICwZpVU/3fnWSZkejA8R2j/t5futtl5Co3CDj7k6J6PwAiEA75Cn2txgpg/KjsOitSKsydL3D6cQIf7NQJtsmvsRTRQ=",
      "format": "x509",
      "publicKey": {
        "content": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFYzJKUkJZbS9OQVo5ZHhhUnNWV05mdTcxV3B5TAo2cGx4L1hsZnNVTlM2SmcrWEhEVmpsaVNBNHV2ZEQ4ZW5XdUhNdWQybS9WdEVQaDZYT0M3bjR0aCtnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="
      }
    }
  }
}
```

## RPM

TODO

## Alpine

TODO

## RPM

TODO

## TSR

TODO

## TUF

Generate a TUF repository (for example, with the [Python reference implementation](https://pypi.org/project/tuf/) or [go-tuf](https://github.com/theupdateframework/go-tuf)).

With go-tuf:

```console
tuf init
tuf gen-key root
tuf gen-key targets
tuf gen-key snapshot
tuf gen-key timestamp
tuf add path/to/some/target.txt
tuf snapshot
tuf timestamp
tuf commit
```

You will find the signed metadata in your TUF `repository/` directory:

```console
$ tree .
.
├── keys
│   ├── snapshot.json
│   ├── targets.json
│   └── timestamp.json
├── repository
│   ├── root.json
│   ├── snapshot.json
│   ├── targets
│   │   └── foo
│   │       └── bar
│   │           └── baz.txt
│   ├── targets.json
│   └── timestamp.json
└── staged
```

Upload any TUF manifest to Rekor by using the `root.json` as the public key:

```console
$ ./rekor-cli upload --artifact repository/timestamp.json --type tuf --public-key repository/root.json
Created entry at index 0, available at: https://rekor.sigstore.dev/api/v1/log/entries/6ed8fa5e9f0aa31b6cdfd2cc6877692f5afba52edd7ff5774eebfb22228e8847
```

View the entry with:

```console
$ rekor-cli get --uuid=31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
LogID: 5c4ceffb024e0d0b50bb9e03bc308ce83a76353f1003f8e57a21c51f74cc1e0e
Index: 0
IntegratedTime: 2021-08-13T19:17:33Z
UUID: 6ed8fa5e9f0aa31b6cdfd2cc6877692f5afba52edd7ff5774eebfb22228e8847
Body: {
  "TufObj": {
    "manifest": {
      "expires": "2021-12-18 13:28:12.99008 -0600 CST",
      "signed": {
        "content": [...]
      },
      "version": 1
    },
    "root": {
      "expires": "2021-12-18 13:28:12.99008 -0600 CST",
      "signed": {
        "content": [...]
      },
      "version": 1
    }
  }
}
```

---

## File: content/en/logging/verify-release.md

---
type: docs
category: Transparency Log
title: Verifying Binaries
weight: 1840
---

> 📓 We will refine this process over time to be more streamlined with a higher consensus threshold
> as well as an implementation of a [TUF](https://theupdateframework.io/) style policy. For now this is quite a
> multi step process. We will also deep dive a fair amount here, as its a good opporuntity to pull the covers aside
> and see how this all works.

Rekor releases are currently signed and verified using Fulcio OpenID Connect based on short lived signing certificates.

Rekor release signing artifacts are also stored within the public Rekor instance.

Here we will show you how to verify a release, but also take the opportunity to dig down into Sigstore's signing implementation and process.

## How to verify a release

Head over to the [release page](https://github.com/sigstore/rekor/releases) and select the correct release for your systems architecture. Alongside downloading the main binary, also download the signature and signing certificate from the same release.

For example, with binary `rekor-cli-linux-amd64`, also retrieve `rekor-cli-linux-amd64_cert.pem` and `rekor-cli-linux-amd64_signature.sig`.

* `rekor-cli-linux-amd64`: The binary itself.
* `rekor-cli-linux-amd64_cert.pem`: The signing certificate. This is an X509 certificate generated by the Sigstore root CA, with the email of a project maintainer embedded as a X509v3 Subject Alternative Name. This provides a guarantee that the binary was signed by the individual with access to that account (the email comes from an OpenID provider). In turn, this information is recorded into the transparency log so that the account can be monitored for misuse or compromise.
* `rekor-cli-linux-amd64_signature.sig`: This is the signature generated as a result of the signing event.

### Basic verify

With the above three files, we can now perform a rudimentary verification.

We grab the public key from the signing cert:

```sh
openssl x509 -pubkey -noout -in rekor-cli-linux-amd64_cert.pem > rekor-cli-linux-amd64_cert_public.pem
```

And then we verify:

```sh
$ openssl dgst -sha256 -verify rekor-cli-linux-amd64_cert_public.pem -signature rekor-cli-linux-amd64_signature.sig rekor-cli-linux-amd64
Verified OK
```

### Verify the certificate chain

We should check the trust chain against Sigstore's Root CA.

The root CA for Fulcio is currently:

```bash
-----BEGIN CERTIFICATE-----
MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq
MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx
MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu
ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy
A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas
taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm
MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u
Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx
Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup
Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
-----END CERTIFICATE-----
```

Save this locally to your machine as `fulcio-root.pem`

> 📓 We are looking at leveraging other trust stores for our Root CA, so consider getting the root CA from here, a temporary approach.

Let's now validate the certificate chain:

```sh
$ openssl verify -verbose -no_check_time -CAfile fulcio-root.pem rekor-cli-linux-amd64_cert.pem
rekor-cli-linux-amd64_cert.pem: OK
```

> 📓 We use `-no_check_time` as Fulcio certificates are short-lived (so they always will be expired by design!)

### Verify the signing identity

However, how do we know we can trust that public key is from a maintainer at Sigstore?

Let's look at mapping this to an identity:

```sh
$ openssl x509 -in rekor-cli-linux-amd64_cert.pem -noout -text |grep email
email:ctadeu@gmail.com
```

OK, so we can see that a Fulcio-generated certificate, with a chain to the root certificate has the email identity of a Sigstore maintainer (in this instance, our own release manager the awesome Carlos).

### Verify the entry is in the transparency log

On the [release page](https://github.com/sigstore/rekor/releases) you will see some URLs, these are the Rekor entries of the signing events.

This is the link for the binary and signing materials we have been working with throughout this guide

[https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33](https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33)

Let's dig into this:

```sh
$ curl -X GET "https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33"  | jq

{
  "b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33": {
    "attestation": {},
    "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJzcGVjIjp7ImRhdGEiOnsiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImNlOWE3YzgyZjMyMTk0OTk1ODg4NzU4Y2YxMDdlZjBjYzUyZTBiOGNkY2U3M2I0MjQwNjU4ZWU5ZTczNzgzY2IifX0sInNpZ25hdHVyZSI6eyJjb250ZW50IjoiTUdVQ01EM29LemdzR25QQWtKRVhlZ0RJc2RsaDRCRkNRYk02am5nNFN5M2F4WS8rMnRsSzk3b2UvQ2t4YWJUMVpYVXFDQUl4QUpEcSt6TGZSWlpFSkQ1RHZhS2hGRXUrSm0rakQ0VVhjM0NhWnAyTVNhamlyYWxtdGFsQTZmU0dDWGp3R2ZVek93PT0iLCJmb3JtYXQiOiJ4NTA5IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VOcmFrTkRRV2hwWjBGM1NVSkJaMGxWUVUwckswZFlSRk41YlVOUFNXODJZbXhNTUc1RVpuZ3hiMjFuZDBObldVbExiMXBKZW1vd1JVRjNUWGNLUzJwRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5Va1YzUkhkWlJGWlJVVVJGZDJoNllWZGtlbVJIT1hsYVZFRmxSbmN3ZVFwTlZFRXpUV3BuZDA5RVRUTk9SRXBoUm5jd2VVMVVRVE5OYW1kM1QwUlZNMDVFUm1GTlFVRjNaR3BCVVVKblkzRm9hMnBQVUZGSlFrSm5WWEpuVVZGQkNrbG5UbWxCUVZKak1ETXJVVTR2VEhCck9HcHFVRlF3VG1WNWEwMXVjbTltTW5wWlVrSnhObTA1ZWk5VE1YaFJTemR1Wm5aaFUzZ3JSalVyVEV0d04zZ0tSMkV4YkhZMlNXTnZSWGR3VUhBMk1VZHNZbmQ1UzBWUVZXSkxkekpyWW5KeVJWcFBNbmhLVjNreGIwVkVVSEJZTWxKcWNUQllTMFJaY0VGNVppOW1Rd295WnpKalNuVnRhbWRuUlc1TlNVbENTWHBCVDBKblRsWklVVGhDUVdZNFJVSkJUVU5DTkVGM1JYZFpSRlpTTUd4Q1FYZDNRMmRaU1V0M1dVSkNVVlZJQ2tGM1RYZEVRVmxFVmxJd1ZFRlJTQzlDUVVsM1FVUkJaRUpuVGxaSVVUUkZSbWRSVlRSQlVEaHRUa0k0ZWpoU1pGSnlUVlZMWjFBMk1tMHhVRkVyZDNjS1NIZFpSRlpTTUdwQ1FtZDNSbTlCVlhsTlZXUkJSVWRoU2tOcmVWVlRWSEpFWVRWTE4xVnZSekFyZDNkbldUQkhRME56UjBGUlZVWkNkMFZDUWtsSFFRcE5TRFIzWmtGWlNVdDNXVUpDVVZWSVRVRkxSMk5IYURCa1NFRTJUSGs1ZDJOdGJESlpXRkpzV1RKRmRGa3lPWFZrUjFaMVpFTXdNazFFVG0xYVZHUnNDazU1TUhkTlJFRjNURlJKZVUxcVkzUlpiVmt6VGxNeGJVNUhXVEZhVkdkM1drUkpOVTVVVVhWak0xSjJZMjFHYmxwVE5XNWlNamx1WWtkV2FHTkhiSG9LVEcxT2RtSlRPV3BaVkUweVdWUkdiRTlVV1hsT1JFcHBUMWRhYWxscVJUQk9hVGxxV1ZNMWFtTnVVWGRJWjFsRVZsSXdVa0ZSU0M5Q1FsRjNSVzlGVVFwWk0xSm9Xa2RXTVZGSFpIUlpWMnh6VEcxT2RtSlVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXZRVVJDYkVGcVJVRTNUVEp3U3poUlVGUnJTR3MxYnpaMENtZG5hbXBaZGpCTFYxQlVhalJLVVRBd1UzUmpSMHhxYTFnM1NVMWlOQzlIZFhwWVJrUTRjelpET0VkM05tcHdNRUZxUVcxWGEySlJPVFZzTXpsblVHUUtSMnBqVWpCU1FVUmFUMGRZYjBOUFFVUndPRTVsU3poQkwyZEtkV2RuUjBaSU5IWllaMmwxT0RKc1FtNU1PRVpTYzA5alBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENnPT0ifX19LCJraW5kIjoicmVrb3JkIn0=",
    "integratedTime": 1627461494,
    "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
    "logIndex": 25579,
    "verification": {
      "inclusionProof": {
        "hashes": [
          "779627efafc2601b0b5c4755d1aa27eb3cf8c1f034960ccc1038b9556b1d78bb",
          "892fffd41824856e3279fb815cdedd28fc76722985e508f6ffdf5af5684f0d84",
          "24259982c90f0e2e8a051c06f4cda83fb7f06c3e47b1307d5bc3e50a625b3dcb",
          "a5d5a5841e65786e0718db2f43d909ff92fbfa19bc90bc3187fc143e7af2eb29",
          "2cba9779511cd8c964ac59e4763ecd5257aa67695b20bfbc957341e326848b60",
          "b269aa60e284ce1f866f5c7abd9da16d8e29bf9ab069c66ce91cfe8d6a852458",
          "8af1c7cd9d0a691984963b643c572c560cee08fe38083e2013763df5131e63b3",
          "e86d56509d6b149df6bf2389e066a4b21516f5a13540b8ef52c790b8ed70efe2",
          "04cfd843e6ee05e78eee3229a1b547a4776a81e651888c09bdbfde866ac38d97",
          "339bd5b9f48f7ecf1116f0b0ec9f9eeb95b84f3d53f27b8081e56facbcd71548",
          "74c9aba66c2704b143e33c3ebc5f12a17be5bda8a8eba055bd471ed57a6fd0b4",
          "43a291f5a7301f1b18bbf76829435251a9189c477aa52633fef3f589e3d47446",
          "73b38c2b7d6eac887dc9f028500b67ede8655f136bc75354f8bfe94515327513",
          "4a33ede5d1c6be306c0362fbee2e9f692522327b4cae78165f810f7dcfaa8dd0"
        ],
        "logIndex": 25579,
        "rootHash": "9ecebec82edb290e54f8b45702b05b94efe1e2a7848d5b5aa2c4bbe188995ca2",
        "treeSize": 27024
      },
      "signedEntryTimestamp": "MEUCIHPlKC5Hh34bdjBrqk++9yuznsFOyolHsoulTTxjM+hGAiEA3MEf6d2zsxFJaiZsGCHIhN8Yvc+NZMmUolIBqUGCps0="
    }
  }
}
```

Let's focus on the body and decode it from base64:

```sh
$ curl -X GET "https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33"  | jq -r '.[].body'| base64 -d | jq -r '.[]'

{
  "data": {
    "hash": {
      "algorithm": "sha256",
      "value": "ce9a7c82f32194995888758cf107ef0cc52e0b8cdce73b4240658ee9e73783cb"
    }
  },
  "signature": {
    "content": "MGUCMD3oKzgsGnPAkJEXegDIsdlh4BFCQbM6jng4Sy3axY/+2tlK97oe/CkxabT1ZXUqCAIxAJDq+zLfRZZEJD5DvaKhFEu+Jm+jD4UXc3CaZp2MSajiralmtalA6fSGCXjwGfUzOw==",
    "format": "x509",
    "publicKey": {
      "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNrakNDQWhpZ0F3SUJBZ0lVQU0rK0dYRFN5bUNPSW82YmxMMG5EZngxb21nd0NnWUlLb1pJemowRUF3TXcKS2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweQpNVEEzTWpnd09ETTNOREphRncweU1UQTNNamd3T0RVM05ERmFNQUF3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBCklnTmlBQVJjMDMrUU4vTHBrOGpqUFQwTmV5a01ucm9mMnpZUkJxNm05ei9TMXhRSzduZnZhU3grRjUrTEtwN3gKR2ExbHY2SWNvRXdwUHA2MUdsYnd5S0VQVWJLdzJrYnJyRVpPMnhKV3kxb0VEUHBYMlJqcTBYS0RZcEF5Zi9mQwoyZzJjSnVtamdnRW5NSUlCSXpBT0JnTlZIUThCQWY4RUJBTUNCNEF3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVICkF3TXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVTRBUDhtTkI4ejhSZFJyTVVLZ1A2Mm0xUFErd3cKSHdZRFZSMGpCQmd3Rm9BVXlNVWRBRUdhSkNreVVTVHJEYTVLN1VvRzArd3dnWTBHQ0NzR0FRVUZCd0VCQklHQQpNSDR3ZkFZSUt3WUJCUVVITUFLR2NHaDBkSEE2THk5d2NtbDJZWFJsWTJFdFkyOXVkR1Z1ZEMwMk1ETm1aVGRsCk55MHdNREF3TFRJeU1qY3RZbVkzTlMxbU5HWTFaVGd3WkRJNU5UUXVjM1J2Y21GblpTNW5iMjluYkdWaGNHbHoKTG1OdmJTOWpZVE0yWVRGbE9UWXlOREppT1daallqRTBOaTlqWVM1amNuUXdIZ1lEVlIwUkFRSC9CQlF3RW9FUQpZM1JoWkdWMVFHZHRZV2xzTG1OdmJUQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqRUE3TTJwSzhRUFRrSGs1bzZ0CmdnampZdjBLV1BUajRKUTAwU3RjR0xqa1g3SU1iNC9HdXpYRkQ4czZDOEd3NmpwMEFqQW1Xa2JROTVsMzlnUGQKR2pjUjBSQURaT0dYb0NPQURwOE5lSzhBL2dKdWdnR0ZINHZYZ2l1ODJsQm5MOEZSc09jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
    }
  }
}
```

Ok, now you can see the digest of the artifact that was signed:

```sh
$ sha256sum rekor-cli-linux-amd64
ce9a7c82f32194995888758cf107ef0cc52e0b8cdce73b4240658ee9e73783cb  rekor-cli-linux-amd64
```

We can then grab the signing certificate:

```sh
echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNrakNDQWhpZ0F3SUJBZ0lVQU0rK0dYRFN5bUNPSW82YmxMMG5EZngxb21nd0NnWUlLb1pJemowRUF3TXcKS2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweQpNVEEzTWpnd09ETTNOREphRncweU1UQTNNamd3T0RVM05ERmFNQUF3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBCklnTmlBQVJjMDMrUU4vTHBrOGpqUFQwTmV5a01ucm9mMnpZUkJxNm05ei9TMXhRSzduZnZhU3grRjUrTEtwN3gKR2ExbHY2SWNvRXdwUHA2MUdsYnd5S0VQVWJLdzJrYnJyRVpPMnhKV3kxb0VEUHBYMlJqcTBYS0RZcEF5Zi9mQwoyZzJjSnVtamdnRW5NSUlCSXpBT0JnTlZIUThCQWY4RUJBTUNCNEF3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVICkF3TXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVTRBUDhtTkI4ejhSZFJyTVVLZ1A2Mm0xUFErd3cKSHdZRFZSMGpCQmd3Rm9BVXlNVWRBRUdhSkNreVVTVHJEYTVLN1VvRzArd3dnWTBHQ0NzR0FRVUZCd0VCQklHQQpNSDR3ZkFZSUt3WUJCUVVITUFLR2NHaDBkSEE2THk5d2NtbDJZWFJsWTJFdFkyOXVkR1Z1ZEMwMk1ETm1aVGRsCk55MHdNREF3TFRJeU1qY3RZbVkzTlMxbU5HWTFaVGd3WkRJNU5UUXVjM1J2Y21GblpTNW5iMjluYkdWaGNHbHoKTG1OdmJTOWpZVE0yWVRGbE9UWXlOREppT1daallqRTBOaTlqWVM1amNuUXdIZ1lEVlIwUkFRSC9CQlF3RW9FUQpZM1JoWkdWMVFHZHRZV2xzTG1OdmJUQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqRUE3TTJwSzhRUFRrSGs1bzZ0CmdnampZdjBLV1BUajRKUTAwU3RjR0xqa1g3SU1iNC9HdXpYRkQ4czZDOEd3NmpwMEFqQW1Xa2JROTVsMzlnUGQKR2pjUjBSQURaT0dYb0NPQURwOE5lSzhBL2dKdWdnR0ZINHZYZ2l1ODJsQm5MOEZSc09jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==| base64 -d > tlog_signing_cert.pem```
```

Which is, of course, the same as our signing certificate:

```sh
diff tlog_signing_cert.pem rekor-cli-linux-amd64_cert.pem 
```

And the signature can also be retrieved:

```sh
echo MGUCMD3oKzgsGnPAkJEXegDIsdlh4BFCQbM6jng4Sy3axY/+2tlK97oe/CkxabT1ZXUqCAIxAJDq+zLfRZZEJD5DvaKhFEu+Jm+jD4UXc3CaZp2MSajiralmtalA6fSGCXjwGfUzOw== | base64 -d > tlog_signing_sig.sig

$ diff tlog_signing_sig.sig rekor-cli-linux-amd64_signature.sig 
```

So we can then do the same verification using just the tlog!

```sh
$ openssl x509 -pubkey -noout -in tlog_signing_cert.pem > tlog_signing_cert_public.pem
$ openssl dgst -sha256 -verify tlog_signing_cert_public.pem -signature tlog_signing_sig.sig rekor-cli-linux-amd64
Verified OK
```

### Summarise

So we now know that the binary you downloaded was signed by the individual in control of the OpenID based account.

In turn, this account has 2FA enabled and is monitored for misuse, since records are transparent within the public Rekor transparency log.

There is a lot more we could do well. Using the sha256 digest you could retrieve the signing materials for a release binary, *even* if you sourced the binary from elsewhere!

---

## File: content/en/language_clients/go.md

---
type: docs
category: Language Clients
title: Go
weight: 10
---

[`sigstore-go`](https://pkg.go.dev/github.com/sigstore/sigstore-go) is the Go language client library for Sigstore.

`sigstore-go` is intended as a minimal dependency library for signing and verifying. It's not intended to replace [Cosign](../../cosign/signing/overview), which provides a CLI with many features for interacting with Sigstore. Over time, `cosign` will use `sigstore-go` for verification.

- Friendly API for integrating Go code with Sigstore
- Smaller dependency tree
- Focuses on newly specified data structures in [sigstore/protobuf-specs](https://github.com/sigstore/protobuf-specs)
- Perfect for simple signing and verififcation tasks

`sigstore-go` is currently in beta.

## Features

- Signing and verification of [Sigstore bundles](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto)
- Verification of raw Sigstore signatures
- Signing and verifying with a Timestamp Authority (TSA)
- Online and offline signing and verifying with Rekor (Artifact Transparency Log)
- Structured verification results including certificate metadata
- TUF support
- Verification support for custom [trusted root](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_trustroot.proto)
- Basic CLI

## Installation

### Main CLI installation

`sigstore-go` requires Go 1.21 or greater. The package is tested with Go 1.23.

To compile/install the CLI, clone [`sigstore-go`](https://github.com/sigstore/sigstore-go) and run.

```console
make install
```

Alternatively, you can use `go run cmd/sigstore-go/main.go` to access the CLI, as show in the [example](#cli-example).

## Example

### CLI example

The following is an example of using the sigstore-go CLI to verify a signature.

```console
go run cmd/sigstore-go/main.go \
  -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 \
  examples/bundle-provenance.json
Verification successful!
{
   "version": 20230823,
   "statement": {
      "_type": "https://in-toto.io/Statement/v0.1",
      "predicateType": "https://slsa.dev/provenance/v0.2",
      "subject": ...
    },
    ...
}
```

### Additional examples

Additional examples are available in the [project documentation](https://github.com/sigstore/sigstore-go#sigstore-go).

- [Signing example](https://github.com/sigstore/sigstore-go/blob/main/docs/signing.md#examples)
- [Verifying example](https://github.com/sigstore/sigstore-go/blob/main/docs/verification.md#verification-using-sigstore-go)
- [OCI image verifying example](https://github.com/sigstore/sigstore-go/blob/main/docs/oci-image-verification.md#example-of-oci-image-verification-using-sigstore-go)