Repository: sigstore/cosign
Pull request #2708 (2023-02-10 09:14:26)

Support non-Sigstore TSA requests
This changes the client to instead simply exchange a TSQ for a TSR given a URL to the API. This will mean that for clients using timestamping currently, they will need to update their Cosign calls to use the full path (e.g. tsa.sigstore/api/v1/timestamp)

Fixes https://github.com/sigstore/cosign/issues/2704

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>

<!--
Thanks for opening a pull request! Please do not just delete this text.  The three fields below are mandatory.

Please remember to:
- This PR requires an issue. If it is a new feature, the issue should proceed the PR and will have allowed sufficent time for discussions to take place. Pleases use
issue tags such as "Closes #XYZ" or "Resolves sigstore/repo-name#XYZ".
  [documentation](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)
- ensure your commits are signed-off, as sigstore uses the [DCO](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin) using `git commit -s`, or `git commit -s --amend` if you want to amend already existing commits
- lastly, ensure there are no merge commits!

Thank you :)
-->

#### Summary
<!--
 Explain the **motivation** for making this change. What existing problem does the pull request solve? How can reviewers test this PR?
-->

#### Release Note
<!--
Add a release note for each of the following conditions:

* Config changes (additions, deletions, updates)
* API additions—new endpoint, new response fields, or newly accepted request parameters
* Database changes (any)
* Websocket additions or changes
* Anything noteworthy to an administrator running private sigstore instances (err on the side of over-communicating)
* New features and improvements, including behavioural changes, UI changes and CLI changes
* Bug fixes and fixes of previous known issues
* Deprecation warnings, breaking changes, or compatibility notes

If no release notes are required write NONE. Use past-tense.

-->

#### Documentation
<!--

Does this change require an update to documentation? How will users implement your new feature?

Please reference a PR within https://docs.sigstore.dev

-->

