# Example of OCI image verification using `sigstore-go`

This document will walk through using the `sigstore-go` library to verify an OCI image reference.

## Disclaimer

This is an example of how to use the `sigstore-go` library to verify an OCI image reference and is not intended to
replace cosign and/or be reused in production. The `sigstore-go` library is still in development and is subject to change.
The following issue tracks the cosign support of the protobuf bundle format - [#3139](https://github.com/sigstore/cosign/issues/3139).

## Overview

In this example, we'll use the `sigstore-go` library to verify an OCI image reference.
This simple CLI is a wrapper around the Go API with the difference that it constructs a
[Sigstore bundle](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto) from the OCI image
reference metadata as a prerequisite to the verification process.

## Requirements

- Unix-compatible OS
- [Go 1.22](https://go.dev/doc/install)

## Getting started

Clone this repository and navigate to the `examples/oci-image-verification` directory:

```shell
$ go build .
```

## Trusted Root

The verifier allows you to use the Sigstore Public Good TUF root or your own custom [trusted root](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_trustroot.proto) containing the root/intermediate certificates of the Fulcio/TSA/Rekor instances used to sign the bundle, in order to verify common open source bundles or bundles signed by your own private Sigstore instance.

## Verification Process

The image we are going to verify is `ghcr.io/stacklok/minder/server:latest`

```shell
$ ./oci-image-verification --ociImage="ghcr.io/stacklok/minder/server:latest" \
    --tufRootURL="tuf-repo-cdn.sigstore.dev" \
    --expectedSANRegex="^https://github.com/stacklok/minder/" \
    --expectedIssuer="https://token.actions.githubusercontent.com"
```

Upon successful verification, the CLI will print the verification result in JSON format along with a `Verification successful!` message.

Below is an example of the bundle that was constructed for this image(at that point of time) followed by the successful verification result, serialized as JSON:

```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"
            },
            "canonicalizedBody": "[encoded data, 4668 characters]"
         }
      ]
   },
   "messageSignature": {
      "messageDigest": {
         "algorithm": "SHA2_256",
         "digest": "qdPqg5eb+jUi1ZBkwyRz7TusiPYsNrPdJD/v6V3sbaA="
      },
      "signature": "MEQCIGTdfr0o+hAiLLFsNCMGVhFqvi4X6nvWotjfpsSOi8qjAiBih0/EV8XrDg1jbQ5r+dycO4Z/xkHVlh5UFRY8gCfstg=="
   }
}
```

and the verification result:

```json
{
  "mediaType": "application/vnd.dev.sigstore.verificationresult+json;version=0.1",
  "signature": {
    "certificate": {
      "certificateIssuer": "CN=sigstore-intermediate,O=sigstore.dev",
      "subjectAlternativeName": {
        "type": "URI",
        "value": "https://github.com/stacklok/minder/.github/workflows/chart-publish.yml@refs/heads/main"
      },
      "issuer": "https://token.actions.githubusercontent.com",
      "githubWorkflowTrigger": "push",
      "githubWorkflowSHA": "6dc6c6c27184f919ba6ca258e064bd7dd18e9200",
      "githubWorkflowName": "Publish Helm Chart",
      "githubWorkflowRepository": "stacklok/minder",
      "githubWorkflowRef": "refs/heads/main",
      "buildSignerURI": "https://github.com/stacklok/minder/.github/workflows/chart-publish.yml@refs/heads/main",
      "buildSignerDigest": "6dc6c6c27184f919ba6ca258e064bd7dd18e9200",
      "runnerEnvironment": "github-hosted",
      "sourceRepositoryURI": "https://github.com/stacklok/minder",
      "sourceRepositoryDigest": "6dc6c6c27184f919ba6ca258e064bd7dd18e9200",
      "sourceRepositoryRef": "refs/heads/main",
      "sourceRepositoryIdentifier": "624056558",
      "sourceRepositoryOwnerURI": "https://github.com/stacklok",
      "sourceRepositoryOwnerIdentifier": "110237746",
      "buildConfigURI": "https://github.com/stacklok/minder/.github/workflows/chart-publish.yml@refs/heads/main",
      "buildConfigDigest": "6dc6c6c27184f919ba6ca258e064bd7dd18e9200",
      "buildTrigger": "push",
      "runInvocationURI": "https://github.com/stacklok/minder/actions/runs/7024502480/attempts/1",
      "sourceRepositoryVisibilityAtSigning": "public"
    }
  },
  "verifiedTimestamps": [
    {
      "type": "Tlog",
      "uri": "TODO",
      "timestamp": "2023-11-28T23:07:08+02:00"
    }
  ],
  "verifiedIdentity": {
    "subjectAlternativeName": {
      "regexp": "^https://github.com/stacklok/minder/"
    },
    "issuer": "https://token.actions.githubusercontent.com"
  }
}
```

To explore a more advanced/configurable verification process, see the CLI implementation in [`examples/sigstore-go-verification/main.go`](../examples/sigstore-go-verification/main.go).