codecov-commenter: # [Codecov](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) Report
> Merging [#2708](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (f5c3816) into [main](https://codecov.io/gh/sigstore/cosign/commit/01bd21df9b45e346585ed83e6b37724763d1d8d4?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (01bd21d) will **increase** coverage by `0.00%`.
> The diff coverage is `21.42%`.

:mega: This organization is not using Codecov’s [GitHub App Integration](https://github.com/apps/codecov). We recommend you install it so Codecov can continue to function properly for your repositories. [Learn more](https://about.codecov.io/blog/codecov-is-updating-its-github-integration/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore)

```diff
@@           Coverage Diff           @@
##             main    #2708   +/-   ##
=======================================
  Coverage   30.15%   30.15%           
=======================================
  Files         146      146           
  Lines        9363     9331   -32     
=======================================
- Hits         2823     2814    -9     
+ Misses       6103     6082   -21     
+ Partials      437      435    -2     
```


| [Impacted Files](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) | Coverage Δ | |
|---|---|---|
| [cmd/cosign/cli/attest/attest.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvYXR0ZXN0L2F0dGVzdC5nbw==) | `0.00% <0.00%> (ø)` | |
| [cmd/cosign/cli/attest/attest\_blob.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvYXR0ZXN0L2F0dGVzdF9ibG9iLmdv) | `30.12% <0.00%> (+0.75%)` | :arrow_up: |
| [cmd/cosign/cli/options/attest.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvb3B0aW9ucy9hdHRlc3QuZ28=) | `0.00% <0.00%> (ø)` | |
| [cmd/cosign/cli/options/attest\_blob.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvb3B0aW9ucy9hdHRlc3RfYmxvYi5nbw==) | `0.00% <0.00%> (ø)` | |
| [cmd/cosign/cli/options/policy.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvb3B0aW9ucy9wb2xpY3kuZ28=) | `0.00% <0.00%> (ø)` | |
| [cmd/cosign/cli/options/sign.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvb3B0aW9ucy9zaWduLmdv) | `0.00% <0.00%> (ø)` | |
| [cmd/cosign/cli/options/signblob.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvb3B0aW9ucy9zaWduYmxvYi5nbw==) | `0.00% <0.00%> (ø)` | |
| [cmd/cosign/cli/policy\_init.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvcG9saWN5X2luaXQuZ28=) | `1.24% <0.00%> (+0.01%)` | :arrow_up: |
| [cmd/cosign/cli/sign/sign.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvc2lnbi9zaWduLmdv) | `15.00% <0.00%> (+0.11%)` | :arrow_up: |
| [cmd/cosign/cli/sign/sign\_blob.go](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-Y21kL2Nvc2lnbi9jbGkvc2lnbi9zaWduX2Jsb2IuZ28=) | `0.00% <0.00%> (ø)` | |
| ... and [5 more](https://codecov.io/gh/sigstore/cosign/pull/2708?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore)

haydentherapper: Will test PR in the morning

Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 919e4900..30d13776 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -50,7 +50,7 @@ jobs:
       uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
 
     - name: Utilize Go Module Cache
-      uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
+      uses: actions/cache@6998d139ddd3e68c71e9e398d8e40b71a2f39812 # v3.2.5
       with:
         path: |
           ~/go/pkg/mod
@@ -67,7 +67,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@8775e868027fa230df8586bdf502bbd9b618a477 # v2.2.3
+      uses: github/codeql-action/init@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
       with:
         languages: ${{ matrix.language }}
 
@@ -75,4 +75,4 @@ jobs:
       run: make cosign
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@8775e868027fa230df8586bdf502bbd9b618a477 # v2.2.3
+      uses: github/codeql-action/analyze@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
diff --git a/.github/workflows/scorecard-action.yml b/.github/workflows/scorecard-action.yml
index 112ac1b0..8d7af558 100644
--- a/.github/workflows/scorecard-action.yml
+++ b/.github/workflows/scorecard-action.yml
@@ -52,6 +52,6 @@ jobs:
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@8775e868027fa230df8586bdf502bbd9b618a477 # v2.2.3
+        uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
         with:
           sarif_file: results.sarif
diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml
index 265748f1..f1cc6d91 100644
--- a/.github/workflows/validate-release.yml
+++ b/.github/workflows/validate-release.yml
@@ -26,14 +26,14 @@ jobs:
   check-signature:
     runs-on: ubuntu-latest
     container:
-      image: gcr.io/projectsigstore/cosign:v2.0.0-rc.1@sha256:12d365ed4ee9bb32ba8a0fd16f6c5eae5229dc50e8d62460312cca0b5b7e0457
+      image: gcr.io/projectsigstore/cosign:v2.0.0-rc.2@sha256:3c62b38a5b7eaa4db90c328d430a705d086792869aece919559ecf381a23a4e8
 
     steps:
       - name: Check Signature
         run: |
-          cosign verify ghcr.io/gythialy/golang-cross:v1.20.0-0@sha256:d50b48a7cf2b90f70e35da6d7419b7b16ed29a10f3175a2c849ef2956d485aae \
+          cosign verify ghcr.io/gythialy/golang-cross:v1.20.1-0@sha256:ca8d8591b77ede34d28b1c73bcaf901552dbea8af9d59bad4d723d18dcfc6cd4 \
           --certificate-oidc-issuer https://token.actions.githubusercontent.com \
-          --certificate-identity "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.20.0-0"
+          --certificate-identity "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.20.1-0"
         env:
           TUF_ROOT: /tmp
 
@@ -43,7 +43,7 @@ jobs:
       - check-signature
 
     container:
-      image: ghcr.io/gythialy/golang-cross:v1.20.0-0@sha256:d50b48a7cf2b90f70e35da6d7419b7b16ed29a10f3175a2c849ef2956d485aae
+      image: ghcr.io/gythialy/golang-cross:v1.20.1-0@sha256:ca8d8591b77ede34d28b1c73bcaf901552dbea8af9d59bad4d723d18dcfc6cd4
 
     permissions: {}
 
diff --git a/.goreleaser.yml b/.goreleaser.yml
index ad299887..52f9d66c 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -5,162 +5,163 @@ env:
   - CGO_ENABLED=1
   - DOCKER_CLI_EXPERIMENTAL=enabled
   - COSIGN_YES=true
+  - COSIGN_EXPERIMENTAL=true
   - LATEST_TAG=,latest
 
 # Prevents parallel builds from stepping on each others toes downloading modules
 before:
   hooks:
-  - go mod tidy
-  - /bin/bash -c 'if [ -n "$(git --no-pager diff --exit-code go.mod go.sum)" ]; then exit 1; fi'
-# if running a release we will generate the images in this step
-# if running in the CI the CI env va is set and we dont run the ko steps
-# this is needed because we are generating files that goreleaser was not aware to push to GH project release
-  - /bin/bash -c 'if [ -z "$CI" ]; then make sign-release-images; fi'
+    - go mod tidy
+    - /bin/bash -c 'if [ -n "$(git --no-pager diff --exit-code go.mod go.sum)" ]; then exit 1; fi'
+    # if running a release we will generate the images in this step
+    # if running in the CI the CI env va is set and we dont run the ko steps
+    # this is needed because we are generating files that goreleaser was not aware to push to GH project release
+    - /bin/bash -c 'if [ -z "$CI" ]; then make sign-release-images; fi'
 
 gomod:
   proxy: true
 
 sboms:
-- artifacts: binary
+  - artifacts: binary
 
 builds:
-- id: linux
-  binary: cosign-linux-{{ .Arch }}
-  no_unique_dist_dir: true
-  main: ./cmd/cosign
-  flags:
-    - -trimpath
-  mod_timestamp: '{{ .CommitTimestamp }}'
-  goos:
-    - linux
-  goarch:
-    - amd64
-    - arm64
-    - arm
-    - s390x
-    - ppc64le
-  goarm:
-    - '7'
-  ldflags:
-    - "{{ .Env.LDFLAGS }}"
-  env:
-    - CGO_ENABLED=0
-
-- id: linux-pivkey-pkcs11key-amd64
-  binary: cosign-linux-pivkey-pkcs11key-amd64
-  no_unique_dist_dir: true
-  main: ./cmd/cosign
-  flags:
-    - -trimpath
-  mod_timestamp: '{{ .CommitTimestamp }}'
-  goos:
-    - linux
-  goarch:
-    - amd64
-  ldflags:
-    - "{{ .Env.LDFLAGS }}"
-  tags:
-    - pivkey
-    - pkcs11key
-  hooks:
-    pre:
-      - apt-get update
-      - apt-get -y install libpcsclite-dev
-  env:
-    - PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/"
-
-- id: darwin-amd64
-  binary: cosign-darwin-amd64
-  no_unique_dist_dir: true
-  env:
-    - CC=o64-clang
-    - CXX=o64-clang++
-  main: ./cmd/cosign
-  flags:
-    - -trimpath
-  mod_timestamp: '{{ .CommitTimestamp }}'
-  goos:
-    - darwin
-  goarch:
-    - amd64
-  ldflags:
-    - "{{ .Env.LDFLAGS }}"
-  tags:
-    - pivkey
-    - pkcs11key
-
-- id: darwin-arm64
-  binary: cosign-darwin-arm64
-  no_unique_dist_dir: true
-  env:
-    - CC=aarch64-apple-darwin21.4-clang
-    - CXX=aarch64-apple-darwin21.4-clang++
-  main: ./cmd/cosign
-  flags:
-    - -trimpath
-  goos:
-    - darwin
-  goarch:
-    - arm64
-  tags:
-    - pivkey
-    - pkcs11key
-  ldflags:
-    - "{{.Env.LDFLAGS}}"
-
-- id: windows-amd64
-  binary: cosign-windows-amd64
-  no_unique_dist_dir: true
-  env:
-    - CC=x86_64-w64-mingw32-gcc
-    - CXX=x86_64-w64-mingw32-g++
-  main: ./cmd/cosign
-  mod_timestamp: '{{ .CommitTimestamp }}'
-  flags:
-    - -trimpath
-  goos:
-    - windows
-  goarch:
-    - amd64
-  ldflags:
-    - -buildmode=exe
-    - "{{ .Env.LDFLAGS }}"
-  tags:
-    - pivkey
-    - pkcs11key
-
-- id: sget
-  binary: sget-{{ .Os }}-{{ .Arch }}
-  no_unique_dist_dir: true
-  mod_timestamp: '{{ .CommitTimestamp }}'
-  main: ./cmd/sget
-  flags:
-    - -trimpath
-  goos:
-    - linux
-    - darwin
-    - windows
-  goarch:
-    - amd64
-    - arm64
-    - arm
-    - s390x
-    - ppc64le
-  goarm:
-    - 7
-  ignore:
-    - goos: windows
-      goarch: arm64
-    - goos: windows
-      goarch: arm
-    - goos: windows
-      goarch: s390x
-    - goos: windows
-      goarch: ppc64le
-  ldflags:
-    - "{{ .Env.LDFLAGS }}"
-  env:
-    - CGO_ENABLED=0
+  - id: linux
+    binary: cosign-linux-{{ .Arch }}
+    no_unique_dist_dir: true
+    main: ./cmd/cosign
+    flags:
+      - -trimpath
+    mod_timestamp: '{{ .CommitTimestamp }}'
+    goos:
+      - linux
+    goarch:
+      - amd64
+      - arm64
+      - arm
+      - s390x
+      - ppc64le
+    goarm:
+      - '7'
+    ldflags:
+      - "{{ .Env.LDFLAGS }}"
+    env:
+      - CGO_ENABLED=0
+
+  - id: linux-pivkey-pkcs11key-amd64
+    binary: cosign-linux-pivkey-pkcs11key-amd64
+    no_unique_dist_dir: true
+    main: ./cmd/cosign
+    flags:
+      - -trimpath
+    mod_timestamp: '{{ .CommitTimestamp }}'
+    goos:
+      - linux
+    goarch:
+      - amd64
+    ldflags:
+      - "{{ .Env.LDFLAGS }}"
+    tags:
+      - pivkey
+      - pkcs11key
+    hooks:
+      pre:
+        - apt-get update
+        - apt-get -y install libpcsclite-dev
+    env:
+      - PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/"
+
+  - id: darwin-amd64
+    binary: cosign-darwin-amd64
+    no_unique_dist_dir: true
+    env:
+      - CC=o64-clang
+      - CXX=o64-clang++
+    main: ./cmd/cosign
+    flags:
+      - -trimpath
+    mod_timestamp: '{{ .CommitTimestamp }}'
+    goos:
+      - darwin
+    goarch:
+      - amd64
+    ldflags:
+      - "{{ .Env.LDFLAGS }}"
+    tags:
+      - pivkey
+      - pkcs11key
+
+  - id: darwin-arm64
+    binary: cosign-darwin-arm64
+    no_unique_dist_dir: true
+    env:
+      - CC=aarch64-apple-darwin21.4-clang
+      - CXX=aarch64-apple-darwin21.4-clang++
+    main: ./cmd/cosign
+    flags:
+      - -trimpath
+    goos:
+      - darwin
+    goarch:
+      - arm64
+    tags:
+      - pivkey
+      - pkcs11key
+    ldflags:
+      - "{{.Env.LDFLAGS}}"
+
+  - id: windows-amd64
+    binary: cosign-windows-amd64
+    no_unique_dist_dir: true
+    env:
+      - CC=x86_64-w64-mingw32-gcc
+      - CXX=x86_64-w64-mingw32-g++
+    main: ./cmd/cosign
+    mod_timestamp: '{{ .CommitTimestamp }}'
+    flags:
+      - -trimpath
+    goos:
+      - windows
+    goarch:
+      - amd64
+    ldflags:
+      - -buildmode=exe
+      - "{{ .Env.LDFLAGS }}"
+    tags:
+      - pivkey
+      - pkcs11key
+
+  - id: sget
+    binary: sget-{{ .Os }}-{{ .Arch }}
+    no_unique_dist_dir: true
+    mod_timestamp: '{{ .CommitTimestamp }}'
+    main: ./cmd/sget
+    flags:
+      - -trimpath
+    goos:
+      - linux
+      - darwin
+      - windows
+    goarch:
+      - amd64
+      - arm64
+      - arm
+      - s390x
+      - ppc64le
+    goarm:
+      - '7'
+    ignore:
+      - goos: windows
+        goarch: arm64
+      - goos: windows
+        goarch: arm
+      - goos: windows
+        goarch: s390x
+      - goos: windows
+        goarch: ppc64le
+    ldflags:
+      - "{{ .Env.LDFLAGS }}"
+    env:
+      - CGO_ENABLED=0
 
 signs:
   - id: cosign
@@ -224,9 +225,9 @@ nfpms:
         type: "symlink"
 
 archives:
-- format: binary
-  name_template: "{{ .Binary }}"
-  allow_different_binary_count: true
+  - format: binary
+    name_template: "{{ .Binary }}"
+    allow_different_binary_count: true
 
 checksum:
   name_template: "{{ .ProjectName }}_checksums.txt"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7735816f..99058c3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,29 @@
+# v2.0.0-rc.2
+_Note: this is a prerelease for Cosign 2.0! Feel free to try it out, but know there are many breaking changes from 1.0 and the prereleases may continue to change._
+
+## Enhancements
+* add generate-key-pair GitHub Enterprise server support (#2676)
+* add in format string for warning (#2699)
+* Support for fetching Fulcio certs with self-managed key (#2532)
+* 2476 predicate type download (#2484)
+* Upgrade to go1.20 (#2689)
+
+## Bug Fixes
+* Fix prompts with Windows line endings (#2674)
+
+## Documentation
+
+* docs(README): verify example failing on latest (#2694)
+
+## Contributors
+* Anish Shah
+* Arthur Lutz
+* Carlos Tadeu Panato Junior
+* Christian Loos
+* Tim Seagren
+* Zack Newman
+* priyawadhwa
+
 # v2.0.0-rc.1
 _Note: this is a prerelease for Cosign 2.0! Feel free to try it out, but know there are many breaking changes from 1.0 and the prereleases may continue to change._
 
diff --git a/KEYLESS.md b/KEYLESS.md
index c0d6461e..5effce04 100644
--- a/KEYLESS.md
+++ b/KEYLESS.md
@@ -1,177 +1,1 @@
-# Keyless Signatures
-
-The full design document for this can be found [here](https://docs.google.com/document/d/1461lQUoVqbhCve7PuKNf-2_NfpjrzBG5tFohuMVTuK4/edit#).
-
-This document explains how the `keyless` signatures work in `cosign`.
-Try it out!
-
-This signature mode relies on the Sigstore Public Good Instance, which is rapidly heading toward a GA release!
-We don't have a date yet, but follow along on the [GitHub project](https://github.com/orgs/sigstore/projects/5).
-
-The following examples use this image:
-
-```shell
-$ IMAGE=gcr.io/dlorenc-vmtest2/demo
-$ IMAGE_DIGEST=$IMAGE@sha256:97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36
-```
-
-## Usage
-
-Keyless signing:
-
-```shell
-$ COSIGN_EXPERIMENTAL=1 cosign sign $IMAGE_DIGEST
-Generating ephemeral keys...
-Retrieving signed certificate...
-Your browser will now be opened to:
-https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&client_id=&redirect_uri=http%3A%2F%2F127.0.0.1%3A5556%2Fauth%2Fgoogle%2Fcallback&response_type=code
-Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig
-```
-
-Keyless verifying:
-
-```shell
-$ COSIGN_EXPERIMENTAL=1 cosign verify $IMAGE
-The following checks were performed on all of these signatures:
-  - The cosign claims were validated
-  - The claims were present in the transparency log
-  - The signatures were integrated into the transparency log when the certificate was valid
-  - The code-signing certificate was verified using trusted certificate authority certificates
-Certificate subject:  dlorenc@google.com
-{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36"},"Type":"cosign container image signature"},"Optional":null}
-```
-
-That's it! No keys!
-The rest of the flags (annotations, claims, tlog, etc.) should all work the same.
-
-## Overview
-
-This uses ephemeral keys and certificates, which are signed automatically by the `fulcio` root CA.
-Signatures are stored in the `rekor` transparency log, which automatically provides an attestation
-as to when the signature was created.
-
-Information on the `fulcio` root CA can be found in the [fulcio repository](https://github.com/sigstore/fulcio).
-
-### Keys
-
-The root CA keys are hard-coded in `cosign` today.
-They can only be changed by recompiling the binary.
-This will be made more configurable in the future.
-
-### OAuth Flows
-
-Cosign supports two OAuth flows today: the standard flow and the device flow.
-
-When there is no terminal attached (non-interactive mode), `cosign` will automatically use the device flow
-where a link is printed to stdout.
-This link must be opened in a browser to complete the flow.
-
-### Identity Tokens
-
-In automated environments, cosign also supports directly using OIDC Identity Tokens from specific issuers.
-These can be supplied on the command line with the `--identity-token` flag.
-The `audiences` field must contain `sigstore`.
-
-`cosign` also has support for detecting some of these automated environments
-and producing an identity token.  Currently this supports Google and GitHub.
-
-#### On GCP
-
-From a GCE VM, you can use the VM's service account identity to sign an image:
-
-```shell
-$ IDENTITY_TOKEN=$(gcloud auth print-identity-token --audiences=sigstore)
-$ cosign sign --identity-token=$IDENTITY_TOKEN $IMAGE_DIGEST
-```
-
-From outside a GCE VM, you can impersonate a GCP IAM service account to sign an image:
-
-```shell
-$ IDENTITY_TOKEN=$(gcloud auth print-identity-token \
-        --audiences=sigstore \
-        --include-email \
-        --impersonate-service-account my-sa@my-project.iam.gserviceaccount.com)
-$ cosign sign --identity-token=$IDENTITY_TOKEN $IMAGE_DIGEST
-```
-
-In order to impersonate an IAM service account, your account must have the
-`roles/iam.serviceAccountTokenCreator` role.
-
-**Note**: On Google Cloud Build, standard identity tokens are not supported through the GCE metadata server.
-`cosign` has a special flow for this case, where you can instruct the Cloud Build service account to impersonate
-another service account.
-To configure this flow:
-
-1. Create a service account to use for signatures (the email address will be present in the certificate subject).
-2. Grant the Cloud Build service account the `roles/iam.serviceAccountTokenCreator` role for this target account.
-3. Set the `GOOGLE_SERVICE_ACCOUNT_NAME` environment variable to the name of the target account in your cloudbuild.yaml
-4. Sign images in GCB, without keys!
-
-### Timestamps
-
-Signature timestamps are checked in the [rekor](https://github.com/sigstore/rekor) transparency log. Rekor's `IntegratedTime` is signed as part of its `signedEntryTimestamp`. Cosign verifies the signature over the timestamp and checks that the signature was created while the certificate was valid.
-
-## Upcoming work
-
-* Root CA hardening: We should use intermediate certs rather than the root, and support chained verification.
-* Root CA configuration: We should allow users to change the roots and add their own.
-* Other timestamps: We should allow for other timestamp attestations, including attached [RFC3161](https://www.ietf.org/rfc/rfc3161.txt) signatures.
-* Probably a lot more: This is very experimental.
-* More OIDC providers: Obvious.
-
-## Public Staging Environment
-
-
-There is a public staging environment that is running Fulcio, Rekor and OIDC issuer.
-
-**NOTE** The staging environment provides no SLO guarantees nor the same protection of the root key material for TUF. This environment is meant for development and testing only, PLEASE do not use for production purposes.
-
-The endpoints are as follows:
-
-* https://fulcio.sigstage.dev
-* https://rekor.sigstage.dev
-* https://oauth2.sigstage.dev/auth
-
-These instances are operated and maintained in the same manner as the public production environment for Sigstore.
-
-### Usage
-
-To use this instance, follow the steps below:
-
-1. `rm -r ~/.sigstore`
-1. `gsutil cp -r gs://tuf-root-staging/root.json .`
-1. `cd tuf-root-staging`
-1. `cosign initialize --mirror=tuf-root-staging --root=root.json`
-1. `COSIGN_EXPERIMENTAL=1 cosign sign --oidc-issuer "https://oauth2.sigstage.dev/auth" --fulcio-url "https://fulcio.sigstage.dev" --rekor-url "https://rekor.sigstage.dev" ${IMAGE_DIGEST}`
-1. `COSIGN_EXPERIMENTAL=1 cosign verify --rekor-url "https://rekor.sigstage.dev" ${IMAGE}`
-
-* Steps 1-4 configures your local environment to use the staging keys and certificates.
-* Step 5 specify the staging environment with flags needed for signing.
-* Step 6 specify the staging environment with flags needed for verifying.
-
-#### Revert back to Production
-
-We need to clear the local TUF root data and re-initialize with the default production TUF root data.
-
-1. `rm -r ~/.sigstore`
-1. `cosign initialize`
-
-## Custom Infrastructure
-
-If you're running your own sigstore services flags are available to set your own endpoint's, e.g
-
-```
- COSIGN_EXPERIMENTAL=1 cosign sign -oidc-issuer "https://oauth2.example.com/auth" \
-                        -fulcio-url "https://fulcio.example.com" \
-                        -rekor-url "https://rekor.example.com"  \
-                        $IMAGE_DIGEST
-
-```
-
-### Custom root Cert
-
-You can override the public good instance root CA using the environment variable `SIGSTORE_ROOT_FILE`, e.g.
-
-```
-export SIGSTORE_ROOT_FILE="/home/jdoe/myrootCA.pem"
-```
+> Note of deprecation: This document has been migrated into [`sigstore/docs`](https://github.com/sigstore/docs/blob/main/content/en/cosign/keyless.md) as part of [documentation migration](https://github.com/sigstore/cosign/issues/822) and PR: https://github.com/sigstore/docs/pull/56. To view the live docs page, go to: https://docs.sigstore.dev/cosign/keyless
diff --git a/Makefile b/Makefile
index 297a8ffd..ec44dd22 100644
--- a/Makefile
+++ b/Makefile
@@ -94,7 +94,7 @@ cross:
 golangci-lint:
 	rm -f $(GOLANGCI_LINT_BIN) || :
 	set -e ;\
-	GOBIN=$(GOLANGCI_LINT_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2 ;\
+	GOBIN=$(GOLANGCI_LINT_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1 ;\
 
 lint: golangci-lint ## Run golangci-lint linter
 	$(GOLANGCI_LINT_BIN) run -n
diff --git a/USAGE.md b/USAGE.md
index a13607f7..e58d1295 100644
--- a/USAGE.md
+++ b/USAGE.md
@@ -138,13 +138,6 @@ $ cosign attach signature --signature file.sig $IMAGE_DIGEST
 Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
 ```
 
-the base64-encoded signature:
-
-```shell
-$ cosign attach signature --signature Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== $IMAGE_DIGEST
-Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig
-```
-
 or, `-` for stdin for chaining from other commands:
 
 ```shell
diff --git a/cmd/cosign/cli/attach.go b/cmd/cosign/cli/attach.go
index 3e86c92c..a9aad9ca 100644
--- a/cmd/cosign/cli/attach.go
+++ b/cmd/cosign/cli/attach.go
@@ -73,7 +73,7 @@ func attachSBOM() *cobra.Command {
 				return err
 			}
 			fmt.Fprintf(os.Stderr, "WARNING: Attaching SBOMs this way does not sign them. If you want to sign them, use 'cosign attest --predicate %s --key <key path>' or 'cosign sign --key <key path> --attachment sbom <image uri>'.\n", o.SBOM)
-			return attach.SBOMCmd(cmd.Context(), o.Registry, o.SBOM, mediaType, args[0])
+			return attach.SBOMCmd(cmd.Context(), o.Registry, o.RegistryExperimental, o.SBOM, mediaType, args[0])
 		},
 	}
 
diff --git a/cmd/cosign/cli/attach/sbom.go b/cmd/cosign/cli/attach/sbom.go
index cf4b660a..df651197 100644
--- a/cmd/cosign/cli/attach/sbom.go
+++ b/cmd/cosign/cli/attach/sbom.go
@@ -20,18 +20,31 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"net/http"
 	"os"
 	"path/filepath"
 
+	"github.com/google/go-containerregistry/pkg/logs"
 	"github.com/google/go-containerregistry/pkg/name"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/google/go-containerregistry/pkg/v1/empty"
+	"github.com/google/go-containerregistry/pkg/v1/mutate"
 	"github.com/google/go-containerregistry/pkg/v1/remote"
-	"github.com/google/go-containerregistry/pkg/v1/types"
+	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
+	ocistatic "github.com/google/go-containerregistry/pkg/v1/static"
+	ocitypes "github.com/google/go-containerregistry/pkg/v1/types"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
+	ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote"
+	"github.com/sigstore/cosign/v2/internal/ui"
 	ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
 	"github.com/sigstore/cosign/v2/pkg/oci/static"
 )
 
-func SBOMCmd(ctx context.Context, regOpts options.RegistryOptions, sbomRef string, sbomType types.MediaType, imageRef string) error {
+func SBOMCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts options.RegistryExperimentalOptions, sbomRef string, sbomType ocitypes.MediaType, imageRef string) error {
+	if regExpOpts.RegistryReferrersMode == options.RegistryReferrersModeOCI11 {
+		return sbomCmdOCIExperimental(ctx, regOpts, sbomRef, sbomType, imageRef)
+	}
+
 	ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...)
 	if err != nil {
 		return err
@@ -52,7 +65,7 @@ func SBOMCmd(ctx context.Context, regOpts options.RegistryOptions, sbomRef strin
 		return err
 	}
 
-	fmt.Fprintf(os.Stderr, "Uploading SBOM file for [%s] to [%s] with mediaType [%s].\n", ref.Name(), dstRef.Name(), sbomType)
+	ui.Infof(ctx, "Uploading SBOM file for [%s] to [%s] with mediaType [%s].\n", ref.Name(), dstRef.Name(), sbomType)
 	img, err := static.NewFile(b, static.WithLayerMediaType(sbomType))
 	if err != nil {
 		return err
@@ -60,6 +73,67 @@ func SBOMCmd(ctx context.Context, regOpts options.RegistryOptions, sbomRef strin
 	return remote.Write(dstRef, img, regOpts.GetRegistryClientOpts(ctx)...)
 }
 
+func sbomCmdOCIExperimental(ctx context.Context, regOpts options.RegistryOptions, sbomRef string, sbomType ocitypes.MediaType, imageRef string) error {
+	var dig name.Digest
+	ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...)
+	if err != nil {
+		return err
+	}
+	if digr, ok := ref.(name.Digest); ok {
+		dig = digr
+	} else {
+		desc, err := remote.Head(ref, regOpts.GetRegistryClientOpts(ctx)...)
+		if err != nil {
+			return err
+		}
+		dig = ref.Context().Digest(desc.Digest.String())
+	}
+
+	artifactType := ociexperimental.ArtifactType("sbom")
+
+	desc, err := remote.Head(dig, regOpts.GetRegistryClientOpts(ctx)...)
+	var terr *transport.Error
+	if errors.As(err, &terr) && terr.StatusCode == http.StatusNotFound {
+		h, err := v1.NewHash(dig.DigestStr())
+		if err != nil {
+			return err
+		}
+		// The subject doesn't exist, attach to it as if it's an empty OCI image.
+		logs.Progress.Println("subject doesn't exist, attaching to empty image")
+		desc = &v1.Descriptor{
+			ArtifactType: artifactType,
+			MediaType:    ocitypes.OCIManifestSchema1,
+			Size:         0,
+			Digest:       h,
+		}
+	} else if err != nil {
+		return err
+	}
+
+	b, err := sbomBytes(sbomRef)
+	if err != nil {
+		return err
+	}
+
+	empty := mutate.MediaType(
+		mutate.ConfigMediaType(empty.Image, ocitypes.MediaType(artifactType)),
+		ocitypes.OCIManifestSchema1)
+	att, err := mutate.AppendLayers(empty, ocistatic.NewLayer(b, sbomType))
+	if err != nil {
+		return err
+	}
+	att = mutate.Subject(att, *desc).(v1.Image)
+	attdig, err := att.Digest()
+	if err != nil {
+		return err
+	}
+	dstRef := ref.Context().Digest(attdig.String())
+
+	fmt.Fprintf(os.Stderr, "Uploading SBOM file for [%s] to [%s] with config.mediaType [%s] layers[0].mediaType [%s].\n",
+		ref.Name(), dstRef.String(), artifactType, sbomType)
+	return remote.Write(dstRef, att, regOpts.GetRegistryClientOpts(ctx)...)
+}
+
 func sbomBytes(sbomRef string) ([]byte, error) {
 	// sbomRef can be "-", a string or a file.
 	switch signatureType(sbomRef) {
diff --git a/cmd/cosign/cli/attach/sig.go b/cmd/cosign/cli/attach/sig.go
index fff14094..1492f7fb 100644
--- a/cmd/cosign/cli/attach/sig.go
+++ b/cmd/cosign/cli/attach/sig.go
@@ -112,14 +112,7 @@ func signatureType(sigRef string) SignatureArgType {
 	switch {
 	case sigRef == "-":
 		return StdinSignature
-	case signatureFileNotExists(sigRef):
-		return RawSignature
 	default:
 		return FileSignature
 	}
 }
-
-func signatureFileNotExists(sigRef string) bool {
-	_, err := os.Stat(sigRef)
-	return os.IsNotExist(err)
-}
diff --git a/cmd/cosign/cli/options/attach.go b/cmd/cosign/cli/options/attach.go
index a0b213f3..4484d500 100644
--- a/cmd/cosign/cli/options/attach.go
+++ b/cmd/cosign/cli/options/attach.go
@@ -39,7 +39,7 @@ func (o *AttachSignatureOptions) AddFlags(cmd *cobra.Command) {
 	o.Registry.AddFlags(cmd)
 
 	cmd.Flags().StringVar(&o.Signature, "signature", "",
-		"the signature, path to the signature, or {-} for stdin")
+		"path to the signature, or {-} for stdin")
 
 	cmd.Flags().StringVar(&o.Payload, "payload", "",
 		"path to the payload covered by the signature (if using another format)")
@@ -47,10 +47,11 @@ func (o *AttachSignatureOptions) AddFlags(cmd *cobra.Command) {
 
 // AttachSBOMOptions is the top level wrapper for the attach sbom command.
 type AttachSBOMOptions struct {
-	SBOM            string
-	SBOMType        string
-	SBOMInputFormat string
-	Registry        RegistryOptions
+	SBOM                 string
+	SBOMType             string
+	SBOMInputFormat      string
+	Registry             RegistryOptions
+	RegistryExperimental RegistryExperimentalOptions
 }
 
 var _ Interface = (*AttachSBOMOptions)(nil)
@@ -58,6 +59,7 @@ var _ Interface = (*AttachSBOMOptions)(nil)
 // AddFlags implements Interface
 func (o *AttachSBOMOptions) AddFlags(cmd *cobra.Command) {
 	o.Registry.AddFlags(cmd)
+	o.RegistryExperimental.AddFlags(cmd)
 
 	cmd.Flags().StringVar(&o.SBOM, "sbom", "",
 		"path to the sbom, or {-} for stdin")
diff --git a/cmd/cosign/cli/options/policy.go b/cmd/cosign/cli/options/policy.go
index 02be0da8..4ecdc9f3 100644
--- a/cmd/cosign/cli/options/policy.go
+++ b/cmd/cosign/cli/options/policy.go
@@ -86,7 +86,7 @@ func (o *PolicySignOptions) AddFlags(cmd *cobra.Command) {
 		"whether or not to upload to the tlog")
 
 	cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
-		"url to the Timestamp RFC3161 server, default none")
+		"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
 
 	o.Registry.AddFlags(cmd)
 	o.Fulcio.AddFlags(cmd)
diff --git a/cmd/cosign/cli/options/registry.go b/cmd/cosign/cli/options/registry.go
index 19846c46..7ffcd498 100644
--- a/cmd/cosign/cli/options/registry.go
+++ b/cmd/cosign/cli/options/registry.go
@@ -17,6 +17,8 @@ package options
 import (
 	"context"
 	"crypto/tls"
+	"errors"
+	"fmt"
 	"io"
 	"net/http"
 
@@ -111,3 +113,47 @@ func (o *RegistryOptions) GetRegistryClientOpts(ctx context.Context) []remote.Op
 	}
 	return opts
 }
+
+type RegistryReferrersMode string
+
+const (
+	RegistryReferrersModeLegacy RegistryReferrersMode = "legacy"
+	RegistryReferrersModeOCI11  RegistryReferrersMode = "oci-1-1"
+)
+
+func (e *RegistryReferrersMode) String() string {
+	return string(*e)
+}
+
+func (e *RegistryReferrersMode) Set(v string) error {
+	switch v {
+	case "legacy":
+		*e = RegistryReferrersMode(v)
+		return nil
+	case "oci-1-1":
+		if !EnableExperimental() {
+			return fmt.Errorf(`in order to use  mode "%s", you must set COSIGN_EXPERIMENTAL=1`, v)
+		}
+		*e = RegistryReferrersMode(v)
+		return nil
+	default:
+		return errors.New(`must be one of "legacy", "oci-1-1"`)
+	}
+}
+
+func (e *RegistryReferrersMode) Type() string {
+	return "registryReferrersMode"
+}
+
+// RegistryExperimentalOptions is the wrapper for the registry experimental options.
+type RegistryExperimentalOptions struct {
+	RegistryReferrersMode RegistryReferrersMode
+}
+
+var _ Interface = (*RegistryExperimentalOptions)(nil)
+
+// AddFlags implements Interface
+func (o *RegistryExperimentalOptions) AddFlags(cmd *cobra.Command) {
+	cmd.Flags().Var(&o.RegistryReferrersMode, "registry-referrers-mode",
+		"mode for fetching references from the registry. allowed: legacy, oci-1-1")
+}
diff --git a/cmd/cosign/cli/options/sign.go b/cmd/cosign/cli/options/sign.go
index eea06d8d..81016c75 100644
--- a/cmd/cosign/cli/options/sign.go
+++ b/cmd/cosign/cli/options/sign.go
@@ -41,7 +41,8 @@ type SignOptions struct {
 	OIDC        OIDCOptions
 	SecurityKey SecurityKeyOptions
 	AnnotationOptions
-	Registry RegistryOptions
+	Registry             RegistryOptions
+	RegistryExperimental RegistryExperimentalOptions
 }
 
 var _ Interface = (*SignOptions)(nil)
@@ -54,6 +55,7 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) {
 	o.SecurityKey.AddFlags(cmd)
 	o.AnnotationOptions.AddFlags(cmd)
 	o.Registry.AddFlags(cmd)
+	o.RegistryExperimental.AddFlags(cmd)
 
 	cmd.Flags().StringVar(&o.Key, "key", "",
 		"path to the private key file, KMS URI or Kubernetes Secret")
@@ -98,7 +100,7 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) {
 		"whether or not to upload to the tlog")
 
 	cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
-		"url to the Timestamp RFC3161 server, default none")
+		"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
 
 	cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false,
 		"issue a code signing certificate from Fulcio, even if a key is provided")
diff --git a/cmd/cosign/cli/options/signblob.go b/cmd/cosign/cli/options/signblob.go
index 654c7ff8..99c1a473 100644
--- a/cmd/cosign/cli/options/signblob.go
+++ b/cmd/cosign/cli/options/signblob.go
@@ -78,7 +78,7 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) {
 		"whether or not to upload to the tlog")
 
 	cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
-		"url to the Timestamp RFC3161 server, default none")
+		"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
 
 	cmd.Flags().StringVar(&o.RFC3161TimestampPath, "rfc3161-timestamp", "",
 		"write the RFC3161 timestamp to a file")
diff --git a/cmd/cosign/cli/policy_init.go b/cmd/cosign/cli/policy_init.go
index 4fde1c4c..ef5a0e31 100644
--- a/cmd/cosign/cli/policy_init.go
+++ b/cmd/cosign/cli/policy_init.go
@@ -38,8 +38,8 @@ import (
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/upload"
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa"
+	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
-	tsaclient "github.com/sigstore/timestamp-authority/pkg/client"
 
 	"github.com/sigstore/cosign/v2/pkg/cosign"
 	cremote "github.com/sigstore/cosign/v2/pkg/cosign/remote"
@@ -268,12 +268,8 @@ func signPolicy() *cobra.Command {
 			}
 
 			if o.TSAServerURL != "" {
-				clientTSA, err := tsaclient.GetTimestampClient(o.TSAServerURL)
-				if err != nil {
-					return fmt.Errorf("failed to create TSA client: %w", err)
-				}
 				// Here we get the response from the timestamped authority server
-				if _, err := tsa.GetTimestampedSignature(signed.Signed, clientTSA); err != nil {
+				if _, err := tsa.GetTimestampedSignature(signed.Signed, client.NewTSAClient(o.TSAServerURL)); err != nil {
 					return err
 				}
 			}
diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go
index 71c3834f..ab7e9053 100644
--- a/cmd/cosign/cli/sign/sign.go
+++ b/cmd/cosign/cli/sign/sign.go
@@ -41,6 +41,7 @@ import (
 	ipayload "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload"
 	irekor "github.com/sigstore/cosign/v2/internal/pkg/cosign/rekor"
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa"
+	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	"github.com/sigstore/cosign/v2/internal/ui"
 	"github.com/sigstore/cosign/v2/pkg/cosign"
 	"github.com/sigstore/cosign/v2/pkg/cosign/pivkey"
@@ -55,7 +56,6 @@ import (
 	"github.com/sigstore/sigstore/pkg/signature"
 	signatureoptions "github.com/sigstore/sigstore/pkg/signature/options"
 	sigPayload "github.com/sigstore/sigstore/pkg/signature/payload"
-	tsaclient "github.com/sigstore/timestamp-authority/pkg/client"
 
 	// Loads OIDC providers
 	_ "github.com/sigstore/cosign/v2/pkg/providers/all"
@@ -158,6 +158,7 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO
 		ErrDone = mutate.ErrSkipChildren
 	}
 	regOpts := signOpts.Registry
+	regExpOpts := signOpts.RegistryExperimental
 	opts, err := regOpts.ClientOpts(ctx)
 	if err != nil {
 		return fmt.Errorf("constructing client options: %w", err)
@@ -182,7 +183,7 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO
 			if err != nil {
 				return fmt.Errorf("accessing image: %w", err)
 			}
-			err = signDigest(ctx, digest, staticPayload, ko, regOpts, annotations, signOpts.Upload, signOpts.OutputSignature, signOpts.OutputCertificate, signOpts.Recursive, signOpts.TlogUpload, dd, sv, se)
+			err = signDigest(ctx, digest, staticPayload, ko, regOpts, regExpOpts, annotations, signOpts.Upload, signOpts.OutputSignature, signOpts.OutputCertificate, signOpts.Recursive, signOpts.TlogUpload, dd, sv, se)
 			if err != nil {
 				return fmt.Errorf("signing digest: %w", err)
 			}
@@ -201,7 +202,7 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO
 				return fmt.Errorf("computing digest: %w", err)
 			}
 			digest := ref.Context().Digest(d.String())
-			err = signDigest(ctx, digest, staticPayload, ko, regOpts, annotations, signOpts.Upload, signOpts.OutputSignature, signOpts.OutputCertificate, signOpts.Recursive, signOpts.TlogUpload, dd, sv, se)
+			err = signDigest(ctx, digest, staticPayload, ko, regOpts, regExpOpts, annotations, signOpts.Upload, signOpts.OutputSignature, signOpts.OutputCertificate, signOpts.Recursive, signOpts.TlogUpload, dd, sv, se)
 			if err != nil {
 				return fmt.Errorf("signing digest: %w", err)
 			}
@@ -215,7 +216,7 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO
 }
 
 func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko options.KeyOpts,
-	regOpts options.RegistryOptions, annotations map[string]interface{}, upload bool, outputSignature, outputCertificate string, recursive bool, tlogUpload bool,
+	regOpts options.RegistryOptions, regExpOpts options.RegistryExperimentalOptions, annotations map[string]interface{}, upload bool, outputSignature, outputCertificate string, recursive bool, tlogUpload bool,
 	dd mutate.DupeDetector, sv *SignerVerifier, se oci.SignedEntity) error {
 	var err error
 	// The payload can be passed to skip generation.
@@ -236,12 +237,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
 	}
 
 	if ko.TSAServerURL != "" {
-		clientTSA, err := tsaclient.GetTimestampClient(ko.TSAServerURL)
-		if err != nil {
-			return fmt.Errorf("failed to create TSA client: %w", err)
-		}
-
-		s = tsa.NewSigner(s, clientTSA)
+		s = tsa.NewSigner(s, client.NewTSAClient(ko.TSAServerURL))
 	}
 	shouldUpload, err := ShouldUploadToTlog(ctx, ko, digest, tlogUpload)
 	if err != nil {
@@ -312,6 +308,11 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
 		ui.Infof(ctx, "Pushing signature to: %s", repo.RepositoryStr())
 	}
 
+	// Publish the signatures associated with this entity (using OCI 1.1+ behavior)
+	if regExpOpts.RegistryReferrersMode == options.RegistryReferrersModeOCI11 {
+		return ociremote.WriteSignaturesExperimentalOCI(digest, newSE, walkOpts...)
+	}
+
 	// Publish the signatures associated with this entity
 	if err := ociremote.WriteSignatures(digest.Repository, newSE, walkOpts...); err != nil {
 		return err
diff --git a/cmd/cosign/cli/sign/sign_blob.go b/cmd/cosign/cli/sign/sign_blob.go
index 6c6e231c..231d808d 100644
--- a/cmd/cosign/cli/sign/sign_blob.go
+++ b/cmd/cosign/cli/sign/sign_blob.go
@@ -25,8 +25,8 @@ import (
 	"path/filepath"
 
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa"
+	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle"
-	tsaclient "github.com/sigstore/timestamp-authority/pkg/client"
 
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
@@ -40,7 +40,6 @@ import (
 func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string, b64 bool, outputSignature string, outputCertificate string, tlogUpload bool) ([]byte, error) {
 	var payload internal.HashReader
 	var err error
-	var rekorBytes []byte
 
 	if payloadPath == "-" {
 		payload = internal.NewHashReader(os.Stdin, sha256.New())
@@ -78,12 +77,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
 			return nil, fmt.Errorf("timestamp output path must be set")
 		}
 
-		clientTSA, err := tsaclient.GetTimestampClient(ko.TSAServerURL)
-		if err != nil {
-			return nil, fmt.Errorf("failed to create TSA client: %w", err)
-		}
-
-		respBytes, err := tsa.GetTimestampedSignature(sig, clientTSA)
+		respBytes, err := tsa.GetTimestampedSignature(sig, client.NewTSAClient(ko.TSAServerURL))
 		if err != nil {
 			return nil, err
 		}
@@ -108,7 +102,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
 		return nil, fmt.Errorf("upload to tlog: %w", err)
 	}
 	if shouldUpload {
-		rekorBytes, err = sv.Bytes(ctx)
+		rekorBytes, err := sv.Bytes(ctx)
 		if err != nil {
 			return nil, err
 		}
@@ -127,7 +121,12 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
 	// if bundle is specified, just do that and ignore the rest
 	if ko.BundlePath != "" {
 		signedPayload.Base64Signature = base64.StdEncoding.EncodeToString(sig)
-		signedPayload.Cert = base64.StdEncoding.EncodeToString(rekorBytes)
+
+		certBytes, err := extractCertificate(ctx, sv)
+		if err != nil {
+			return nil, err
+		}
+		signedPayload.Cert = base64.StdEncoding.EncodeToString(certBytes)
 
 		contents, err := json.Marshal(signedPayload)
 		if err != nil {
@@ -160,16 +159,14 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
 	}
 
 	if outputCertificate != "" {
-		signer, err := sv.Bytes(ctx)
+		certBytes, err := extractCertificate(ctx, sv)
 		if err != nil {
-			return nil, fmt.Errorf("error getting signer: %w", err)
+			return nil, err
 		}
-		cert, err := cryptoutils.UnmarshalCertificatesFromPEM(signer)
-		// signer is a certificate
-		if err == nil && len(cert) == 1 {
-			bts := signer
+		if certBytes != nil {
+			bts := certBytes
 			if b64 {
-				bts = []byte(base64.StdEncoding.EncodeToString(signer))
+				bts = []byte(base64.StdEncoding.EncodeToString(certBytes))
 			}
 			if err := os.WriteFile(outputCertificate, bts, 0600); err != nil {
 				return nil, fmt.Errorf("create certificate file: %w", err)
@@ -180,3 +177,17 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string
 
 	return sig, nil
 }
+
+// Extract an encoded certificate from the SignerVerifier. Returns (nil, nil) if verifier is not a certificate.
+func extractCertificate(ctx context.Context, sv *SignerVerifier) ([]byte, error) {
+	signer, err := sv.Bytes(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("error getting signer: %w", err)
+	}
+	cert, err := cryptoutils.UnmarshalCertificatesFromPEM(signer)
+	// signer is a certificate
+	if err == nil && len(cert) == 1 {
+		return signer, nil
+	}
+	return nil, nil
+}
diff --git a/cmd/cosign/cli/verify/verify.go b/cmd/cosign/cli/verify/verify.go
index db748fd8..73de8b4a 100644
--- a/cmd/cosign/cli/verify/verify.go
+++ b/cmd/cosign/cli/verify/verify.go
@@ -29,11 +29,11 @@ import (
 	"path/filepath"
 
 	"github.com/google/go-containerregistry/pkg/name"
-
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
+	cosignError "github.com/sigstore/cosign/v2/cmd/cosign/errors"
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa"
 	"github.com/sigstore/cosign/v2/pkg/blob"
 	"github.com/sigstore/cosign/v2/pkg/cosign"
@@ -278,7 +278,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
 
 			verified, bundleVerified, err := cosign.VerifyImageSignatures(ctx, ref, co)
 			if err != nil {
-				return err
+				return cosignError.WrapError(err)
 			}
 
 			PrintVerificationHeader(ref.Name(), co, bundleVerified, fulcioVerified)
diff --git a/cmd/cosign/errors/error_wrap.go b/cmd/cosign/errors/error_wrap.go
new file mode 100644
index 00000000..96c4fad6
--- /dev/null
+++ b/cmd/cosign/errors/error_wrap.go
@@ -0,0 +1,44 @@
+//
+// Copyright 2022 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+import (
+	"errors"
+
+	verificationError "github.com/sigstore/cosign/v2/pkg/cosign"
+)
+
+// WrapError takes an error type and depending on the type of error
+// passed, will access it's error message and errorType (and return
+// the associated exitCode) and wrap them in a generic `CosignError`.
+// If no custom error has been found, then it will still return a
+// `CosignError` with an error message, but the `exitCode` will be `1`.
+func WrapError(err error) error {
+	// VerificationError
+	var verificationError *verificationError.VerificationError
+	if errors.As(err, &verificationError) {
+		return &CosignError{
+			Message: verificationError.Error(),
+			Code:    LookupExitCodeForErrorType(verificationError.ErrorType()),
+		}
+	}
+
+	// return default cosign error with error message and default exit code
+	return &CosignError{
+		Message: err.Error(),
+		Code:    1,
+	}
+}
diff --git a/cmd/cosign/errors/errors.go b/cmd/cosign/errors/errors.go
new file mode 100644
index 00000000..d051a628
--- /dev/null
+++ b/cmd/cosign/errors/errors.go
@@ -0,0 +1,40 @@
+//
+// Copyright 2022 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+type CosignError struct {
+	Message string
+	Code    int
+}
+
+func Error(cosignError CosignError) error {
+	return &CosignError{
+		Message: cosignError.Message,
+		Code:    cosignError.Code,
+	}
+}
+
+// Assert that we implement error at build time.
+var _ error = (*CosignError)(nil)
+
+// Error implements error
+func (ce *CosignError) Error() string {
+	return ce.Message
+}
+
+func (ce *CosignError) ExitCode() int {
+	return ce.Code
+}
diff --git a/cmd/cosign/errors/exit_code_lookup.go b/cmd/cosign/errors/exit_code_lookup.go
new file mode 100644
index 00000000..b7d70959
--- /dev/null
+++ b/cmd/cosign/errors/exit_code_lookup.go
@@ -0,0 +1,38 @@
+//
+// Copyright 2022 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+import (
+	verificationError "github.com/sigstore/cosign/v2/pkg/cosign"
+)
+
+// exitCodeLookup contains a map of errorTypes and their associated exitCodes.
+var exitCodeLookup = map[string]int{
+	verificationError.ErrNoMatchingSignaturesType: NoMatchingSignature,
+}
+
+func LookupExitCodeForErrorType(errorType string) int {
+	exitCode := exitCodeLookup[errorType]
+
+	// if there is no entry in the lookup map for the passed errorType,
+	// then by default, it will return `0`. however, as `0` as an exitCode
+	// for success, we want to return `1` instead until there is a valid
+	// exit code entry in the map for the passed errorType.
+	if exitCode == 0 {
+		return 1
+	}
+	return exitCode
+}
diff --git a/cmd/cosign/errors/exit_codes.go b/cmd/cosign/errors/exit_codes.go
new file mode 100644
index 00000000..5454198e
--- /dev/null
+++ b/cmd/cosign/errors/exit_codes.go
@@ -0,0 +1,35 @@
+//
+// Copyright 2022 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+// Exit codes for cosign.
+// To allow for document generation of exit codes the following convention is
+// to be followed.
+// Convention:
+//   | // comment that explains the error
+//   | const NamedConstant = ERRORCODE
+//
+// This is so when `make docgen` is run, the cosign_exit-codes.md doc is automatically
+// generated inside of the docs dir following the format of "Exit Code : Comment".
+
+// Error verifying image due to no signature
+const ImageWithoutSignature = 10
+
+// Error verifying image due to non-existent tag
+const NonExistentTag = 11
+
+// Error verifying image due to no matching signature
+const NoMatchingSignature = 12
diff --git a/cmd/cosign/errors/generate_docs.go b/cmd/cosign/errors/generate_docs.go
new file mode 100644
index 00000000..c174eff3
--- /dev/null
+++ b/cmd/cosign/errors/generate_docs.go
@@ -0,0 +1,106 @@
+//
+// Copyright 2022 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+import (
+	"fmt"
+	"go/ast"
+	godoc "go/doc"
+	"go/parser"
+	"go/token"
+	"os"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// GenerateExitCodeDocs will generate documentation for the exit codes
+// that the cosign application will throw. Inspired by elemental-cli who
+// convieniently solved this problem prior: https://github.com/rancher/elemental-cli/blob/main/docs/generate_docs.go
+// there was no need to change (apart from some file paths) due to it
+// giving us exactly what we want without error.
+func GenerateExitCodeDocs(dir string) error {
+	fset := token.NewFileSet()
+	files := []*ast.File{
+		mustParse(fset, "./cmd/cosign/errors/exit_codes.go"),
+	}
+	p, err := godoc.NewFromFiles(fset, files, "github.com/sigstore/cosign")
+	if err != nil {
+		panic(err)
+	}
+	// nolint prealloc
+	var (
+		exitCodes []*ErrorCode
+		used      map[int]bool
+	)
+
+	used = make(map[int]bool)
+
+	for _, c := range p.Consts {
+		// Cast it, its safe as these are constants
+		v := c.Decl.Specs[0].(*ast.ValueSpec)
+		val := v.Values[0].(*ast.BasicLit)
+		code, _ := strconv.Atoi(val.Value)
+
+		if _, ok := used[code]; ok {
+			return fmt.Errorf("duplicate exit-code found: %v", code)
+		}
+
+		used[code] = true
+		exitCodes = append(exitCodes, &ErrorCode{code: code, doc: c.Doc})
+	}
+
+	sort.Slice(exitCodes, func(i, j int) bool {
+		return exitCodes[i].code < exitCodes[j].code
+	})
+
+	exitCodesFile, err := os.Create(dir + "/cosign_exit_codes.md")
+
+	if err != nil {
+		fmt.Print(err)
+		return err
+	}
+
+	defer func() {
+		_ = exitCodesFile.Close()
+	}()
+
+	_, _ = exitCodesFile.WriteString("# Exit codes for cosign CLI\n\n")
+	_, _ = exitCodesFile.WriteString("> The following exit codes may be subject to change\n\n")
+	_, _ = exitCodesFile.WriteString("| Exit code | Meaning |\n")
+	_, _ = exitCodesFile.WriteString("| :----: | :---- |\n")
+	for _, code := range exitCodes {
+		_, err = exitCodesFile.WriteString(fmt.Sprintf("| %d | %s|\n", code.code, strings.Replace(code.doc, "\n", "", 1)))
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func mustParse(fset *token.FileSet, filename string) *ast.File {
+	f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
+	if err != nil {
+		panic(err)
+	}
+	return f
+}
+
+type ErrorCode struct {
+	code int
+	doc  string
+}
diff --git a/cmd/cosign/main.go b/cmd/cosign/main.go
index 1da9823e..50edaefc 100644
--- a/cmd/cosign/main.go
+++ b/cmd/cosign/main.go
@@ -16,12 +16,14 @@ package main
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"log"
 	"os"
 	"strings"
 
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli"
+	cosignError "github.com/sigstore/cosign/v2/cmd/cosign/errors"
 	"github.com/sigstore/cosign/v2/internal/ui"
 
 	// Register the provider-specific plugins
@@ -60,6 +62,15 @@ func main() {
 	}
 
 	if err := cli.New().Execute(); err != nil {
+		// if the error is a `CosignError` then we want to use the exit code that
+		// is related to the type of error that has occurred.
+		var cosignError *cosignError.CosignError
+		if errors.As(err, &cosignError) {
+			log.Printf("error during command execution: %v", err)
+			os.Exit(cosignError.ExitCode())
+		}
+
+		// we don't call os.Exit as Fatalf does both PrintF and os.Exit(1)
 		log.Fatalf("error during command execution: %v", err)
 	}
 }
diff --git a/cmd/help/main.go b/cmd/help/main.go
index 8eaf38df..197d0c34 100644
--- a/cmd/help/main.go
+++ b/cmd/help/main.go
@@ -19,6 +19,7 @@ import (
 	"os"
 
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli"
+	errors "github.com/sigstore/cosign/v2/cmd/cosign/errors"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra/doc"
 )
@@ -31,6 +32,11 @@ func main() {
 		SilenceUsage: true,
 		Args:         cobra.NoArgs,
 		RunE: func(*cobra.Command, []string) error {
+			err := errors.GenerateExitCodeDocs(dir)
+			if err != nil {
+				fmt.Println(err)
+				os.Exit(1)
+			}
 			return doc.GenMarkdownTree(cli.New(), dir)
 		},
 	}
diff --git a/doc/cosign_attach_sbom.md b/doc/cosign_attach_sbom.md
index 41b5cc56..0fcfce9b 100644
--- a/doc/cosign_attach_sbom.md
+++ b/doc/cosign_attach_sbom.md
@@ -21,6 +21,7 @@ cosign attach sbom [flags]
   -h, --help                                                                                     help for sbom
       --input-format string                                                                      type of sbom input format (json|xml|text)
       --k8s-keychain                                                                             whether to use the kubernetes keychain instead of the default keychain (supports workload identity).
+      --registry-referrers-mode registryReferrersMode                                            mode for fetching references from the registry. allowed: legacy, oci-1-1
       --sbom string                                                                              path to the sbom, or {-} for stdin
       --type string                                                                              type of sbom (spdx|cyclonedx|syft) (default "spdx")
 ```
diff --git a/doc/cosign_attach_signature.md b/doc/cosign_attach_signature.md
index 65b074f2..02ddb753 100644
--- a/doc/cosign_attach_signature.md
+++ b/doc/cosign_attach_signature.md
@@ -21,7 +21,7 @@ cosign attach signature [flags]
   -h, --help                                                                                     help for signature
       --k8s-keychain                                                                             whether to use the kubernetes keychain instead of the default keychain (supports workload identity).
       --payload string                                                                           path to the payload covered by the signature (if using another format)
-      --signature string                                                                         the signature, path to the signature, or {-} for stdin
+      --signature string                                                                         path to the signature, or {-} for stdin
 ```
 
 ### Options inherited from parent commands
diff --git a/doc/cosign_exit_codes.md b/doc/cosign_exit_codes.md
new file mode 100644
index 00000000..5548c663
--- /dev/null
+++ b/doc/cosign_exit_codes.md
@@ -0,0 +1,9 @@
+# Exit codes for cosign CLI
+
+> The following exit codes may be subject to change
+
+| Exit code | Meaning |
+| :----: | :---- |
+| 10 | Error verifying image due to no signature|
+| 11 | Error verifying image due to non-existent tag|
+| 12 | Error verifying image due to no matching signature|
diff --git a/doc/cosign_policy_sign.md b/doc/cosign_policy_sign.md
index 9e1b4d14..1b1ce44c 100644
--- a/doc/cosign_policy_sign.md
+++ b/doc/cosign_policy_sign.md
@@ -32,7 +32,7 @@ cosign policy sign [flags]
       --oidc-redirect-url string                                                                 [EXPERIMENTAL] OIDC redirect URL (Optional). The default oidc-redirect-url is 'http://localhost:0/auth/callback'.
       --out string                                                                               output policy locally (default "o")
       --rekor-url string                                                                         [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev")
-      --timestamp-server-url string                                                              url to the Timestamp RFC3161 server, default none
+      --timestamp-server-url string                                                              url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr
       --tlog-upload                                                                              whether or not to upload to the tlog (default true)
   -y, --yes                                                                                      skip confirmation prompts for non-destructive operations
 ```
diff --git a/doc/cosign_sign-blob.md b/doc/cosign_sign-blob.md
index 6a3b7f09..e889d3f6 100644
--- a/doc/cosign_sign-blob.md
+++ b/doc/cosign_sign-blob.md
@@ -54,7 +54,7 @@ cosign sign-blob [flags]
       --rfc3161-timestamp string         write the RFC3161 timestamp to a file
       --sk                               whether to use a hardware security key
       --slot string                      security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management)
-      --timestamp-server-url string      url to the Timestamp RFC3161 server, default none
+      --timestamp-server-url string      url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr
       --tlog-upload                      whether or not to upload to the tlog (default true)
   -y, --yes                              skip confirmation prompts for non-destructive operations
 ```
diff --git a/doc/cosign_sign.md b/doc/cosign_sign.md
index 11fb0dd2..f1a17d7c 100644
--- a/doc/cosign_sign.md
+++ b/doc/cosign_sign.md
@@ -90,10 +90,11 @@ cosign sign [flags]
       --output-signature string                                                                  write the signature to FILE
       --payload string                                                                           path to a payload file to use rather than generating one
   -r, --recursive                                                                                if a multi-arch image is specified, additionally sign each discrete image
+      --registry-referrers-mode registryReferrersMode                                            mode for fetching references from the registry. allowed: legacy, oci-1-1
       --rekor-url string                                                                         [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev")
       --sk                                                                                       whether to use a hardware security key
       --slot string                                                                              security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management)
-      --timestamp-server-url string                                                              url to the Timestamp RFC3161 server, default none
+      --timestamp-server-url string                                                              url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr
       --tlog-upload                                                                              whether or not to upload to the tlog (default true)
       --upload                                                                                   whether to upload the signature (default true)
   -y, --yes                                                                                      skip confirmation prompts for non-destructive operations
diff --git a/go.mod b/go.mod
index 17f53c07..386258af 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
 	github.com/go-piv/piv-go v1.10.0
 	github.com/google/certificate-transparency-go v1.1.4
 	github.com/google/go-cmp v0.5.9
-	github.com/google/go-containerregistry v0.13.0
+	github.com/google/go-containerregistry v0.13.1-0.20230203223142-b3c23b4c3f28
 	github.com/google/go-github/v50 v50.0.0
 	github.com/in-toto/in-toto-golang v0.6.0
 	github.com/kelseyhightower/envconfig v1.4.0
@@ -38,13 +38,13 @@ require (
 	github.com/theupdateframework/go-tuf v0.5.2
 	github.com/transparency-dev/merkle v0.0.1
 	github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
-	github.com/xanzy/go-gitlab v0.79.1
-	go.step.sm/crypto v0.24.0
+	github.com/xanzy/go-gitlab v0.80.0
+	go.step.sm/crypto v0.25.0
 	golang.org/x/crypto v0.6.0
 	golang.org/x/oauth2 v0.5.0
 	golang.org/x/sync v0.1.0
 	golang.org/x/term v0.5.0
-	google.golang.org/api v0.109.0
+	google.golang.org/api v0.110.0
 	k8s.io/api v0.23.5
 	k8s.io/apimachinery v0.23.5
 	k8s.io/client-go v0.23.5
@@ -53,7 +53,7 @@ require (
 )
 
 require (
-	cloud.google.com/go/compute v1.14.0 // indirect
+	cloud.google.com/go/compute v1.18.0 // indirect
 	cloud.google.com/go/compute/metadata v0.2.3 // indirect
 	cloud.google.com/go/iam v0.8.0 // indirect
 	cloud.google.com/go/kms v1.8.0 // indirect
@@ -106,7 +106,7 @@ require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/blang/semver v3.5.1+incompatible // indirect
 	github.com/cenkalti/backoff/v3 v3.2.2 // indirect
-	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
 	github.com/clbanning/mxj/v2 v2.5.6 // indirect
 	github.com/cockroachdb/apd/v2 v2.0.1 // indirect
@@ -152,7 +152,7 @@ require (
 	github.com/google/tink/go v1.7.0 // indirect
 	github.com/google/trillian v1.5.1-0.20220819043421-0a389c4bb8d9 // indirect
 	github.com/google/uuid v1.3.0 // indirect
-	github.com/googleapis/enterprise-certificate-proxy v0.2.1 // indirect
+	github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
 	github.com/googleapis/gax-go/v2 v2.7.0 // indirect
 	github.com/googleapis/gnostic v0.5.5 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -250,8 +250,8 @@ require (
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.5.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20230109162033-3c3c17ce83e6 // indirect
-	google.golang.org/grpc v1.52.3 // indirect
+	google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc // indirect
+	google.golang.org/grpc v1.53.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
diff --git a/go.sum b/go.sum
index 292e6292..04522e57 100644
--- a/go.sum
+++ b/go.sum
@@ -27,8 +27,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
 cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
 cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0=
-cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
+cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
+cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
 cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
@@ -233,8 +233,9 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21 h1:XlpL9EHrPOBJMLDDOf35/G4t5rGAFNNAZQ3cDcWavtc=
 github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21/go.mod h1:Zlre/PVxuSI9y6/UV4NwGixQ48RHQDSPiUkofr6rbMU=
 github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
@@ -507,8 +508,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8
 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-containerregistry v0.13.0 h1:y1C7Z3e149OJbOPDBxLYR8ITPz8dTKqQwjErKVHJC8k=
-github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo=
+github.com/google/go-containerregistry v0.13.1-0.20230203223142-b3c23b4c3f28 h1:gFDKHwyCxpzgUozSOM8eLCx0V7muSr30QYU2QH+p48E=
+github.com/google/go-containerregistry v0.13.1-0.20230203223142-b3c23b4c3f28/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo=
 github.com/google/go-github/v50 v50.0.0 h1:gdO1AeuSZZK4iYWwVbjni7zg8PIQhp7QfmPunr016Jk=
 github.com/google/go-github/v50 v50.0.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA=
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@@ -542,8 +543,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg=
-github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
+github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
@@ -983,8 +984,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9
 github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
 github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38VVdoroRsT0Z88fmvdYrI2EjzJst35I=
 github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k=
-github.com/xanzy/go-gitlab v0.79.1 h1:ZmEei8RZYlqk4D7nYrWWZqywmKBOd7vmPMlJbueZXUU=
-github.com/xanzy/go-gitlab v0.79.1/go.mod h1:DlByVTSXhPsJMYL6+cm8e8fTJjeBmhrXdC/yvkKKt6M=
+github.com/xanzy/go-gitlab v0.80.0 h1:2d6RwUrI3ZC2Xh9urnqiiHCLzWNndrGtje3yByZubdQ=
+github.com/xanzy/go-gitlab v0.80.0/go.mod h1:DlByVTSXhPsJMYL6+cm8e8fTJjeBmhrXdC/yvkKKt6M=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
@@ -1033,8 +1034,8 @@ go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZ
 go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs=
 go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=
 go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=
-go.step.sm/crypto v0.24.0 h1:9qzl0cQWHvKxajHLyVrJET+dauYzoVB3PVQDLMYs+HE=
-go.step.sm/crypto v0.24.0/go.mod h1:kr1rzO6SzeQnLm6Zu6lNtksHZLiFe9k8LolSJNhoc94=
+go.step.sm/crypto v0.25.0 h1:a+7sKyozZH9B30s0dHluygxreUxI1NtCBEmuNXx7a4k=
+go.step.sm/crypto v0.25.0/go.mod h1:kr1rzO6SzeQnLm6Zu6lNtksHZLiFe9k8LolSJNhoc94=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
@@ -1405,8 +1406,8 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q
 google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
 google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
 google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.109.0 h1:sW9hgHyX497PP5//NUM7nqfV8D0iDfBApqq7sOh1XR8=
-google.golang.org/api v0.109.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
+google.golang.org/api v0.110.0 h1:l+rh0KYUooe9JGbGVx71tbFo4SMbMTXK3I3ia2QSEeU=
+google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1457,8 +1458,8 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20230109162033-3c3c17ce83e6 h1:uUn6GsgKK2eCI0bWeRMgRCcqDaQXYDuB+5tXA5Xeg/8=
-google.golang.org/genproto v0.0.0-20230109162033-3c3c17ce83e6/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1478,8 +1479,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ=
-google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
+google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
+google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff --git a/internal/pkg/cosign/tsa/client/client.go b/internal/pkg/cosign/tsa/client/client.go
new file mode 100644
index 00000000..380f270b
--- /dev/null
+++ b/internal/pkg/cosign/tsa/client/client.go
@@ -0,0 +1,83 @@
+// Copyright 2023 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/digitorus/timestamp"
+	"github.com/pkg/errors"
+)
+
+// TimestampAuthorityClient should be implemented by clients that want to request timestamp responses
+type TimestampAuthorityClient interface {
+	GetTimestampResponse(tsq []byte) ([]byte, error)
+}
+
+// TimestampAuthorityClient provides a client to query RFC 3161 timestamp authorities
+type TimestampAuthorityClientImpl struct {
+	TimestampAuthorityClient
+
+	// URL is the path to the API to request timestamp responses
+	URL string
+
+	// Timeout is the request timeout
+	Timeout time.Duration
+}
+
+// GetTimestampResponse sends a timestamp query to a timestamp authority, returning a timestamp response.
+// The query and response are defined by RFC 3161.
+func (t *TimestampAuthorityClientImpl) GetTimestampResponse(tsq []byte) ([]byte, error) {
+	client := http.Client{
+		Timeout: t.Timeout,
+	}
+	req, err := http.NewRequest("POST", t.URL, bytes.NewReader(tsq))
+	if err != nil {
+		return nil, errors.Wrap(err, "error creating HTTP request")
+	}
+	req.Header.Set("Content-Type", "application/timestamp-query")
+
+	tsr, err := client.Do(req)
+	if err != nil {
+		return nil, errors.Wrap(err, "error making request to timestamp authority")
+	}
+	if tsr.StatusCode != 200 && tsr.StatusCode != 201 {
+		return nil, fmt.Errorf("request to timestamp authority failed with status code %d", tsr.StatusCode)
+	}
+
+	resp, err := io.ReadAll(tsr.Body)
+	if err != nil {
+		return nil, errors.Wrap(err, "error reading timestamp response")
+	}
+
+	// validate that the timestamp response is parseable
+	ts, err := timestamp.ParseResponse(resp)
+	if err != nil {
+		return nil, err
+	}
+
+	fmt.Fprintln(os.Stderr, "Timestamp fetched with time: ", ts.Time)
+
+	return resp, nil
+}
+
+func NewTSAClient(url string) *TimestampAuthorityClientImpl {
+	return &TimestampAuthorityClientImpl{URL: url, Timeout: 10 * time.Second}
+}
diff --git a/internal/pkg/cosign/tsa/mock/mock_tsa_client.go b/internal/pkg/cosign/tsa/mock/mock_tsa_client.go
index cb708ba9..54d91cff 100644
--- a/internal/pkg/cosign/tsa/mock/mock_tsa_client.go
+++ b/internal/pkg/cosign/tsa/mock/mock_tsa_client.go
@@ -15,24 +15,19 @@
 package mock
 
 import (
-	"bytes"
 	"crypto"
 	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/x509"
 	"encoding/asn1"
-	"fmt"
-	"io"
 	"time"
 
-	"github.com/go-openapi/runtime"
 	"github.com/pkg/errors"
 
 	"github.com/digitorus/timestamp"
+	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
 	"github.com/sigstore/sigstore/pkg/signature"
-	"github.com/sigstore/timestamp-authority/pkg/generated/client"
-	ts "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp"
 	"github.com/sigstore/timestamp-authority/pkg/signer"
 )
 
@@ -41,11 +36,12 @@ import (
 // Time can be provided in the initializer, or defaults to time.Now().
 // All other timestamp parameters are hardcoded.
 type TSAClient struct {
-	Signer       crypto.Signer
-	CertChain    []*x509.Certificate
-	CertChainPEM string
-	Time         time.Time
-	Message      []byte
+	client.TimestampAuthorityClient
+
+	Signer    crypto.Signer
+	CertChain []*x509.Certificate
+	Time      time.Time
+	Message   []byte
 }
 
 // TSAClientOptions provide customization for the mock TSA client.
@@ -58,7 +54,7 @@ type TSAClientOptions struct {
 	Signer crypto.Signer
 }
 
-func NewTSAClient(o TSAClientOptions) (*client.TimestampAuthority, error) {
+func NewTSAClient(o TSAClientOptions) (*TSAClient, error) {
 	sv := o.Signer
 	if sv == nil {
 		var err error
@@ -71,37 +67,21 @@ func NewTSAClient(o TSAClientOptions) (*client.TimestampAuthority, error) {
 	if err != nil {
 		return nil, errors.Wrap(err, "generating timestamping cert chain")
 	}
-	certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(certChain)
-	if err != nil {
-		return nil, fmt.Errorf("marshal certificates to PEM: %w", err)
-	}
 
-	return &client.TimestampAuthority{
-		Timestamp: &TSAClient{
-			Signer:       sv,
-			CertChain:    certChain,
-			CertChainPEM: string(certChainPEM),
-			Time:         o.Time,
-			Message:      o.Message,
-		},
+	return &TSAClient{
+		Signer:    sv,
+		CertChain: certChain,
+		Time:      o.Time,
+		Message:   o.Message,
 	}, nil
 }
 
-func (c *TSAClient) GetTimestampCertChain(_ *ts.GetTimestampCertChainParams, _ ...ts.ClientOption) (*ts.GetTimestampCertChainOK, error) {
-	return &ts.GetTimestampCertChainOK{Payload: c.CertChainPEM}, nil
-}
-
-func (c *TSAClient) GetTimestampResponse(params *ts.GetTimestampResponseParams, w io.Writer, _ ...ts.ClientOption) (*ts.GetTimestampResponseCreated, error) {
+func (c *TSAClient) GetTimestampResponse(tsq []byte) ([]byte, error) {
 	var hashAlg crypto.Hash
 	var hashedMessage []byte
 
-	if params.Request != nil {
-		requestBytes, err := io.ReadAll(params.Request)
-		if err != nil {
-			return nil, err
-		}
-
-		req, err := timestamp.ParseRequest(requestBytes)
+	if tsq != nil {
+		req, err := timestamp.ParseRequest(tsq)
 		if err != nil {
 			return nil, err
 		}
@@ -137,21 +117,5 @@ func (c *TSAClient) GetTimestampResponse(params *ts.GetTimestampResponseParams,
 		tsStruct.Time = c.Time
 	}
 
-	resp, err := tsStruct.CreateResponse(c.CertChain[0], c.Signer)
-	if err != nil {
-		return nil, err
-	}
-
-	// write response to provided buffer and payload
-	if w != nil {
-		_, err := w.Write(resp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return &ts.GetTimestampResponseCreated{Payload: bytes.NewBuffer(resp)}, nil
-}
-
-func (c *TSAClient) SetTransport(transport runtime.ClientTransport) {
-	// nothing to do
+	return tsStruct.CreateResponse(c.CertChain[0], c.Signer)
 }
diff --git a/internal/pkg/cosign/tsa/signer.go b/internal/pkg/cosign/tsa/signer.go
index 10ac6fd7..99c05402 100644
--- a/internal/pkg/cosign/tsa/signer.go
+++ b/internal/pkg/cosign/tsa/signer.go
@@ -18,57 +18,37 @@ import (
 	"bytes"
 	"context"
 	"crypto"
-	"fmt"
 	"io"
-	"os"
 	"strconv"
 	"strings"
-	"time"
 
 	"github.com/digitorus/timestamp"
+	"github.com/pkg/errors"
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign"
+	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	"github.com/sigstore/cosign/v2/pkg/cosign/bundle"
 	"github.com/sigstore/cosign/v2/pkg/oci"
 	"github.com/sigstore/cosign/v2/pkg/oci/mutate"
 
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
-	tsaclient "github.com/sigstore/timestamp-authority/pkg/generated/client"
-	ts "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp"
 )
 
 // GetTimestampedSignature queries a timestamp authority to fetch an RFC3161 timestamp. sigBytes is an
 // opaque blob, but is typically a signature over an artifact.
-func GetTimestampedSignature(sigBytes []byte, tsaClient *tsaclient.TimestampAuthority) ([]byte, error) {
+func GetTimestampedSignature(sigBytes []byte, tsaClient client.TimestampAuthorityClient) ([]byte, error) {
 	requestBytes, err := createTimestampAuthorityRequest(sigBytes, crypto.SHA256, "")
 	if err != nil {
-		return nil, err
+		return nil, errors.Wrap(err, "error creating timestamp request")
 	}
-	params := ts.NewGetTimestampResponseParams()
-	params.SetTimeout(time.Second * 10)
-	params.Request = io.NopCloser(bytes.NewReader(requestBytes))
-
-	var respBytes bytes.Buffer
-	_, err = tsaClient.Timestamp.GetTimestampResponse(params, &respBytes)
-	if err != nil {
-		return nil, fmt.Errorf("unable to get the response: %w", err)
-	}
-
-	// validate that timestamp is parseable
-	ts, err := timestamp.ParseResponse(respBytes.Bytes())
-	if err != nil {
-		return nil, err
-	}
-
-	fmt.Fprintln(os.Stderr, "Timestamp fetched with time: ", ts.Time)
 
-	return respBytes.Bytes(), nil
+	return tsaClient.GetTimestampResponse(requestBytes)
 }
 
 // signerWrapper calls a wrapped, inner signer then uploads either the Cert or Pub(licKey) of the results to Rekor, then adds the resulting `Bundle`
 type signerWrapper struct {
 	inner cosign.Signer
 
-	tsaClient *tsaclient.TimestampAuthority
+	tsaClient client.TimestampAuthorityClient
 }
 
 var _ cosign.Signer = (*signerWrapper)(nil)
@@ -126,7 +106,7 @@ func createTimestampAuthorityRequest(artifactBytes []byte, hash crypto.Hash, pol
 }
 
 // NewSigner returns a `cosign.Signer` which uploads the signature to a TSA
-func NewSigner(inner cosign.Signer, tsaClient *tsaclient.TimestampAuthority) cosign.Signer {
+func NewSigner(inner cosign.Signer, tsaClient client.TimestampAuthorityClient) cosign.Signer {
 	return &signerWrapper{
 		inner:     inner,
 		tsaClient: tsaClient,
diff --git a/internal/pkg/oci/remote/remote.go b/internal/pkg/oci/remote/remote.go
new file mode 100644
index 00000000..250a5c0d
--- /dev/null
+++ b/internal/pkg/oci/remote/remote.go
@@ -0,0 +1,25 @@
+//
+// Copyright 2023 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package remote
+
+import (
+	"fmt"
+)
+
+// ArtifactType converts a attachment name (sig/sbom/att/etc.) into a valid artifactType (OCI 1.1+).
+func ArtifactType(attName string) string {
+	return fmt.Sprintf("application/vnd.dev.cosign.artifact.%s.v1+json", attName)
+}
diff --git a/pkg/cosign/errors.go b/pkg/cosign/errors.go
index c4ef6c23..984ed6a0 100644
--- a/pkg/cosign/errors.go
+++ b/pkg/cosign/errors.go
@@ -17,20 +17,21 @@ package cosign
 import "fmt"
 
 var (
-	// ErrNoMatchingSignatures is the error returned when there are no matching
-	// signatures during verification.
-	ErrNoMatchingSignatures = &VerificationError{"no matching signatures"}
+	// NoMatchingAttestations
+	ErrNoMatchingAttestationsMessage = "no matching attestations"
+	ErrNoMatchingAttestationsType    = "NoMatchingAttestations"
 
-	// ErrNoMatchingAttestations is the error returned when there are no
-	// matching attestations during verification.
-	ErrNoMatchingAttestations = &VerificationError{"no matching attestations"}
+	// NoMatchingSignatures
+	ErrNoMatchingSignaturesType    = "NoMatchingSignatures"
+	ErrNoMatchingSignaturesMessage = "no matching signatures"
 )
 
 // VerificationError is the type of Go error that is used by cosign to surface
 // errors actually related to verification (vs. transient, misconfiguration,
 // transport, or authentication related issues).
 type VerificationError struct {
-	message string
+	errorType string
+	message   string
 }
 
 // NewVerificationError constructs a new VerificationError in a manner similar
@@ -48,3 +49,12 @@ var _ error = (*VerificationError)(nil)
 func (ve *VerificationError) Error() string {
 	return ve.message
 }
+
+// Error implements error
+func (ve *VerificationError) ErrorType() string {
+	return ve.errorType
+}
+
+func (ve *VerificationError) SetErrorType(errorType string) {
+	ve.errorType = errorType
+}
diff --git a/pkg/cosign/verify.go b/pkg/cosign/verify.go
index 13aa9f29..bfb3cd17 100644
--- a/pkg/cosign/verify.go
+++ b/pkg/cosign/verify.go
@@ -46,6 +46,8 @@ import (
 	v1 "github.com/google/go-containerregistry/pkg/v1"
 
 	ssldsse "github.com/secure-systems-lab/go-securesystemslib/dsse"
+	ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote"
+	"github.com/sigstore/cosign/v2/internal/ui"
 	"github.com/sigstore/cosign/v2/pkg/oci"
 	"github.com/sigstore/cosign/v2/pkg/oci/layout"
 	ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
@@ -233,7 +235,8 @@ func ValidateAndUnpackCert(cert *x509.Certificate, co *CheckOpts) (signature.Ver
 		return nil, err
 	}
 	if !contains && len(co.SCT) == 0 {
-		return nil, &VerificationError{"certificate does not include required embedded SCT and no detached SCT was set"}
+		// TODO: add error type instead of blank string
+		return nil, &VerificationError{"", "certificate does not include required embedded SCT and no detached SCT was set"}
 	}
 	// handle if chains has more than one chain - grab first and print message
 	if len(chains) > 1 {
@@ -326,7 +329,7 @@ func CheckCertificatePolicy(cert *x509.Certificate, co *CheckOpts) error {
 				return nil
 			}
 		}
-		return &VerificationError{
+		return &VerificationError{"",
 			fmt.Sprintf("none of the expected identities matched what was in the certificate, got subjects [%s] with issuer %s",
 				strings.Join(sans, ", "), oidcIssuer)}
 	}
@@ -336,31 +339,36 @@ func CheckCertificatePolicy(cert *x509.Certificate, co *CheckOpts) error {
 func validateCertExtensions(ce CertExtensions, co *CheckOpts) error {
 	if co.CertGithubWorkflowTrigger != "" {
 		if ce.GetCertExtensionGithubWorkflowTrigger() != co.CertGithubWorkflowTrigger {
-			return &VerificationError{"expected GitHub Workflow Trigger not found in certificate"}
+			// TODO: add error type instead of blank string
+			return &VerificationError{"", "expected GitHub Workflow Trigger not found in certificate"}
 		}
 	}
 
 	if co.CertGithubWorkflowSha != "" {
 		if ce.GetExtensionGithubWorkflowSha() != co.CertGithubWorkflowSha {
-			return &VerificationError{"expected GitHub Workflow SHA not found in certificate"}
+			// TODO: add error type instead of blank string
+			return &VerificationError{"", "expected GitHub Workflow SHA not found in certificate"}
 		}
 	}
 
 	if co.CertGithubWorkflowName != "" {
 		if ce.GetCertExtensionGithubWorkflowName() != co.CertGithubWorkflowName {
-			return &VerificationError{"expected GitHub Workflow Name not found in certificate"}
+			// TODO: add error type instead of blank string
+			return &VerificationError{"", "expected GitHub Workflow Name not found in certificate"}
 		}
 	}
 
 	if co.CertGithubWorkflowRepository != "" {
 		if ce.GetCertExtensionGithubWorkflowRepository() != co.CertGithubWorkflowRepository {
-			return &VerificationError{"expected GitHub Workflow Repository not found in certificate"}
+			// TODO: add error type instead of blank string
+			return &VerificationError{"", "expected GitHub Workflow Repository not found in certificate"}
 		}
 	}
 
 	if co.CertGithubWorkflowRef != "" {
 		if ce.GetCertExtensionGithubWorkflowRef() != co.CertGithubWorkflowRef {
-			return &VerificationError{"expected GitHub Workflow Ref not found in certificate"}
+			// TODO: add error type instead of blank string
+			return &VerificationError{"", "expected GitHub Workflow Ref not found in certificate"}
 		}
 	}
 	return nil
@@ -461,6 +469,12 @@ func (fos *fakeOCISignatures) Get() ([]oci.Signature, error) {
 // VerifyImageSignatures does all the main cosign checks in a loop, returning the verified signatures.
 // If there were no valid signatures, we return an error.
 func VerifyImageSignatures(ctx context.Context, signedImgRef name.Reference, co *CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) {
+	// Try first using OCI 1.1 behavior
+	verified, bundleVerified, err := verifyImageSignaturesExperimentalOCI(ctx, signedImgRef, co)
+	if err == nil {
+		return verified, bundleVerified, nil
+	}
+
 	// Enforce this up front.
 	if co.RootCerts == nil && co.SigVerifier == nil {
 		return nil, false, errors.New("one of verifier or root certs is required")
@@ -572,7 +586,10 @@ func verifySignatures(ctx context.Context, sigs oci.Signatures, h v1.Hash, co *C
 		checkedSignatures = append(checkedSignatures, sig)
 	}
 	if len(checkedSignatures) == 0 {
-		return nil, false, fmt.Errorf("%w:\n%s", ErrNoMatchingSignatures, strings.Join(validationErrs, "\n "))
+		return nil, false, &VerificationError{
+			errorType: ErrNoMatchingSignaturesType,
+			message:   fmt.Sprintf("%s:\n%s", ErrNoMatchingSignaturesMessage, strings.Join(validationErrs, "\n ")),
+		}
 	}
 	return checkedSignatures, bundleVerified, nil
 }
@@ -646,7 +663,8 @@ func verifyInternal(ctx context.Context, sig oci.Signature, h v1.Hash,
 			return false, err
 		}
 		if cert == nil {
-			return false, &VerificationError{"no certificate found on signature"}
+			// TODO: add error type instead of blank string
+			return false, &VerificationError{"", "no certificate found on signature"}
 		}
 		// Create a certificate pool for intermediate CA certificates, excluding the root
 		chain, err := sig.Chain()
@@ -713,7 +731,8 @@ func verifyInternal(ctx context.Context, sig oci.Signature, h v1.Hash,
 			if err := CheckExpiry(cert, time.Now()); err != nil {
 				// If certificate is expired and not signed timestamp was provided then error the following message. Otherwise throw an expiration error.
 				if co.IgnoreTlog && acceptableRFC3161Time == nil {
-					return false, &VerificationError{"expected a signed timestamp to verify an expired certificate"}
+					// TODO: add error type instead of blank string
+					return false, &VerificationError{"", "expected a signed timestamp to verify an expired certificate"}
 				}
 				return false, fmt.Errorf("checking expiry on certificate with bundle: %w", err)
 			}
@@ -896,7 +915,10 @@ func verifyImageAttestations(ctx context.Context, atts oci.Signatures, h v1.Hash
 		checkedAttestations = append(checkedAttestations, att)
 	}
 	if len(checkedAttestations) == 0 {
-		return nil, false, fmt.Errorf("%w:\n%s", ErrNoMatchingAttestations, strings.Join(validationErrs, "\n "))
+		return nil, false, &VerificationError{
+			errorType: ErrNoMatchingAttestationsType,
+			message:   fmt.Sprintf("%s:\n%s", ErrNoMatchingAttestationsMessage, strings.Join(validationErrs, "\n ")),
+		}
 	}
 	return checkedAttestations, bundleVerified, nil
 }
@@ -957,7 +979,8 @@ func VerifyBundle(sig oci.Signature, co *CheckOpts) (bool, error) {
 
 	pubKey, ok := co.RekorPubKeys.Keys[bundle.Payload.LogID]
 	if !ok {
-		return false, &VerificationError{"verifying bundle: rekor log public key not found for payload"}
+		// TODO: add error type instead of blank string
+		return false, &VerificationError{"", "verifying bundle: rekor log public key not found for payload"}
 	}
 	err = VerifySET(bundle.Payload, bundle.SignedEntryTimestamp, pubKey.PubKey.(*ecdsa.PublicKey))
 	if err != nil {
@@ -1047,7 +1070,8 @@ func compareSigs(bundleBody string, sig oci.Signature) error {
 		return nil
 	}
 	if bundleSignature != actualSig {
-		return &VerificationError{"signature in bundle does not match signature being verified"}
+		// TODO: add error type instead of blank string
+		return &VerificationError{"", "signature in bundle does not match signature being verified"}
 	}
 	return nil
 }
@@ -1250,7 +1274,8 @@ func VerifySET(bundlePayload cbundle.RekorPayload, signature []byte, pub *ecdsa.
 	// verify the SET against the public key
 	hash := sha256.Sum256(canonicalized)
 	if !ecdsa.VerifyASN1(pub, hash[:], signature) {
-		return &VerificationError{"unable to verify SET"}
+		// TODO: add error type instead of blank string
+		return &VerificationError{"", "unable to verify SET"}
 	}
 	return nil
 }
@@ -1281,3 +1306,58 @@ func correctAnnotations(wanted, have map[string]interface{}) bool {
 	}
 	return true
 }
+
+// verifyImageSignaturesExperimentalOCI does all the main cosign checks in a loop, returning the verified signatures.
+// If there were no valid signatures, we return an error, using OCI 1.1+ behavior.
+func verifyImageSignaturesExperimentalOCI(ctx context.Context, signedImgRef name.Reference, co *CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) {
+	// Enforce this up front.
+	if co.RootCerts == nil && co.SigVerifier == nil {
+		return nil, false, errors.New("one of verifier or root certs is required")
+	}
+
+	// This is a carefully optimized sequence for fetching the signatures of the
+	// entity that minimizes registry requests when supplied with a digest input
+	digest, err := ociremote.ResolveDigest(signedImgRef, co.RegistryClientOpts...)
+	if err != nil {
+		return nil, false, err
+	}
+	h, err := v1.NewHash(digest.Identifier())
+	if err != nil {
+		return nil, false, err
+	}
+
+	var sigs oci.Signatures
+	sigRef := co.SignatureRef
+	if sigRef == "" {
+		artifactType := ociexperimental.ArtifactType("sig")
+		index, err := ociremote.Referrers(digest, artifactType, co.RegistryClientOpts...)
+		if err != nil {
+			return nil, false, err
+		}
+		results := index.Manifests
+		numResults := len(results)
+		if numResults == 0 {
+			return nil, false, fmt.Errorf("unable to locate reference with artifactType %s", artifactType)
+		} else if numResults > 1 {
+			// TODO: if there is more than 1 result.. what does that even mean?
+			ui.Warnf(ctx, "there were a total of %d references with artifactType %s\n", numResults, artifactType)
+		}
+		// TODO: do this smarter using "created" annotations
+		lastResult := results[numResults-1]
+		st, err := name.ParseReference(fmt.Sprintf("%s@%s", digest.Repository, lastResult.Digest.String()))
+		if err != nil {
+			return nil, false, err
+		}
+		sigs, err = ociremote.Signatures(st, co.RegistryClientOpts...)
+		if err != nil {
+			return nil, false, err
+		}
+	} else {
+		sigs, err = loadSignatureFromFile(sigRef, signedImgRef, co)
+		if err != nil {
+			return nil, false, err
+		}
+	}
+
+	return verifySignatures(ctx, sigs, h, co)
+}
diff --git a/pkg/oci/remote/referrers.go b/pkg/oci/remote/referrers.go
new file mode 100644
index 00000000..868ee20c
--- /dev/null
+++ b/pkg/oci/remote/referrers.go
@@ -0,0 +1,30 @@
+//
+// Copyright 2023 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package remote
+
+import (
+	"github.com/google/go-containerregistry/pkg/name"
+	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/google/go-containerregistry/pkg/v1/remote"
+)
+
+// Referrers fetches references using registry options.
+func Referrers(d name.Digest, artifactType string, opts ...Option) (*v1.IndexManifest, error) {
+	o := makeOptions(name.Repository{}, opts...)
+	rOpt := o.ROpt
+	rOpt = append(rOpt, remote.WithFilter("artifactType", artifactType))
+	return remote.Referrers(d, rOpt...)
+}
diff --git a/pkg/oci/remote/remote.go b/pkg/oci/remote/remote.go
index 6cc9dc61..01b48f5d 100644
--- a/pkg/oci/remote/remote.go
+++ b/pkg/oci/remote/remote.go
@@ -26,6 +26,7 @@ import (
 	"github.com/google/go-containerregistry/pkg/v1/remote"
 	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
 	"github.com/google/go-containerregistry/pkg/v1/types"
+	ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote"
 	"github.com/sigstore/cosign/v2/pkg/oci"
 )
 
@@ -146,6 +147,11 @@ func attestations(digestable digestable, o *options) (oci.Signatures, error) {
 
 // attachment is a shared implementation of the oci.Signed* Attachment method.
 func attachment(digestable digestable, attName string, o *options) (oci.File, error) {
+	// Try using OCI 1.1 behavior
+	if file, err := attachmentExperimentalOCI(digestable, attName, o); err == nil {
+		return file, nil
+	}
+
 	h, err := digestable.Digest()
 	if err != nil {
 		return nil, err
@@ -193,3 +199,46 @@ func (f *attached) Payload() ([]byte, error) {
 	defer rc.Close()
 	return io.ReadAll(rc)
 }
+
+// attachmentExperimentalOCI is a shared implementation of the oci.Signed* Attachment method (for OCI 1.1+ behavior).
+func attachmentExperimentalOCI(digestable digestable, attName string, o *options) (oci.File, error) {
+	h, err := digestable.Digest()
+	if err != nil {
+		return nil, err
+	}
+	d := o.TargetRepository.Digest(h.String())
+
+	artifactType := ociexperimental.ArtifactType(attName)
+	index, err := Referrers(d, artifactType, o.OriginalOptions...)
+	if err != nil {
+		return nil, err
+	}
+	results := index.Manifests
+
+	numResults := len(results)
+	if numResults == 0 {
+		return nil, fmt.Errorf("unable to locate reference with artifactType %s", artifactType)
+	} else if numResults > 1 {
+		// TODO: if there is more than 1 result.. what does that even mean?
+		// TODO: use ui.Warn
+		fmt.Printf("WARNING: there were a total of %d references with artifactType %s\n", numResults, artifactType)
+	}
+	// TODO: do this smarter using "created" annotations
+	lastResult := results[numResults-1]
+
+	img, err := SignedImage(o.TargetRepository.Digest(lastResult.Digest.String()), o.OriginalOptions...)
+	if err != nil {
+		return nil, err
+	}
+	ls, err := img.Layers()
+	if err != nil {
+		return nil, err
+	}
+	if len(ls) != 1 {
+		return nil, fmt.Errorf("expected exactly one layer in attachment, got %d", len(ls))
+	}
+	return &attached{
+		SignedImage: img,
+		layer:       ls[0],
+	}, nil
+}
diff --git a/pkg/oci/remote/write.go b/pkg/oci/remote/write.go
index 037e16a3..3229a39c 100644
--- a/pkg/oci/remote/write.go
+++ b/pkg/oci/remote/write.go
@@ -16,12 +16,19 @@
 package remote
 
 import (
+	"bytes"
+	"encoding/json"
 	"fmt"
+	"os"
 
 	"github.com/google/go-containerregistry/pkg/name"
 	v1 "github.com/google/go-containerregistry/pkg/v1"
 	"github.com/google/go-containerregistry/pkg/v1/remote"
+	"github.com/google/go-containerregistry/pkg/v1/static"
+	"github.com/google/go-containerregistry/pkg/v1/types"
+	ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote"
 	"github.com/sigstore/cosign/v2/pkg/oci"
+	ctypes "github.com/sigstore/cosign/v2/pkg/types"
 )
 
 // WriteSignedImageIndexImages writes the images within the image index
@@ -127,3 +134,90 @@ func WriteAttestations(repo name.Repository, se oci.SignedEntity, opts ...Option
 	// Write the Signatures image to the tag, with the provided remote.Options
 	return remoteWrite(tag, atts, o.ROpt...)
 }
+
+// WriteSignaturesExperimentalOCI publishes the signatures attached to the given entity
+// into the provided repository (using OCI 1.1 methods).
+func WriteSignaturesExperimentalOCI(d name.Digest, se oci.SignedEntity, opts ...Option) error {
+	o := makeOptions(d.Repository, opts...)
+	signTarget := d.String()
+	ref, err := name.ParseReference(signTarget, o.NameOpts...)
+	if err != nil {
+		return err
+	}
+	desc, err := remote.Head(ref, o.ROpt...)
+	if err != nil {
+		return err
+	}
+	sigs, err := se.Signatures()
+	if err != nil {
+		return err
+	}
+
+	// Write the signature blobs
+	s, err := sigs.Get()
+	if err != nil {
+		return err
+	}
+	for _, v := range s {
+		if err := remote.WriteLayer(d.Repository, v, o.ROpt...); err != nil {
+			return err
+		}
+	}
+
+	// Write the config
+	configBytes, err := sigs.RawConfigFile()
+	if err != nil {
+		return err
+	}
+	var configDesc v1.Descriptor
+	if err := json.Unmarshal(configBytes, &configDesc); err != nil {
+		return err
+	}
+	configLayer := static.NewLayer(configBytes, configDesc.MediaType)
+	if err := remote.WriteLayer(d.Repository, configLayer, o.ROpt...); err != nil {
+		return err
+	}
+
+	// Write the manifest containing a subject
+	b, err := sigs.RawManifest()
+	if err != nil {
+		return err
+	}
+	var m v1.Manifest
+	if err := json.Unmarshal(b, &m); err != nil {
+		return err
+	}
+
+	artifactType := ociexperimental.ArtifactType("sig")
+	m.Config.MediaType = types.MediaType(artifactType)
+	m.Subject = desc
+	b, err = json.Marshal(&m)
+	if err != nil {
+		return err
+	}
+	digest, _, err := v1.SHA256(bytes.NewReader(b))
+	if err != nil {
+		return err
+	}
+	targetRef, err := name.ParseReference(fmt.Sprintf("%s/%s@%s", d.RegistryStr(), d.RepositoryStr(), digest.String()))
+	if err != nil {
+		return err
+	}
+	// TODO: use ui.Infof
+	fmt.Fprintf(os.Stderr, "Uploading signature for [%s] to [%s] with config.mediaType [%s] layers[0].mediaType [%s].\n",
+		d.String(), targetRef.String(), artifactType, ctypes.SimpleSigningMediaType)
+	return remote.Put(targetRef, &taggableManifest{raw: b, mediaType: m.MediaType}, o.ROpt...)
+}
+
+type taggableManifest struct {
+	raw       []byte
+	mediaType types.MediaType
+}
+
+func (taggable taggableManifest) RawManifest() ([]byte, error) {
+	return taggable.raw, nil
+}
+
+func (taggable taggableManifest) MediaType() (types.MediaType, error) {
+	return taggable.mediaType, nil
+}
diff --git a/release/cloudbuild.yaml b/release/cloudbuild.yaml
index c5c0104e..ab80da41 100644
--- a/release/cloudbuild.yaml
+++ b/release/cloudbuild.yaml
@@ -16,98 +16,104 @@
 timeout: 3600s
 
 steps:
-- name: gcr.io/cloud-builders/git
-  dir: "go/src/sigstore"
-  args:
-  - "clone"
-  - "https://github.com/${_TOOL_ORG}/${_TOOL_REPO}"
+  - name: gcr.io/cloud-builders/git
+    dir: "go/src/sigstore"
+    args:
+      - "clone"
+      - "https://github.com/${_TOOL_ORG}/${_TOOL_REPO}"
 
-- name: gcr.io/cloud-builders/git
-  entrypoint: "bash"
-  dir: "go/src/sigstore/cosign"
-  args:
-  - '-c'
-  - |
-    git fetch
-    echo "Checking out ${_GIT_TAG}"
-    git checkout ${_GIT_TAG}
+  - name: gcr.io/cloud-builders/git
+    entrypoint: "bash"
+    dir: "go/src/sigstore/cosign"
+    args:
+      - '-c'
+      - |
+        git fetch
+        echo "Checking out ${_GIT_TAG}"
+        git checkout ${_GIT_TAG}
 
-- name: 'gcr.io/projectsigstore/cosign:v2.0.0-rc.1@sha256:12d365ed4ee9bb32ba8a0fd16f6c5eae5229dc50e8d62460312cca0b5b7e0457'
-  dir: "go/src/sigstore/cosign"
-  env:
-  - TUF_ROOT=/tmp
-  args:
-  - 'verify'
-  - 'ghcr.io/gythialy/golang-cross:v1.20.0-0@sha256:d50b48a7cf2b90f70e35da6d7419b7b16ed29a10f3175a2c849ef2956d485aae'
+  - name: 'gcr.io/projectsigstore/cosign:v2.0.0-rc.2@sha256:3c62b38a5b7eaa4db90c328d430a705d086792869aece919559ecf381a23a4e8'
+    dir: "go/src/sigstore/cosign"
+    env:
+      - TUF_ROOT=/tmp
+    args:
+      - 'verify'
+      - 'ghcr.io/gythialy/golang-cross:v1.20.1-0@sha256:ca8d8591b77ede34d28b1c73bcaf901552dbea8af9d59bad4d723d18dcfc6cd4'
+      - '--certificate-oidc-issuer'
+      - "https://token.actions.githubusercontent.com"
+      - '--certificate-identity'
+      - "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.20.1-0"
 
-# maybe we can build our own image and use that to be more in a safe side
-- name: ghcr.io/gythialy/golang-cross:v1.20.0-0@sha256:d50b48a7cf2b90f70e35da6d7419b7b16ed29a10f3175a2c849ef2956d485aae
-  entrypoint: /bin/sh
-  dir: "go/src/sigstore/cosign"
-  env:
-  - "GOPATH=/workspace/go"
-  - "GOBIN=/workspace/bin"
-  - PROJECT_ID=${PROJECT_ID}
-  - KEY_LOCATION=${_KEY_LOCATION}
-  - KEY_RING=${_KEY_RING}
-  - KEY_NAME=${_KEY_NAME}
-  - KEY_VERSION=${_KEY_VERSION}
-  - GIT_TAG=${_GIT_TAG}
-  - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com
-  - COSIGN_YES=true
-  - KO_PREFIX=gcr.io/${PROJECT_ID}
-  secretEnv:
-  - GITHUB_TOKEN
-  args:
-    - '-c'
-    - |
-      gcloud auth configure-docker \
-      && make release
+  # maybe we can build our own image and use that to be more in a safe side
+  - name: ghcr.io/gythialy/golang-cross:v1.20.1-0@sha256:ca8d8591b77ede34d28b1c73bcaf901552dbea8af9d59bad4d723d18dcfc6cd4
+    entrypoint: /bin/sh
+    dir: "go/src/sigstore/cosign"
+    env:
+      - "GOPATH=/workspace/go"
+      - "GOBIN=/workspace/bin"
+      - PROJECT_ID=${PROJECT_ID}
+      - KEY_LOCATION=${_KEY_LOCATION}
+      - KEY_RING=${_KEY_RING}
+      - KEY_NAME=${_KEY_NAME}
+      - KEY_VERSION=${_KEY_VERSION}
+      - GIT_TAG=${_GIT_TAG}
+      - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com
+      - COSIGN_YES=true
+      - COSIGN_EXPERIMENTAL=true
+      - KO_PREFIX=gcr.io/${PROJECT_ID}
+    secretEnv:
+      - GITHUB_TOKEN
+    args:
+      - '-c'
+      - |
+        gcloud auth configure-docker \
+        && make release
 
-- name: ghcr.io/gythialy/golang-cross:v1.20.0-0@sha256:d50b48a7cf2b90f70e35da6d7419b7b16ed29a10f3175a2c849ef2956d485aae
-  entrypoint: 'bash'
-  dir: "go/src/sigstore/cosign"
-  env:
-  - "GOPATH=/workspace/go"
-  - "GOBIN=/workspace/bin"
-  - PROJECT_ID=${PROJECT_ID}
-  - KEY_LOCATION=${_KEY_LOCATION}
-  - KEY_RING=${_KEY_RING}
-  - KEY_NAME=${_KEY_NAME}
-  - KEY_VERSION=${_KEY_VERSION}
-  - GIT_TAG=${_GIT_TAG}
-  - KO_PREFIX=gcr.io/${PROJECT_ID}
-  - COSIGN_YES=true
-  - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com
-  - GITHUB_USER=${_GITHUB_USER}
-  secretEnv:
-  - GITHUB_TOKEN
-  args:
-    - '-c'
-    - |
-      echo $$GITHUB_TOKEN | docker login ghcr.io -u $$GITHUB_USER --password-stdin \
-      && make copy-signed-release-to-ghcr || true
+  - name: ghcr.io/gythialy/golang-cross:v1.20.1-0@sha256:ca8d8591b77ede34d28b1c73bcaf901552dbea8af9d59bad4d723d18dcfc6cd4
+    entrypoint: 'bash'
+    dir: "go/src/sigstore/cosign"
+    env:
+      - "GOPATH=/workspace/go"
+      - "GOBIN=/workspace/bin"
+      - PROJECT_ID=${PROJECT_ID}
+      - KEY_LOCATION=${_KEY_LOCATION}
+      - KEY_RING=${_KEY_RING}
+      - KEY_NAME=${_KEY_NAME}
+      - KEY_VERSION=${_KEY_VERSION}
+      - GIT_TAG=${_GIT_TAG}
+      - KO_PREFIX=gcr.io/${PROJECT_ID}
+      - COSIGN_YES=true
+      - COSIGN_EXPERIMENTAL=true
+      - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com
+      - GITHUB_USER=${_GITHUB_USER}
+    secretEnv:
+      - GITHUB_TOKEN
+    args:
+      - '-c'
+      - |
+        echo $$GITHUB_TOKEN | docker login ghcr.io -u $$GITHUB_USER --password-stdin \
+        && make copy-signed-release-to-ghcr || true
 
 availableSecrets:
   secretManager:
-  - versionName: projects/${PROJECT_NUMBER}/secrets/GITHUB_TOKEN/versions/latest
-    env: GITHUB_TOKEN
+    - versionName: projects/${PROJECT_NUMBER}/secrets/GITHUB_TOKEN/versions/latest
+      env: GITHUB_TOKEN
 
 artifacts:
   objects:
     location: 'gs://${_STORAGE_LOCATION}/${_GIT_TAG}'
     paths:
-    - "go/src/sigstore/cosign/dist/*"
-    - "go/src/sigstore/cosign/release/release-cosign.pub"
+      - "go/src/sigstore/cosign/dist/*"
+      - "go/src/sigstore/cosign/release/release-cosign.pub"
 
 options:
   machineType: E2_HIGHCPU_32
 
 tags:
-- cosign-release
-- ${_GIT_TAG}
-- ${_TOOL_ORG}
-- ${_TOOL_REPO}
+  - cosign-release
+  - ${_GIT_TAG}
+  - ${_TOOL_ORG}
+  - ${_TOOL_REPO}
 
 substitutions:
   _GIT_TAG: 'v1.23.45'
diff --git a/specs/COSIGN_PREDICATE_SPEC.md b/specs/COSIGN_PREDICATE_SPEC.md
index 0e899b5e..314cebe8 100644
--- a/specs/COSIGN_PREDICATE_SPEC.md
+++ b/specs/COSIGN_PREDICATE_SPEC.md
@@ -14,7 +14,7 @@ Here is an example attestation containing a data file containing `foo`:
 ```json
 {
   "_type": "https://in-toto.io/Statement/v0.1",
-  "predicateType": "cosign.sigstore.dev/attestation/v1",
+  "predicateType": "https://cosign.sigstore.dev/attestation/v1",
   "subject": [
     {
       "name": "us.gcr.io/dlorenc-vmtest2/demo",


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 085c3b01..583681d2 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -48,7 +48,7 @@ jobs:
     steps:
       - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
       # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds
-      - uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
+      - uses: actions/cache@6998d139ddd3e68c71e9e398d8e40b71a2f39812 # v3.2.5
         with:
           # In order:
           # * Module download cache
@@ -90,7 +90,7 @@ jobs:
     steps:
       - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
       # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds
-      - uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
+      - uses: actions/cache@6998d139ddd3e68c71e9e398d8e40b71a2f39812 # v3.2.5
         with:
           # In order:
           # * Module download cache
@@ -137,7 +137,7 @@ jobs:
           check-latest: true
 
       # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds
-      - uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
+      - uses: actions/cache@6998d139ddd3e68c71e9e398d8e40b71a2f39812 # v3.2.5
         with:
           # In order:
           # * Module download cache
diff --git a/cmd/cosign/cli/attest/attest.go b/cmd/cosign/cli/attest/attest.go
index 98edd1c6..2a0aab6b 100644
--- a/cmd/cosign/cli/attest/attest.go
+++ b/cmd/cosign/cli/attest/attest.go
@@ -32,6 +32,7 @@ import (
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa"
+	tsaclient "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	"github.com/sigstore/cosign/v2/internal/ui"
 	"github.com/sigstore/cosign/v2/pkg/cosign"
 	"github.com/sigstore/cosign/v2/pkg/cosign/attestation"
@@ -45,7 +46,6 @@ import (
 	"github.com/sigstore/rekor/pkg/generated/models"
 	"github.com/sigstore/sigstore/pkg/signature/dsse"
 	signatureoptions "github.com/sigstore/sigstore/pkg/signature/options"
-	tsaclient "github.com/sigstore/timestamp-authority/pkg/client"
 )
 
 type tlogUploadFn func(*client.Rekor, []byte) (*models.LogEntryAnon, error)
@@ -173,13 +173,8 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error {
 		opts = append(opts, static.WithCertChain(sv.Cert, sv.Chain))
 	}
 	if c.KeyOpts.TSAServerURL != "" {
-		clientTSA, err := tsaclient.GetTimestampClient(c.KeyOpts.TSAServerURL)
-		if err != nil {
-			return fmt.Errorf("failed to create TSA client: %w", err)
-		}
-
 		// Here we get the response from the timestamped authority server
-		responseBytes, err := tsa.GetTimestampedSignature(signedPayload, clientTSA)
+		responseBytes, err := tsa.GetTimestampedSignature(signedPayload, tsaclient.NewTSAClient(c.KeyOpts.TSAServerURL))
 		if err != nil {
 			return err
 		}
diff --git a/cmd/cosign/cli/attest/attest_blob.go b/cmd/cosign/cli/attest/attest_blob.go
index ec52a3d2..2946ea1c 100644
--- a/cmd/cosign/cli/attest/attest_blob.go
+++ b/cmd/cosign/cli/attest/attest_blob.go
@@ -34,6 +34,7 @@ import (
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
 	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa"
+	"github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client"
 	"github.com/sigstore/cosign/v2/pkg/cosign"
 	"github.com/sigstore/cosign/v2/pkg/cosign/attestation"
 	cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle"
@@ -42,7 +43,6 @@ import (
 	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/sigstore/sigstore/pkg/signature/dsse"
 	signatureoptions "github.com/sigstore/sigstore/pkg/signature/options"
-	tsaclient "github.com/sigstore/timestamp-authority/pkg/client"
 )
 
 // nolint
@@ -145,11 +145,7 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error
 
 	var rfc3161Timestamp *cbundle.RFC3161Timestamp
 	if c.TSAServerURL != "" {
-		clientTSA, err := tsaclient.GetTimestampClient(c.TSAServerURL)
-		if err != nil {
-			return fmt.Errorf("failed to create TSA client: %w", err)
-		}
-		respBytes, err := tsa.GetTimestampedSignature(sig, clientTSA)
+		respBytes, err := tsa.GetTimestampedSignature(sig, client.NewTSAClient(c.TSAServerURL))
 		if err != nil {
 			return err
 		}
diff --git a/cmd/cosign/cli/options/attest.go b/cmd/cosign/cli/options/attest.go
index 9c480f7d..cb1a2756 100644
--- a/cmd/cosign/cli/options/attest.go
+++ b/cmd/cosign/cli/options/attest.go
@@ -81,5 +81,5 @@ func (o *AttestOptions) AddFlags(cmd *cobra.Command) {
 		"whether or not to upload to the tlog")
 
 	cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
-		"url to the Timestamp RFC3161 server, default none")
+		"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
 }
diff --git a/cmd/cosign/cli/options/attest_blob.go b/cmd/cosign/cli/options/attest_blob.go
index b724d3cf..e960884a 100644
--- a/cmd/cosign/cli/options/attest_blob.go
+++ b/cmd/cosign/cli/options/attest_blob.go
@@ -93,7 +93,7 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) {
 		"whether or not to upload to the tlog")
 
 	cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
-		"url to the Timestamp RFC3161 server, default none")
+		"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
 
 	cmd.Flags().StringVar(&o.RFC3161TimestampPath, "rfc3161-timestamp-bundle", "",
 		"path to an RFC 3161 timestamp bundle FILE")
diff --git a/cmd/cosign/cli/verify/verify_blob_test.go b/cmd/cosign/cli/verify/verify_blob_test.go
index 6a891c15..fab70bc3 100644
--- a/cmd/cosign/cli/verify/verify_blob_test.go
+++ b/cmd/cosign/cli/verify/verify_blob_test.go
@@ -56,7 +56,6 @@ import (
 	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/sigstore/sigstore/pkg/signature/dsse"
 	signatureoptions "github.com/sigstore/sigstore/pkg/signature/options"
-	"github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp"
 )
 
 func TestSignaturesRef(t *testing.T) {
@@ -195,38 +194,36 @@ func TestVerifyBlob(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	tsChain, err := tsaClient.Timestamp.GetTimestampCertChain(nil)
+	certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(tsaClient.CertChain)
 	if err != nil {
-		t.Fatalf("unexpected error getting timestamp chain: %v", err)
+		t.Fatalf("unexpected error marshalling cert chain: %v", err)
 	}
 	expiredTSACertChainPath := filepath.Join(td, "exptsacertchain.pem")
-	if err := os.WriteFile(expiredTSACertChainPath, []byte(tsChain.Payload), 0644); err != nil {
+	if err := os.WriteFile(expiredTSACertChainPath, certChainPEM, 0644); err != nil {
 		t.Fatal(err)
 	}
-	var tsRespBytes bytes.Buffer
-	_, err = tsaClient.Timestamp.GetTimestampResponse(&timestamp.GetTimestampResponseParams{}, &tsRespBytes)
+	tsr, err := tsaClient.GetTimestampResponse(nil)
 	if err != nil {
 		t.Fatalf("unable to generate a timestamp response: %v", err)
 	}
-	rfc3161Timestamp := &bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsRespBytes.Bytes()}
+	rfc3161Timestamp := &bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsr}
 	expiredTSPath := writeTimestampFile(t, td, rfc3161Timestamp, "expiredrfc3161TS.json")
 	tsaClient, err = mock.NewTSAClient(unexpiredTSAOpts)
 	if err != nil {
 		t.Fatal(err)
 	}
-	tsRespBytes.Reset()
-	_, err = tsaClient.Timestamp.GetTimestampResponse(&timestamp.GetTimestampResponseParams{}, &tsRespBytes)
+	tsr, err = tsaClient.GetTimestampResponse(nil)
 	if err != nil {
 		t.Fatalf("unable to generate a timestamp response: %v", err)
 	}
-	rfc3161Timestamp = &bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsRespBytes.Bytes()}
+	rfc3161Timestamp = &bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsr}
 	unexpiredTSPath := writeTimestampFile(t, td, rfc3161Timestamp, "unexpiredrfc3161TS.json")
-	tsChain, err = tsaClient.Timestamp.GetTimestampCertChain(nil)
+	certChainPEM, err = cryptoutils.MarshalCertificatesToPEM(tsaClient.CertChain)
 	if err != nil {
-		t.Fatalf("unexpected error getting timestamp chain: %v", err)
+		t.Fatalf("unexpected error marshalling cert chain: %v", err)
 	}
 	unexpiredTSACertChainPath := filepath.Join(td, "unexptsacertchain.pem")
-	if err := os.WriteFile(unexpiredTSACertChainPath, []byte(tsChain.Payload), 0644); err != nil {
+	if err := os.WriteFile(unexpiredTSACertChainPath, certChainPEM, 0644); err != nil {
 		t.Fatal(err)
 	}
 
@@ -1073,20 +1070,19 @@ func TestVerifyBlobCmdWithBundle(t *testing.T) {
 		if err != nil {
 			t.Fatal(err)
 		}
-		tsChain, err := tsaClient.Timestamp.GetTimestampCertChain(nil)
+		certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(tsaClient.CertChain)
 		if err != nil {
-			t.Fatalf("unexpected error getting timestamp chain: %v", err)
+			t.Fatalf("unexpected error marshalling cert chain: %v", err)
 		}
 		tsaCertChainPath := filepath.Join(keyless.td, "tsacertchain.pem")
-		if err := os.WriteFile(tsaCertChainPath, []byte(tsChain.Payload), 0644); err != nil {
+		if err := os.WriteFile(tsaCertChainPath, certChainPEM, 0644); err != nil {
 			t.Fatal(err)
 		}
-		var tsRespBytes bytes.Buffer
-		_, err = tsaClient.Timestamp.GetTimestampResponse(&timestamp.GetTimestampResponseParams{}, &tsRespBytes)
+		tsr, err := tsaClient.GetTimestampResponse(nil)
 		if err != nil {
 			t.Fatalf("unable to generate a timestamp response: %v", err)
 		}
-		rfc3161Timestamp := &bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsRespBytes.Bytes()}
+		rfc3161Timestamp := &bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsr}
 		tsPath := writeTimestampFile(t, keyless.td, rfc3161Timestamp, "rfc3161TS.json")
 
 		entry := genRekorEntry(t, hashedrekord.KIND, hashedrekord.New().DefaultVersion(), []byte(blob), leafPemCert, sig)
diff --git a/cmd/cosign/errors/error_wrap_test.go b/cmd/cosign/errors/error_wrap_test.go
new file mode 100644
index 00000000..e9559460
--- /dev/null
+++ b/cmd/cosign/errors/error_wrap_test.go
@@ -0,0 +1,51 @@
+//
+// Copyright 2021 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+import (
+	"errors"
+	"testing"
+
+	verificationError "github.com/sigstore/cosign/v2/pkg/cosign"
+)
+
+func TestWrapWithVerificationError(t *testing.T) {
+	ve := &verificationError.VerificationError{}
+	ve.SetErrorType(verificationError.ErrNoMatchingSignaturesType)
+	err := WrapError(ve)
+
+	var cosignError *CosignError
+	if errors.As(err, &cosignError) {
+		if cosignError.ExitCode() != NoMatchingSignature {
+			t.Fatalf("verification error unsuccessfully wrapped")
+		}
+		t.Logf("verification error successfully wrapped and exit code returned")
+	}
+}
+
+func TestWrapWithGenericCosignError(t *testing.T) {
+	errorText := "i am a generic cosign error"
+	err := WrapError(errors.New(errorText))
+
+	var cosignError *CosignError
+	if errors.As(err, &cosignError) {
+		if cosignError.ExitCode() == 1 && cosignError.Message == errorText {
+			t.Logf("generic cosign error successfully returned")
+			return
+		}
+		t.Fatalf("generic cosign error unsuccessfully returned")
+	}
+}
diff --git a/cmd/cosign/errors/exit_code_lookup_test.go b/cmd/cosign/errors/exit_code_lookup_test.go
new file mode 100644
index 00000000..d9e58461
--- /dev/null
+++ b/cmd/cosign/errors/exit_code_lookup_test.go
@@ -0,0 +1,28 @@
+//
+// Copyright 2021 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package errors
+
+import (
+	"testing"
+)
+
+func TestDefaultExitCodeReturnIfErrorTypeDoesNotExist(t *testing.T) {
+	exitCode := LookupExitCodeForErrorType("I do not exist as an error type")
+	if exitCode != 1 {
+		t.Fatalf("default exit code not returned when an error type doesn't exist. default should be 1")
+	}
+	t.Logf("Correct default exit code returned")
+}
diff --git a/doc/cosign_attest-blob.md b/doc/cosign_attest-blob.md
index 599b3277..b3989a63 100644
--- a/doc/cosign_attest-blob.md
+++ b/doc/cosign_attest-blob.md
@@ -53,7 +53,7 @@ cosign attest-blob [flags]
       --rfc3161-timestamp-bundle string   path to an RFC 3161 timestamp bundle FILE
       --sk                                whether to use a hardware security key
       --slot string                       security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management)
-      --timestamp-server-url string       url to the Timestamp RFC3161 server, default none
+      --timestamp-server-url string       url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr
       --tlog-upload                       whether or not to upload to the tlog (default true)
       --type string                       specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom")
   -y, --yes                               skip confirmation prompts for non-destructive operations
diff --git a/doc/cosign_attest.md b/doc/cosign_attest.md
index d50c8030..babeae6f 100644
--- a/doc/cosign_attest.md
+++ b/doc/cosign_attest.md
@@ -63,7 +63,7 @@ cosign attest [flags]
       --replace                                                                                  
       --sk                                                                                       whether to use a hardware security key
       --slot string                                                                              security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management)
-      --timestamp-server-url string                                                              url to the Timestamp RFC3161 server, default none
+      --timestamp-server-url string                                                              url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr
       --tlog-upload                                                                              whether or not to upload to the tlog (default true)
       --type string                                                                              specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom")
   -y, --yes                                                                                      skip confirmation prompts for non-destructive operations
diff --git a/pkg/cosign/attestation/attestation.go b/pkg/cosign/attestation/attestation.go
index 9c16393a..52a20080 100644
--- a/pkg/cosign/attestation/attestation.go
+++ b/pkg/cosign/attestation/attestation.go
@@ -30,10 +30,10 @@ import (
 
 const (
 	// CosignCustomProvenanceV01 specifies the type of the Predicate.
-	CosignCustomProvenanceV01 = "cosign.sigstore.dev/attestation/v1"
+	CosignCustomProvenanceV01 = "https://cosign.sigstore.dev/attestation/v1"
 
 	// CosignVulnProvenanceV01 specifies the type of VulnerabilityScan Predicate
-	CosignVulnProvenanceV01 = "cosign.sigstore.dev/attestation/vuln/v1"
+	CosignVulnProvenanceV01 = "https://cosign.sigstore.dev/attestation/vuln/v1"
 )
 
 // CosignPredicate specifies the format of the Custom Predicate.
@@ -241,9 +241,7 @@ func generateSPDXStatement(rawPayload []byte, digest string, repo string, parseJ
 	}
 	return in_toto.SPDXStatement{
 		StatementHeader: generateStatementHeader(digest, repo, in_toto.PredicateSPDX),
-		Predicate: CosignPredicate{
-			Data: data,
-		},
+		Predicate:       data,
 	}, nil
 }
 
@@ -254,9 +252,7 @@ func generateCycloneDXStatement(rawPayload []byte, digest string, repo string) (
 	}
 	return in_toto.SPDXStatement{
 		StatementHeader: generateStatementHeader(digest, repo, in_toto.PredicateCycloneDX),
-		Predicate: CosignPredicate{
-			Data: data,
-		},
+		Predicate:       data,
 	}, nil
 }
 
diff --git a/pkg/cosign/errors_test.go b/pkg/cosign/errors_test.go
index 357db7b4..8d6520a9 100644
--- a/pkg/cosign/errors_test.go
+++ b/pkg/cosign/errors_test.go
@@ -22,10 +22,8 @@ import (
 
 func TestErrors(t *testing.T) {
 	for _, want := range []error{
-		ErrNoMatchingAttestations,
-		ErrNoMatchingSignatures,
 		NewVerificationError("not a constant %d", 3),
-		fmt.Errorf("wrapped errors: %w", ErrNoMatchingSignatures),
+		NewVerificationError("not a string %s", "i am a string"),
 	} {
 		t.Run(want.Error(), func(t *testing.T) {
 			verr := &VerificationError{}
diff --git a/pkg/cosign/verifiers_test.go b/pkg/cosign/verifiers_test.go
index 5a355e0f..81633dcb 100644
--- a/pkg/cosign/verifiers_test.go
+++ b/pkg/cosign/verifiers_test.go
@@ -25,7 +25,7 @@ import (
 The following JSON is the payload in valid attestation:
 {
   "_type": "https://in-toto.io/Statement/v0.1",
-  "predicateType": "cosign.sigstore.dev/attestation/v1",
+  "predicateType": "https://cosign.sigstore.dev/attestation/v1",
   "subject": [
     {
       "name": "registry.local:5000/knative/demo",
diff --git a/pkg/cosign/verify_test.go b/pkg/cosign/verify_test.go
index 3141516b..69424d97 100644
--- a/pkg/cosign/verify_test.go
+++ b/pkg/cosign/verify_test.go
@@ -536,12 +536,12 @@ func TestVerifyImageSignatureWithSigVerifierAndTSA(t *testing.T) {
 	payloadSigner := payload.NewSigner(sv)
 	testSigner := tsa.NewSigner(payloadSigner, client)
 
-	chain, err := client.Timestamp.GetTimestampCertChain(nil)
+	certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(client.CertChain)
 	if err != nil {
-		t.Fatalf("unexpected error getting timestamp chain: %v", err)
+		t.Fatalf("unexpected error marshalling cert chain: %v", err)
 	}
 
-	leaves, intermediates, roots, err := tsa.SplitPEMCertificateChain([]byte(chain.Payload))
+	leaves, intermediates, roots, err := tsa.SplitPEMCertificateChain(certChainPEM)
 	if err != nil {
 		t.Fatal("error splitting response into certificate chain")
 	}
@@ -582,12 +582,12 @@ func TestVerifyImageSignatureWithSigVerifierAndRekorTSA(t *testing.T) {
 	payloadSigner := payload.NewSigner(sv)
 	tsaSigner := tsa.NewSigner(payloadSigner, client)
 
-	chain, err := client.Timestamp.GetTimestampCertChain(nil)
+	certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(client.CertChain)
 	if err != nil {
-		t.Fatalf("unexpected error getting timestamp chain: %v", err)
+		t.Fatalf("unexpected error marshalling cert chain: %v", err)
 	}
 
-	leaves, intermediates, roots, err := tsa.SplitPEMCertificateChain([]byte(chain.Payload))
+	leaves, intermediates, roots, err := tsa.SplitPEMCertificateChain(certChainPEM)
 	if err != nil {
 		t.Fatal("error splitting response into certificate chain")
 	}
@@ -1378,12 +1378,13 @@ func TestVerifyRFC3161Timestamp(t *testing.T) {
 		t.Fatalf("unexpected error creating timestamp: %v", err)
 	}
 	rfc3161TS := bundle.RFC3161Timestamp{SignedRFC3161Timestamp: tsBytes}
-	chain, err := client.Timestamp.GetTimestampCertChain(nil)
+
+	certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(client.CertChain)
 	if err != nil {
-		t.Fatalf("unexpected error getting timestamp chain: %v", err)
+		t.Fatalf("unexpected error marshalling cert chain: %v", err)
 	}
 
-	leaves, intermediates, roots, err := tsa.SplitPEMCertificateChain([]byte(chain.Payload))
+	leaves, intermediates, roots, err := tsa.SplitPEMCertificateChain(certChainPEM)
 	if err != nil {
 		t.Fatal("error splitting response into certificate chain")
 	}
diff --git a/pkg/policy/attestation_test.go b/pkg/policy/attestation_test.go
index 4d85fbcf..c8be3712 100644
--- a/pkg/policy/attestation_test.go
+++ b/pkg/policy/attestation_test.go
@@ -150,13 +150,13 @@ func TestAttestationToPayloadJson(t *testing.T) {
 		case "custom":
 			var intoto in_toto.Statement
 			if err := json.Unmarshal(jsonBytes, &intoto); err != nil {
-				t.Fatal("Wanted custom statement, can't unmarshal to it: ", err)
+				t.Fatalf("[%s] Wanted custom statement, can't unmarshal to it: %v", fileName, err)
 			}
 			checkPredicateType(t, attestation.CosignCustomProvenanceV01, intoto.PredicateType)
 		case "vuln":
 			var vulnStatement attestation.CosignVulnStatement
 			if err := json.Unmarshal(jsonBytes, &vulnStatement); err != nil {
-				t.Fatal("Wanted vuln statement, can't unmarshal to it: ", err)
+				t.Fatalf("[%s] Wanted vuln statement, can't unmarshal to it: %v", fileName, err)
 			}
 			checkPredicateType(t, attestation.CosignVulnProvenanceV01, vulnStatement.PredicateType)
 		case "default":
diff --git a/pkg/policy/eval_test.go b/pkg/policy/eval_test.go
index 8ebacfa3..eb854f9f 100644
--- a/pkg/policy/eval_test.go
+++ b/pkg/policy/eval_test.go
@@ -25,7 +25,7 @@ const (
 	customAttestation = `
 	{
 		"_type": "https://in-toto.io/Statement/v0.1",
-		"predicateType": "cosign.sigstore.dev/attestation/v1",
+		"predicateType": "https://cosign.sigstore.dev/attestation/v1",
 		"subject": [
 		  {
 			"name": "registry.local:5000/policy-controller/demo",
@@ -43,7 +43,7 @@ const (
 	vulnAttestation = `
 	{
 		"_type": "https://in-toto.io/Statement/v0.1",
-		"predicateType": "cosign.sigstore.dev/attestation/vuln/v1",
+		"predicateType": "https://cosign.sigstore.dev/attestation/vuln/v1",
 		"subject": [
 		  {
 			"name": "registry.local:5000/policy-controller/demo",
@@ -93,20 +93,20 @@ func TestEvalPolicy(t *testing.T) {
 		name:       "custom attestation, mismatched predicateType",
 		json:       customAttestation,
 		policyType: "cue",
-		policyFile: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`,
+		policyFile: `predicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"`,
 		wantErr:    true,
-		wantErrSub: `conflicting values "cosign.sigstore.dev/attestation/v1" and "cosign.sigstore.dev/attestation/vuln/v1"`,
+		wantErrSub: `conflicting values "https://cosign.sigstore.dev/attestation/v1" and "https://cosign.sigstore.dev/attestation/vuln/v1"`,
 	}, {
 		name:       "custom attestation, predicateType and data checks out",
 		json:       customAttestation,
 		policyType: "cue",
-		policyFile: `predicateType: "cosign.sigstore.dev/attestation/v1"
+		policyFile: `predicateType: "https://cosign.sigstore.dev/attestation/v1"
 		predicate: Data: "foobar e2e test"`,
 	}, {
 		name:       "custom attestation, data mismatch",
 		json:       customAttestation,
 		policyType: "cue",
-		policyFile: `predicateType: "cosign.sigstore.dev/attestation/v1"
+		policyFile: `predicateType: "https://cosign.sigstore.dev/attestation/v1"
 		predicate: Data: "invalid data here"`,
 		wantErr:    true,
 		wantErrSub: `predicate.Data: conflicting values "foobar e2e test" and "invalid data here"`,
@@ -114,7 +114,7 @@ func TestEvalPolicy(t *testing.T) {
 		name:       "vuln attestation, wrong invocation url",
 		json:       vulnAttestation,
 		policyType: "cue",
-		policyFile: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"
+		policyFile: `predicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"
 		predicate: invocation: uri: "invocation.example.com/wrong-url-here"`,
 		wantErr:    true,
 		wantErrSub: `conflicting values "invocation.example.com/cosign-testing" and "invocation.example.com/wrong-url-here"`,
@@ -122,7 +122,7 @@ func TestEvalPolicy(t *testing.T) {
 		name:       "vuln attestation, checks out",
 		json:       vulnAttestation,
 		policyType: "cue",
-		policyFile: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"
+		policyFile: `predicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"
 		predicate: invocation: uri: "invocation.example.com/cosign-testing"`,
 	}, {
 		name:       "cluster image policy main policy, checks out",
diff --git a/pkg/policy/testdata/valid/custom b/pkg/policy/testdata/valid/custom
index d05cabaa..c4a14c7b 100644
--- a/pkg/policy/testdata/valid/custom
+++ b/pkg/policy/testdata/valid/custom
@@ -1,1 +1,1 @@
-{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJjb3NpZ24uc2lnc3RvcmUuZGV2L2F0dGVzdGF0aW9uL3YxIiwic3ViamVjdCI6W3sibmFtZSI6InJlZ2lzdHJ5LmxvY2FsOjUwMDAva25hdGl2ZS9kZW1vIiwiZGlnZXN0Ijp7InNoYTI1NiI6IjZjNmZkNmE0MTE1YzZlOTk4ZmYzNTdjZDkxNDY4MDkzMWJiOWE2YzFhN2NkNWY1Y2IyZjVlMWMwOTMyYWI2ZWQifX1dLCJwcmVkaWNhdGUiOnsiRGF0YSI6ImZvb2JhciB0ZXN0IGF0dGVzdGF0aW9uIiwiVGltZXN0YW1wIjoiMjAyMi0wNC0wN1QxOToyMjoyNVoifX0=","signatures":[{"keyid":"","sig":"MEUCIQC/slGQVpRKgw4Jo8tcbgo85WNG/FOJfxcvQFvTEnG9swIgP4LeOmID+biUNwLLeylBQpAEgeV6GVcEpyG6r8LVnfY="}]}
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2Nvc2lnbi5zaWdzdG9yZS5kZXYvYXR0ZXN0YXRpb24vdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicmVnaXN0cnkubG9jYWw6NTAwMC9rbmF0aXZlL2RlbW8iLCJkaWdlc3QiOnsic2hhMjU2IjoiNmM2ZmQ2YTQxMTVjNmU5OThmZjM1N2NkOTE0NjgwOTMxYmI5YTZjMWE3Y2Q1ZjVjYjJmNWUxYzA5MzJhYjZlZCJ9fV0sInByZWRpY2F0ZSI6eyJEYXRhIjoiZm9vYmFyIHRlc3QgYXR0ZXN0YXRpb24iLCJUaW1lc3RhbXAiOiIyMDIyLTA0LTA3VDE5OjIyOjI1WiJ9fQ==","signatures":[{"keyid":"","sig":"MEUCIQC/slGQVpRKgw4Jo8tcbgo85WNG/FOJfxcvQFvTEnG9swIgP4LeOmID+biUNwLLeylBQpAEgeV6GVcEpyG6r8LVnfY="}]}
diff --git a/pkg/policy/testdata/valid/vuln b/pkg/policy/testdata/valid/vuln
index 2a38ba9d..0d5857ac 100644
--- a/pkg/policy/testdata/valid/vuln
+++ b/pkg/policy/testdata/valid/vuln
@@ -1,1 +1,1 @@
-{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJjb3NpZ24uc2lnc3RvcmUuZGV2L2F0dGVzdGF0aW9uL3Z1bG4vdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicmVnaXN0cnkubG9jYWw6NTAwMC9rbmF0aXZlL2RlbW8iLCJkaWdlc3QiOnsic2hhMjU2IjoiM2MxOWFhOTgwYTljNTcwOWEyYzk2YzJkMDc3OWZlYmY2ZTVlNDUzYjkyYjE3MmNlODRjYjg1ZmRhZjY5NTM3MyJ9fV0sInByZWRpY2F0ZSI6eyJpbnZvY2F0aW9uIjp7InBhcmFtZXRlcnMiOm51bGwsInVyaSI6IiIsImV2ZW50X2lkIjoiIiwiYnVpbGRlci5pZCI6IiJ9LCJzY2FubmVyIjp7InVyaSI6IiIsInZlcnNpb24iOiIiLCJkYiI6eyJ1cmkiOiIiLCJ2ZXJzaW9uIjoiIn0sInJlc3VsdCI6bnVsbH0sIm1ldGFkYXRhIjp7InNjYW5TdGFydGVkT24iOiIwMDAxLTAxLTAxVDAwOjAwOjAwWiIsInNjYW5GaW5pc2hlZE9uIjoiMDAwMS0wMS0wMVQwMDowMDowMFoifX19","signatures":[{"keyid":"","sig":"MEUCIHE9QkUy+d6uFwae0LSH2Fgy99na3jQvaYMU6qj5dzbFAiEA0uKmqGY1ZHoQZsd0BR4Ug0c8d+sHT0hPcxA61o4DKlM="}]}
+{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2Nvc2lnbi5zaWdzdG9yZS5kZXYvYXR0ZXN0YXRpb24vdnVsbi92MSIsInN1YmplY3QiOlt7Im5hbWUiOiJyZWdpc3RyeS5sb2NhbDo1MDAwL2tuYXRpdmUvZGVtbyIsImRpZ2VzdCI6eyJzaGEyNTYiOiIzYzE5YWE5ODBhOWM1NzA5YTJjOTZjMmQwNzc5ZmViZjZlNWU0NTNiOTJiMTcyY2U4NGNiODVmZGFmNjk1MzczIn19XSwicHJlZGljYXRlIjp7Imludm9jYXRpb24iOnsicGFyYW1ldGVycyI6bnVsbCwidXJpIjoiIiwiZXZlbnRfaWQiOiIiLCJidWlsZGVyLmlkIjoiIn0sInNjYW5uZXIiOnsidXJpIjoiIiwidmVyc2lvbiI6IiIsImRiIjp7InVyaSI6IiIsInZlcnNpb24iOiIifSwicmVzdWx0IjpudWxsfSwibWV0YWRhdGEiOnsic2NhblN0YXJ0ZWRPbiI6IjAwMDEtMDEtMDFUMDA6MDA6MDBaIiwic2NhbkZpbmlzaGVkT24iOiIwMDAxLTAxLTAxVDAwOjAwOjAwWiJ9fX0=","signatures":[{"keyid":"","sig":"MEUCIHE9QkUy+d6uFwae0LSH2Fgy99na3jQvaYMU6qj5dzbFAiEA0uKmqGY1ZHoQZsd0BR4Ug0c8d+sHT0hPcxA61o4DKlM="}]}
diff --git a/specs/COSIGN_VULN_ATTESTATION_SPEC.md b/specs/COSIGN_VULN_ATTESTATION_SPEC.md
index 38e246d9..03b688cf 100644
--- a/specs/COSIGN_VULN_ATTESTATION_SPEC.md
+++ b/specs/COSIGN_VULN_ATTESTATION_SPEC.md
@@ -21,7 +21,7 @@ And the final format for this is defined as follows:
     }
   ],
   // Predicate:
-  "predicateType": "cosign.sigstore.dev/attestation/vuln/v1",
+  "predicateType": "https://cosign.sigstore.dev/attestation/vuln/v1",
   "predicate": {
     "invocation": {
       "parameters": [],
diff --git a/test/e2e_test.go b/test/e2e_test.go
index abe9b1cc..ba0277ac 100644
--- a/test/e2e_test.go
+++ b/test/e2e_test.go
@@ -260,8 +260,8 @@ func TestAttestVerifySPDXJSON(t *testing.T) {
 	attestVerify(t,
 		"spdxjson",
 		string(attestationBytes),
-		`predicate: Data: spdxVersion: "SPDX-2.2"`,
-		`predicate: Data: spdxVersion: "SPDX-9.9"`,
+		`predicate: spdxVersion: "SPDX-2.2"`,
+		`predicate: spdxVersion: "SPDX-9.9"`,
 	)
 }
 
@@ -273,8 +273,8 @@ func TestAttestVerifyCycloneDXJSON(t *testing.T) {
 	attestVerify(t,
 		"cyclonedx",
 		string(attestationBytes),
-		`predicate: Data: specVersion: "1.4"`,
-		`predicate: Data: specVersion: "7.7"`,
+		`predicate: specVersion: "1.4"`,
+		`predicate: specVersion: "7.7"`,
 	)
 }
 
@@ -768,7 +768,7 @@ func TestAttestationRFC3161Timestamp(t *testing.T) {
 		PredicatePath: slsaAttestationPath,
 		PredicateType: "slsaprovenance",
 		Timeout:       30 * time.Second,
-		TSAServerURL:  server.URL,
+		TSAServerURL:  server.URL + "/api/v1/timestamp",
 		TlogUpload:    false,
 	}
 	must(attestCommand.Exec(ctx, imgName), t)
@@ -923,7 +923,7 @@ func TestRFC3161Timestamp(t *testing.T) {
 	ko := options.KeyOpts{
 		KeyRef:       privKeyPath,
 		PassFunc:     passFunc,
-		TSAServerURL: server.URL,
+		TSAServerURL: server.URL + "/api/v1/timestamp",
 	}
 	so := options.SignOptions{
 		Upload:     true,
@@ -977,7 +977,7 @@ func TestRekorBundleAndRFC3161Timestamp(t *testing.T) {
 	ko := options.KeyOpts{
 		KeyRef:           privKeyPath,
 		PassFunc:         passFunc,
-		TSAServerURL:     server.URL,
+		TSAServerURL:     server.URL + "/api/v1/timestamp",
 		RekorURL:         rekorURL,
 		SkipConfirmation: true,
 	}
@@ -1220,10 +1220,11 @@ func TestSignBlobBundle(t *testing.T) {
 
 	// Now sign the blob with one key
 	ko := options.KeyOpts{
-		KeyRef:     privKeyPath1,
-		PassFunc:   passFunc,
-		BundlePath: bundlePath,
-		RekorURL:   rekorURL,
+		KeyRef:           privKeyPath1,
+		PassFunc:         passFunc,
+		BundlePath:       bundlePath,
+		RekorURL:         rekorURL,
+		SkipConfirmation: true,
 	}
 	if _, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", false); err != nil {
 		t.Fatal(err)
@@ -1305,8 +1306,9 @@ func TestSignBlobRFC3161TimestampBundle(t *testing.T) {
 		PassFunc:             passFunc,
 		BundlePath:           bundlePath,
 		RFC3161TimestampPath: tsPath,
-		TSAServerURL:         server.URL,
+		TSAServerURL:         server.URL + "/api/v1/timestamp",
 		RekorURL:             rekorURL,
+		SkipConfirmation:     true,
 	}
 	if _, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", false); err != nil {
 		t.Fatal(err)
@@ -1452,6 +1454,11 @@ func TestUploadDownload(t *testing.T) {
 		signatureType attach.SignatureArgType
 		expectedErr   bool
 	}{
+		"stdin containing signature": {
+			signature:     "testsignatureraw",
+			signatureType: attach.StdinSignature,
+			expectedErr:   false,
+		},
 		"file containing signature": {
 			signature:     "testsignaturefile",
 			signatureType: attach.FileSignature,
@@ -1460,7 +1467,7 @@ func TestUploadDownload(t *testing.T) {
 		"raw signature as argument": {
 			signature:     "testsignatureraw",
 			signatureType: attach.RawSignature,
-			expectedErr:   false,
+			expectedErr:   true,
 		},
 		"empty signature as argument": {
 			signature:     "",
@@ -1476,10 +1483,14 @@ func TestUploadDownload(t *testing.T) {
 			payload := "testpayload"
 			payloadPath := mkfile(payload, td, t)
 			signature := base64.StdEncoding.EncodeToString([]byte(testCase.signature))
+			restoreStdin := func() {}
 
 			var sigRef string
 			if testCase.signatureType == attach.FileSignature {
 				sigRef = mkfile(signature, td, t)
+			} else if testCase.signatureType == attach.StdinSignature {
+				sigRef = "-"
+				restoreStdin = mockStdin(signature, td, t)
 			} else {
 				sigRef = signature
 			}
@@ -1491,6 +1502,7 @@ func TestUploadDownload(t *testing.T) {
 			} else {
 				must(err, t)
 			}
+			restoreStdin()
 
 			// Now download it!
 			se, err := ociremote.SignedEntity(ref, ociremote.WithRemoteOptions(registryClientOpts(ctx)...))
@@ -1716,7 +1728,7 @@ func TestAttachSBOM(t *testing.T) {
 	out.Reset()
 
 	// Upload it!
-	must(attach.SBOMCmd(ctx, options.RegistryOptions{}, "./testdata/bom-go-mod.spdx", "spdx", imgName), t)
+	must(attach.SBOMCmd(ctx, options.RegistryOptions{}, options.RegistryExperimentalOptions{}, "./testdata/bom-go-mod.spdx", "spdx", imgName), t)
 
 	sboms, err := download.SBOMCmd(ctx, options.RegistryOptions{}, options.SBOMDownloadOptions{}, imgName, &out)
 	if err != nil {
@@ -1757,6 +1769,97 @@ func TestAttachSBOM(t *testing.T) {
 	mustErr(verify(pubKeyPath2, imgName, true, nil, "sbom"), t)
 }
 
+func TestAttachSBOM_bom_flag(t *testing.T) {
+	repo, stop := reg(t)
+	defer stop()
+	td := t.TempDir()
+	ctx := context.Background()
+	bomData, err := os.ReadFile("./testdata/bom-go-mod.spdx")
+	must(err, t)
+
+	testCases := map[string]struct {
+		bom         string
+		bomType     attach.SignatureArgType
+		expectedErr bool
+	}{
+		"stdin containing bom": {
+			bom:         string(bomData),
+			bomType:     attach.StdinSignature,
+			expectedErr: false,
+		},
+		"file containing bom": {
+			bom:         string(bomData),
+			bomType:     attach.FileSignature,
+			expectedErr: false,
+		},
+		"raw bom as argument": {
+			bom:         string(bomData),
+			bomType:     attach.RawSignature,
+			expectedErr: true,
+		},
+		"empty bom as argument": {
+			bom:         "",
+			bomType:     attach.RawSignature,
+			expectedErr: true,
+		},
+	}
+
+	for testName, testCase := range testCases {
+		t.Run(testName, func(t *testing.T) {
+			imgName := path.Join(repo, "sbom-image")
+			img, _, cleanup := mkimage(t, imgName)
+			var sbomRef string
+			restoreStdin := func() {}
+			if testCase.bomType == attach.FileSignature {
+				sbomRef = mkfile(testCase.bom, td, t)
+			} else if testCase.bomType == attach.StdinSignature {
+				sbomRef = "-"
+				restoreStdin = mockStdin(testCase.bom, td, t)
+			} else {
+				sbomRef = testCase.bom
+			}
+
+			out := bytes.Buffer{}
+			_, errPl := download.SBOMCmd(ctx, options.RegistryOptions{}, options.SBOMDownloadOptions{Platform: "darwin/amd64"}, img.Name(), &out)
+			if errPl == nil {
+				t.Fatalf("Expected error when passing Platform to single arch image")
+			}
+			_, err := download.SBOMCmd(ctx, options.RegistryOptions{}, options.SBOMDownloadOptions{}, img.Name(), &out)
+			if err == nil {
+				t.Fatal("Expected error")
+			}
+			t.Log(out.String())
+			out.Reset()
+
+			// Upload it!
+			err = attach.SBOMCmd(ctx, options.RegistryOptions{}, options.RegistryExperimentalOptions{}, sbomRef, "spdx", imgName)
+			restoreStdin()
+
+			if testCase.expectedErr {
+				mustErr(err, t)
+			} else {
+				sboms, err := download.SBOMCmd(ctx, options.RegistryOptions{}, options.SBOMDownloadOptions{}, imgName, &out)
+				if err != nil {
+					t.Fatal(err)
+				}
+				t.Log(out.String())
+				if len(sboms) != 1 {
+					t.Fatalf("Expected one sbom, got %d", len(sboms))
+				}
+				want, err := os.ReadFile("./testdata/bom-go-mod.spdx")
+				if err != nil {
+					t.Fatal(err)
+				}
+				if diff := cmp.Diff(string(want), sboms[0]); diff != "" {
+					t.Errorf("diff: %s", diff)
+				}
+			}
+
+			cleanup()
+		})
+	}
+}
+
 func setenv(t *testing.T, k, v string) func() {
 	if err := os.Setenv(k, v); err != nil {
 		t.Fatalf("error setting env: %v", err)
@@ -1868,6 +1971,19 @@ func TestGetPublicKeyCustomOut(t *testing.T) {
 	equals(keys.PublicBytes, output, t)
 }
 
+func mockStdin(contents, td string, t *testing.T) func() {
+	origin := os.Stdin
+
+	p := mkfile(contents, td, t)
+	f, err := os.Open(p)
+	if err != nil {
+		t.Fatal(err)
+	}
+	os.Stdin = f
+
+	return func() { os.Stdin = origin }
+}
+
 func mkfile(contents, td string, t *testing.T) string {
 	f, err := os.CreateTemp(td, "")
 	if err != nil {
diff --git a/test/testdata/policies/cue-fails.cue b/test/testdata/policies/cue-fails.cue
index af557aef..9125860d 100644
--- a/test/testdata/policies/cue-fails.cue
+++ b/test/testdata/policies/cue-fails.cue
@@ -3,8 +3,8 @@ import "time"
 before: time.Parse(time.RFC3339, "2049-10-09T17:10:27Z")
 
 // Test with invalid predicate type. It should be this, so change it
-//predicateType: "cosign.sigstore.dev/attestation/v1"
-predicateType: "cosignnotreally.sigstore.dev/attestation/v1"
+//predicateType: "https://cosign.sigstore.dev/attestation/v1"
+predicateType: "https://cosignnotreally.sigstore.dev/attestation/v1"
 
 // The predicate must match the following constraints.
 predicate: {
diff --git a/test/testdata/policies/cue-vuln-fails.cue b/test/testdata/policies/cue-vuln-fails.cue
index 57d741ab..5f444ee7 100644
--- a/test/testdata/policies/cue-vuln-fails.cue
+++ b/test/testdata/policies/cue-vuln-fails.cue
@@ -5,7 +5,7 @@ before: time.Parse(time.RFC3339, "2022-04-01T17:10:27Z")
 after: time.Parse(time.RFC3339, "2022-03-09T17:10:27Z")
 
 // The predicateType field must match this string
-predicateType: "cosign.sigstore.dev/attestation/vuln/v1"
+predicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"
 
 predicate: {
   invocation: {
diff --git a/test/testdata/policies/cue-vuln-works.cue b/test/testdata/policies/cue-vuln-works.cue
index 79ea7108..cd62af31 100644
--- a/test/testdata/policies/cue-vuln-works.cue
+++ b/test/testdata/policies/cue-vuln-works.cue
@@ -4,7 +4,7 @@ before: time.Parse(time.RFC3339, "2022-04-15T17:10:27Z")
 after: time.Parse(time.RFC3339, "2022-03-09T17:10:27Z")
 
 // The predicateType field must match this string
-predicateType: "cosign.sigstore.dev/attestation/vuln/v1"
+predicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"
 
 predicate: {
   invocation: {
diff --git a/test/testdata/policies/cue-works.cue b/test/testdata/policies/cue-works.cue
index 20a159c3..6da50103 100644
--- a/test/testdata/policies/cue-works.cue
+++ b/test/testdata/policies/cue-works.cue
@@ -3,7 +3,7 @@ import "time"
 before: time.Parse(time.RFC3339, "2049-10-09T17:10:27Z")
 
 // The predicateType field must match this string
-predicateType: "cosign.sigstore.dev/attestation/v1"
+predicateType: "https://cosign.sigstore.dev/attestation/v1"
 
 // The predicate must match the following constraints.
 predicate: {