Showing preview only (865K chars total). Download the full file or copy to clipboard to get everything.
Repository: sigstore/sigstore-rs
Branch: main
Commit: 1485d8b140fc
Files: 165
Total size: 814.8 KB
Directory structure:
gitextract_mgzc87yz/
├── .cargo/
│ └── audit.toml
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── auto-publish-crates-upon-release.yml
│ ├── conformance.yml
│ ├── security-audit.yml
│ ├── tests.yml
│ └── zizmor.yml
├── .gitignore
├── .taplo.toml
├── CHANGELOG.md
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTORS.md
├── COPYRIGHT.txt
├── Cargo.toml
├── LICENSE
├── Makefile
├── README.md
├── clippy.toml
├── examples/
│ ├── README.md
│ ├── bundle/
│ │ ├── README.md
│ │ └── main.rs
│ ├── cosign/
│ │ ├── sign/
│ │ │ ├── README.md
│ │ │ └── main.rs
│ │ ├── trustroot/
│ │ │ └── main.rs
│ │ ├── verify/
│ │ │ ├── README.md
│ │ │ └── main.rs
│ │ ├── verify-blob/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ └── main.rs
│ │ └── verify-bundle/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── main.rs
│ │ └── run.sh
│ ├── fulcio/
│ │ └── cert/
│ │ └── main.rs
│ ├── key_interface/
│ │ ├── README.md
│ │ ├── key_pair_gen_and_export/
│ │ │ └── main.rs
│ │ ├── key_pair_gen_sign_verify/
│ │ │ └── main.rs
│ │ └── key_pair_import/
│ │ ├── ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key
│ │ ├── ECDSA_P256_ASN1_PRIVATE_DER.key
│ │ ├── ECDSA_P256_ASN1_PRIVATE_PEM.key
│ │ ├── ECDSA_P256_ASN1_PUBLIC_DER.pub
│ │ ├── ECDSA_P256_ASN1_PUBLIC_PEM.pub
│ │ └── main.rs
│ ├── openidflow/
│ │ ├── README.md
│ │ └── openidconnect/
│ │ └── main.rs
│ └── rekor/
│ ├── README.md
│ ├── create_log_entry/
│ │ └── main.rs
│ ├── get_log_entry_by_index/
│ │ └── main.rs
│ ├── get_log_entry_by_uuid/
│ │ └── main.rs
│ ├── get_log_info/
│ │ └── main.rs
│ ├── get_log_proof/
│ │ └── main.rs
│ ├── get_public_key/
│ │ └── main.rs
│ ├── merkle_proofs/
│ │ ├── consistency.rs
│ │ └── inclusion.rs
│ ├── search_index/
│ │ └── main.rs
│ └── search_log_query/
│ └── main.rs
├── rust-toolchain.toml
├── src/
│ ├── bundle/
│ │ ├── mod.rs
│ │ ├── models.rs
│ │ ├── sign.rs
│ │ └── verify/
│ │ ├── mod.rs
│ │ ├── models.rs
│ │ ├── policy.rs
│ │ └── verifier.rs
│ ├── cosign/
│ │ ├── bundle.rs
│ │ ├── client.rs
│ │ ├── client_builder.rs
│ │ ├── constants.rs
│ │ ├── constraint/
│ │ │ ├── annotation.rs
│ │ │ ├── mod.rs
│ │ │ └── signature.rs
│ │ ├── mod.rs
│ │ ├── payload/
│ │ │ ├── mod.rs
│ │ │ └── simple_signing.rs
│ │ ├── signature_layers.rs
│ │ └── verification_constraint/
│ │ ├── annotation_verifier.rs
│ │ ├── cert_subject_email_verifier.rs
│ │ ├── cert_subject_url_verifier.rs
│ │ ├── certificate_verifier.rs
│ │ ├── mod.rs
│ │ └── public_key_verifier.rs
│ ├── crypto/
│ │ ├── certificate.rs
│ │ ├── certificate_pool.rs
│ │ ├── keyring.rs
│ │ ├── merkle/
│ │ │ ├── mod.rs
│ │ │ ├── proof_verification.rs
│ │ │ └── rfc6962.rs
│ │ ├── mod.rs
│ │ ├── signing_key/
│ │ │ ├── ecdsa/
│ │ │ │ ├── ec.rs
│ │ │ │ └── mod.rs
│ │ │ ├── ed25519.rs
│ │ │ ├── kdf.rs
│ │ │ ├── mod.rs
│ │ │ └── rsa/
│ │ │ ├── keypair.rs
│ │ │ └── mod.rs
│ │ ├── transparency.rs
│ │ └── verification_key.rs
│ ├── errors.rs
│ ├── fulcio/
│ │ ├── mod.rs
│ │ ├── models.rs
│ │ └── oauth.rs
│ ├── lib.rs
│ ├── mock_client.rs
│ ├── oauth/
│ │ ├── http_client.rs
│ │ ├── mod.rs
│ │ ├── openidflow.rs
│ │ └── token.rs
│ ├── registry/
│ │ ├── config.rs
│ │ ├── mod.rs
│ │ ├── oci_caching_client.rs
│ │ ├── oci_client.rs
│ │ └── oci_reference.rs
│ ├── rekor/
│ │ ├── apis/
│ │ │ ├── configuration.rs
│ │ │ ├── entries_api.rs
│ │ │ ├── index_api.rs
│ │ │ ├── mod.rs
│ │ │ ├── pubkey_api.rs
│ │ │ └── tlog_api.rs
│ │ ├── mod.rs
│ │ └── models/
│ │ ├── alpine.rs
│ │ ├── alpine_all_of.rs
│ │ ├── checkpoint.rs
│ │ ├── consistency_proof.rs
│ │ ├── error.rs
│ │ ├── hashedrekord.rs
│ │ ├── hashedrekord_all_of.rs
│ │ ├── helm.rs
│ │ ├── helm_all_of.rs
│ │ ├── inactive_shard_log_info.rs
│ │ ├── inclusion_proof.rs
│ │ ├── intoto.rs
│ │ ├── intoto_all_of.rs
│ │ ├── jar.rs
│ │ ├── jar_all_of.rs
│ │ ├── log_entry.rs
│ │ ├── log_info.rs
│ │ ├── mod.rs
│ │ ├── proposed_entry.rs
│ │ ├── rekord.rs
│ │ ├── rekord_all_of.rs
│ │ ├── rfc3161.rs
│ │ ├── rfc3161_all_of.rs
│ │ ├── rpm.rs
│ │ ├── rpm_all_of.rs
│ │ ├── search_index.rs
│ │ ├── search_index_public_key.rs
│ │ ├── search_log_query.rs
│ │ ├── tuf.rs
│ │ └── tuf_all_of.rs
│ └── trust/
│ ├── mod.rs
│ └── sigstore/
│ ├── constants.rs
│ ├── mod.rs
│ └── transport.rs
├── tests/
│ ├── conformance/
│ │ ├── Cargo.toml
│ │ └── conformance.rs
│ └── data/
│ └── keys/
│ ├── cosign_generated_encrypted_empty_private.key
│ ├── ecdsa_encrypted_private.key
│ ├── ecdsa_private.key
│ ├── ed25519_encrypted_private.key
│ ├── ed25519_private.key
│ ├── rsa_encrypted_private.key
│ └── rsa_private.key
└── trust_root/
└── prod/
├── root.json
└── trusted_root.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .cargo/audit.toml
================================================
[advisories]
ignore = [
"RUSTSEC-2023-0071", # "Classic" RSA timing sidechannel attack from non-constant-time implementation.
# Okay for local use.
# https://rustsec.org/advisories/RUSTSEC-2023-0071.html
"RUSTSEC-2024-0370", # This is a warning about `proc-macro-errors` being unmaintained. It's a transitive dependency of `sigstore` and `oci-spec`.
]
================================================
FILE: .github/dependabot.yml
================================================
#
# 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.
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
cooldown:
default-days: 7
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
cooldown:
default-days: 7
================================================
FILE: .github/workflows/auto-publish-crates-upon-release.yml
================================================
name: Publish-Crate-Upon-Release
on:
release:
types: [published]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
publish-automatically:
name: Publish crates
runs-on: ubuntu-latest
permissions:
id-token: write # needed to get OpenID Connect token for authentication
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4
id: auth
- name: Rustup
run: |
rustup install stable
rustup override set stable
- name: publish crates
env:
CARGO_REGISTRY_TOKEN: "${{ steps.auth.outputs.token }}"
run: cargo publish
================================================
FILE: .github/workflows/conformance.yml
================================================
on: [workflow_dispatch]
name: Conformance Suite
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
conformance:
name: Check sigstore conformance
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Rustup
run: |
rustup install --profile minimal stable
rustup override set stable
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
cargo build --manifest-path=tests/conformance/Cargo.toml
- uses: sigstore/sigstore-conformance@main
with:
entrypoint: ${{ github.workspace }}/tests/conformance/target/debug/sigstore
================================================
FILE: .github/workflows/security-audit.yml
================================================
name: Security audit
on:
schedule:
- cron: "0 0 * * *"
push:
paths:
- "**/Cargo.toml"
- "**/Cargo.lock"
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
audit:
name: Audit for vulnerable crates
permissions:
checks: write # for rustsec/audit-check to create check
contents: read # for actions/checkout to fetch code
issues: write # for rustsec/audit-check to create issues
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Generate lockfile
run: cargo generate-lockfile
- uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/tests.yml
================================================
on: [push, pull_request]
name: Continuous integration
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
check:
name: Check features
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- uses: taiki-e/install-action@481c34c1cf3a84c68b5e46f4eccfc82af798415a # v2.75.23
with:
tool: cargo-hack
# cosign, full, mock-client, registry will ONLY compile with a *-tls feature
- run: |
cargo hack check --each-feature --skip cosign --skip full --skip mock-client --skip registry
check-native-tls:
name: Check native-tls features
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- uses: taiki-e/install-action@481c34c1cf3a84c68b5e46f4eccfc82af798415a # v2.75.23
with:
tool: cargo-hack
- run: |
cargo hack check --feature-powerset --features native-tls --skip wasm --skip test-registry --skip rustls-tls --skip rustls-tls-native-roots
check-rustls-tls:
name: Check rusttls-tls features
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- uses: taiki-e/install-action@481c34c1cf3a84c68b5e46f4eccfc82af798415a # v2.75.23
with:
tool: cargo-hack
- run: |
cargo hack check --feature-powerset --features rustls-tls --skip wasm --skip test-registry --skip native-tls
test-native-tls:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
cargo test --workspace --no-default-features --features full,native-tls,test-registry
test-rustls-tls:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
cargo test --workspace --no-default-features --features full,rustls-tls,test-registry
check-wasm:
name: Check wasm32-unknown-unknown target
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
with:
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
cargo check --no-default-features --features wasm --target wasm32-unknown-unknown
doc:
name: Build Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@351f82a4dc29e4159746a068ed925da17341219f # nightly
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
make doc
toml:
name: Toml format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
- uses: taiki-e/install-action@481c34c1cf3a84c68b5e46f4eccfc82af798415a # v2.75.23
with:
tool: taplo-cli
- run: |
taplo fmt --check
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
with:
components: rustfmt
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@e081816240890017053eacbb1bdf337761dc5582 # 1.95.0
with:
components: clippy
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: |
cargo clippy --workspace -- -D warnings
================================================
FILE: .github/workflows/zizmor.yml
================================================
name: 'zizmor: GitHub Actions Security Analysis'
on:
push:
branches: ["main"]
pull_request:
branches: ["**"]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
zizmor:
name: Zizmor
runs-on: ubuntu-24.04
permissions:
security-events: write # needed to create vulnerability alerts
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
with:
persona: pedantic
================================================
FILE: .gitignore
================================================
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# ide files
.idea
.vscode
================================================
FILE: .taplo.toml
================================================
exclude = [".cargo/audit.toml"]
[[rule]]
[rule.formatting]
indent_string = " "
reorder_arrays = true
reorder_keys = true
================================================
FILE: CHANGELOG.md
================================================
# v0.10.0
## What's Changed
- chore(deps): Update oci-distribution requirement from 0.10 to 0.11 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/343
- verify: init by @jleightcap in https://github.com/sigstore/sigstore-rs/pull/311
- chore(deps): Update rstest requirement from 0.18.1 to 0.19.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/351
- chore(deps): Bump actions/checkout from 4.1.2 to 4.1.5 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/360
- fix linter warning by @flavio in https://github.com/sigstore/sigstore-rs/pull/361
- chore(deps): Update cached requirement from 0.49.2 to 0.51.3 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/362
- chore(deps): Update webbrowser requirement from 0.8.12 to 1.0.1 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/359
- chore(deps): Bump actions/checkout from 4.1.5 to 4.1.6 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/363
- chore(deps): Update testcontainers requirement from 0.15 to 0.16 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/355
- chore(deps): change provider of cargo-audit GH action by @flavio in https://github.com/sigstore/sigstore-rs/pull/364
- fix docs by @flavio in https://github.com/sigstore/sigstore-rs/pull/366
- fix: allow ManualTrustRoot to have multiple rekor keys by @flavio in https://github.com/sigstore/sigstore-rs/pull/365
- build(deps): update testcontainers requirement from 0.16 to 0.17 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/368
- build(deps): update rstest requirement from 0.19.0 to 0.21.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/370
- build(deps): bump actions/checkout from 4.1.6 to 4.1.7 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/372
- build(deps): update testcontainers requirement from 0.17 to 0.18 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/371
- Signed Certificate Timestamp verification by @tnytown in https://github.com/sigstore/sigstore-rs/pull/326
- transparency: pull OID constants from `const-oid` by @tnytown in https://github.com/sigstore/sigstore-rs/pull/374
- build(deps): update testcontainers requirement from 0.18 to 0.19 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/375
- build(deps): update cached requirement from 0.51.3 to 0.52.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/377
- build(deps): update testcontainers requirement from 0.19 to 0.20 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/376
- build(deps): update cached requirement from 0.52.0 to 0.53.1 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/379
- build(deps): update rstest requirement from 0.21.0 to 0.22.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/383
- build(deps): update testcontainers requirement from 0.20 to 0.21 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/382
- build(deps): update testcontainers requirement from 0.21 to 0.22 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/386
- fix: Allow empty passwords for encrypted pem files by @gmpinder in https://github.com/sigstore/sigstore-rs/pull/381
- build(deps): update tough requirement from 0.17.1 to 0.18.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/389
- dependency cleanup by @flavio in https://github.com/sigstore/sigstore-rs/pull/390
- chore: update cargo audit ignore list by @flavio in https://github.com/sigstore/sigstore-rs/pull/387
## New Contributors
- @tnytown made their first contribution in https://github.com/sigstore/sigstore-rs/pull/326
- @gmpinder made their first contribution in https://github.com/sigstore/sigstore-rs/pull/381
**Full Changelog**: https://github.com/sigstore/sigstore-rs/compare/v0.9.0...v0.10.0
# v0.9.0
## What's Changed
- sign: init by @jleightcap in https://github.com/sigstore/sigstore-rs/pull/310
- cargo audit: ignore RUSTSEC-2023-0071 by @jleightcap in https://github.com/sigstore/sigstore-rs/pull/321
- chore(deps): Update json-syntax requirement from 0.9.6 to 0.10.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/319
- chore(deps): Update cached requirement from 0.46.0 to 0.47.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/323
- chore(deps): Update serial_test requirement from 2.0.0 to 3.0.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/322
- dep: update rustls-webpki, fold in pki_types by @jleightcap in https://github.com/sigstore/sigstore-rs/pull/324
- chore(deps): Update cached requirement from 0.47.0 to 0.48.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/325
- chore(deps): Update json-syntax requirement from 0.10.0 to 0.11.1 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/327
- chore(deps): Update cached requirement from 0.48.0 to 0.49.2 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/329
- chore(deps): Update json-syntax requirement from 0.11.1 to 0.12.2 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/330
- lint: fix lint error of chrono and tokio by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/334
- chore(deps): Update base64 requirement from 0.21.0 to 0.22.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/332
- The `Repository` trait and `ManualRepository` struct no longer require a feature flag by @tannaurus in https://github.com/sigstore/sigstore-rs/pull/331
- chore(deps): Bump actions/checkout from 4.1.1 to 4.1.2 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/336
- chore(deps): Update reqwest requirement from 0.11 to 0.12 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/341
- update tough dep by @astoycos in https://github.com/sigstore/sigstore-rs/pull/340
- Tag the 0.9.0 release by @flavio in https://github.com/sigstore/sigstore-rs/pull/342
## New Contributors
- @tannaurus made their first contribution in https://github.com/sigstore/sigstore-rs/pull/331
- @astoycos made their first contribution in https://github.com/sigstore/sigstore-rs/pull/340
**Full Changelog**: https://github.com/sigstore/sigstore-rs/compare/v0.8.0...v0.9.0
# v0.8.0
## What's Changed
- chore(deps): Update rstest requirement from 0.17.0 to 0.18.1 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/282
- chore(deps): do not enable default features of chrono by @flavio in https://github.com/sigstore/sigstore-rs/pull/286
- chore(deps): Update pem requirement from 2.0 to 3.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/289
- conformance: add conformance CLI and action by @jleightcap in https://github.com/sigstore/sigstore-rs/pull/287
- chore: fix clippy warnings by @flavio in https://github.com/sigstore/sigstore-rs/pull/292
- chore(deps): Bump actions/checkout from 3.5.3 to 3.6.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/291
- chore(deps): Update tough requirement from 0.13 to 0.14 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/290
- chore(deps): update to latest version of picky by @flavio in https://github.com/sigstore/sigstore-rs/pull/293
- chore(deps): Bump actions/checkout from 3.6.0 to 4.0.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/294
- chore: add repository link to Cargo metadata by @flavio in https://github.com/sigstore/sigstore-rs/pull/297
- chore(deps): Update cached requirement from 0.44.0 to 0.45.1 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/298
- chore(deps): Bump actions/checkout from 4.0.0 to 4.1.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/302
- chore(deps): Update cached requirement from 0.45.1 to 0.46.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/301
- chore(deps): Update testcontainers requirement from 0.14 to 0.15 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/303
- chore(deps): Bump actions/checkout from 4.1.0 to 4.1.1 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/304
- cosign/tuf: use trustroot by @jleightcap in https://github.com/sigstore/sigstore-rs/pull/305
- Fix broken tests, update deps by @flavio in https://github.com/sigstore/sigstore-rs/pull/313
## New Contributors
- @jleightcap made their first contribution in https://github.com/sigstore/sigstore-rs/pull/287
**Full Changelog**: https://github.com/sigstore/sigstore-rs/compare/v0.7.2...v0.8.0
# v0.7.2
## What's Changed
- chore(deps): Update cached requirement from 0.42.0 to 0.44.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/277
- chore(deps): Bump actions/checkout from 3.5.2 to 3.5.3 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/278
- chore(deps): update picky dependency by @flavio in https://github.com/sigstore/sigstore-rs/pull/279
**Full Changelog**: https://github.com/sigstore/sigstore-rs/compare/v0.7.1...v0.7.2
# v0.7.1
## What's Changed
- fix: ensure cosign client can be sent between threads by @flavio in https://github.com/sigstore/sigstore-rs/pull/275
**Full Changelog**: https://github.com/sigstore/sigstore-rs/compare/v0.7.0...v0.7.1
# v0.7.0
## What's Changed
- Fix typo in SignatureLayer::new doc comment by @danbev in https://github.com/sigstore/sigstore-rs/pull/170
- feat: replace example dependency docker_credential by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/172
- Clean up readme by @lukehinds in https://github.com/sigstore/sigstore-rs/pull/173
- chore(deps): Update rstest requirement from 0.15.0 to 0.16.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/174
- Fix typo in simple_signing.rs by @danbev in https://github.com/sigstore/sigstore-rs/pull/175
- Introduce SignedArtifactBundle by @danbev in https://github.com/sigstore/sigstore-rs/pull/171
- chore(deps): Update base64 requirement from 0.13.0 to 0.20.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/177
- chore(deps): Bump actions/checkout from 3.1.0 to 3.2.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/180
- chore(deps): Update serial_test requirement from 0.9.0 to 0.10.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/182
- chore(deps): Update cached requirement from 0.40.0 to 0.41.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/181
- Fix typo in SecretBoxCipher doc comment by @danbev in https://github.com/sigstore/sigstore-rs/pull/179
- chore(deps): Update cached requirement from 0.41.0 to 0.42.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/185
- chore(deps): Bump actions/checkout from 3.2.0 to 3.3.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/183
- chore(deps): Update base64 requirement from 0.20.0 to 0.21.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/184
- Add cosign verify-bundle example by @danbev in https://github.com/sigstore/sigstore-rs/pull/186
- Fix incorrect base64_signature doc comment by @danbev in https://github.com/sigstore/sigstore-rs/pull/188
- Fix typos in tuf/mod.rs by @danbev in https://github.com/sigstore/sigstore-rs/pull/195
- chore(deps): Update serial_test requirement from 0.10.0 to 1.0.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/200
- fix: show actual response status field by @ctron in https://github.com/sigstore/sigstore-rs/pull/197
- Update target -> target_name for consistency by @danbev in https://github.com/sigstore/sigstore-rs/pull/196
- fix: make the fields accessible by @ctron in https://github.com/sigstore/sigstore-rs/pull/202
- Add verify-bundle example to README.md by @danbev in https://github.com/sigstore/sigstore-rs/pull/203
- fix: make fields of hash accessible by @ctron in https://github.com/sigstore/sigstore-rs/pull/205
- Improve public key output and add file output by @Gronner in https://github.com/sigstore/sigstore-rs/pull/194
- Add TokenProvider::Static doc comment by @danbev in https://github.com/sigstore/sigstore-rs/pull/208
- Changed the type of LogEntry.body from String to Body by @Neccolini in https://github.com/sigstore/sigstore-rs/pull/207
- Fix errors/warnings reported by clippy by @danbev in https://github.com/sigstore/sigstore-rs/pull/210
- Add fine-grained features to control the compilation by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/189
- fix: bring tuf feature out of rekor and add related docs by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/211
- chore: update crypto deps by @flavio in https://github.com/sigstore/sigstore-rs/pull/204
- Replace `x509-parser` with `x509-cert` by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/212
- Fix: Wrong parameter order inside documentation example. by @vembacher in https://github.com/sigstore/sigstore-rs/pull/215
- Remove lines about timestamp in lib.rs by @naveensrinivasan in https://github.com/sigstore/sigstore-rs/pull/213
- Fix ed25519 version conflict by @vembacher in https://github.com/sigstore/sigstore-rs/pull/223
- Support compiling to wasm32 architectures by @lulf in https://github.com/sigstore/sigstore-rs/pull/221
- Fix link to contributor doc in readme by @oliviacrain in https://github.com/sigstore/sigstore-rs/pull/225
- refactor: derive `Clone` trait by @flavio in https://gitub.com/sigstore/sigstore-rs/pull/227
- fix: correct typo in verify/main.rs by @danbev in https://github.com/sigstore/sigstore-rs/pull/228
- chore(deps): Update tough requirement from 0.12 to 0.13 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/237
- chore(deps): Bump actions/checkout from 3.3.0 to 3.4.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/240
- dep: update picky version to git rid of `ring` by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/226
- chore(deps): Bump actions/checkout from 3.4.0 to 3.5.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/245
- fix: make LogEntry Body an enum by @danbev in https://github.com/sigstore/sigstore-rs/pull/244
- Add verify-blob example by @danbev in https://github.com/sigstore/sigstore-rs/pull/239
- Introduce Newtype `OciReference` into API for OCI image references. by @vembacher in https://github.com/sigstore/sigstore-rs/pull/216
- Swap over to using CDN to fetch TUF metadata by @haydentherapper in https://github.com/sigstore/sigstore-rs/pull/251
- chore(deps): Bump actions/checkout from 3.5.0 to 3.5.2 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/252
- upgrade 'der' to 0.7.5 by @dmitris in https://github.com/sigstore/sigstore-rs/pull/257
- remove unused 'clock' feature for chrono by @dmitris in https://github.com/sigstore/sigstore-rs/pull/258
- update pkcs1 from 0.4.0 to 0.7.5 by @dmitris in https://github.com/sigstore/sigstore-rs/pull/260
- use 2021 Rust edition by @dmitris in https://github.com/sigstore/sigstore-rs/pull/261
- chore(deps): Update serial_test requirement from 1.0.0 to 2.0.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/264
- update scrypt to 0.11.0, adapt for API change (fix #231) by @dmitris in https://github.com/sigstore/sigstore-rs/pull/268
- upgrade ed25519-dalek to 2.0.0-rc.2 by @dmitris in https://github.com/sigstore/sigstore-rs/pull/263
- chore(deps): Update openidconnect requirement from 2.3 to 3.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/265
- chore(deps): Update rstest requirement from 0.16.0 to 0.17.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/271
- Update crypto deps by @flavio in https://github.com/sigstore/sigstore-rs/pull/269
- Update create_log_entry example to create key pair. by @jvanz in https://github.com/sigstore/sigstore-rs/pull/206
## New Contributors
- @ctron made their first contribution in https://github.com/sigstore/sigstore-rs/pull/197
- @Gronner made their first contribution in https://github.com/sigstore/sigstore-rs/pull/194
- @Neccolini made their first contribution in https://github.com/sigstore/sigstore-rs/pull/207
- @vembacher made their first contribution in https://github.com/sigstore/sigstore-rs/pull/215
- @naveensrinivasan made their first contribution in https://github.com/sigstore/sigstore-rs/pull/213
- @lulf made their first contribution in https://github.com/sigstore/sigstore-rs/pull/221
- @oliviacrain made their first contribution in https://github.com/sigstore/sigstore-rs/pull/225
- @haydentherapper made their first contribution in https://github.com/sigstore/sigstore-rs/pull/251
- @dmitris made their first contribution in https://github.com/sigstore/sigstore-rs/pull/257
- @jvanz made their first contribution in https://github.com/sigstore/sigstore-rs/pull/206
**Full Changelog**: https://github.com/sigstore/sigstore-rs/compare/v0.6.0...v0.7.0h
# v0.6.0
## Fixes
- Fix typo in cosign/mod.rs doc comment by @danbev in https://github.com/sigstore/sigstore-rs/pull/148
- Fix typo in KeyPair trait doc comment by @danbev in https://github.com/sigstore/sigstore-rs/pull/149
- Update cached requirement from 0.39.0 to 0.40.0 by @dependabot in https://github.com/sigstore/sigstore-rs/pull/154
- Fix typos in PublicKeyVerifier doc comments by @danbev in https://github.com/sigstore/sigstore-rs/pull/155
- Fix: CI error for auto deref by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/160
- Fix typo and grammar in signature_layers.rs by @danbev in https://github.com/sigstore/sigstore-rs/pull/161
- Remove unused imports in examples/rekor by @danbev in https://github.com/sigstore/sigstore-rs/pull/162
- Update link to verification example by @danbev in https://github.com/sigstore/sigstore-rs/pull/156
- Fix typos in from_encrypted_pem doc comments by @danbev in https://github.com/sigstore/sigstore-rs/pull/164
- Fix typos in doc comments by @danbev in https://github.com/sigstore/sigstore-rs/pull/163
- Update path to fulcio-cert in verify example by @danbev in https://github.com/sigstore/sigstore-rs/pull/168
## Enhancements
- Add getter functions for LogEntry fields by @lkatalin in https://github.com/sigstore/sigstore-rs/pull/147
- Add TreeSize alias to Rekor by @avery-blanchard in https://github.com/sigstore/sigstore-rs/pull/151
- Updates for parsing hashedrekord LogEntry by @lkatalin in https://github.com/sigstore/sigstore-rs/pull/152
- Add certificate based verification by @flavio in https://github.com/sigstore/sigstore-rs/pull/159
- Add support for OCI Image signing (spec v1.0) by @Xynnn007 in https://github.com/sigstore/sigstore-rs/pull/158
## Contributors
- Avery Blanchard (@avery-blanchardmade)
- Daniel Bevenius (@danbev)
- Flavio Castelli (@flavio)
- Lily Sturmann (@lkatalin)
- Xynnn (@Xynnn007)
# v0.5.3
## Fixes
- rustls should not require openssl by (https://github.com/sigstore/sigstore-rs/pull/146)
## Others
- Rework Rekor module structure and enable doc tests (https://github.com/sigstore/sigstore-rs/pull/145)
## Contributors
- Flavio Castelli (@flavio)
- Lily Sturmann (@lkatalin)
# v0.5.2
## Fixes
- Address compilation error (https://github.com/sigstore/sigstore-rs/pull/143)
## Contributors
- Flavio Castelli (@flavio)
# v0.5.1
## Fixes
- fix verification of signatures produced with PKI11 (https://github.com/sigstore/sigstore-rs/pull/142)
## Others
- Update rsa dependency to stable version 0.7.0 (https://github.com/sigstore/sigstore-rs/pull/141)
- Bump actions/checkout from 3.0.2 to 3.1.0 (https://github.com/sigstore/sigstore-rs/pull/140)
## Contributors
- Flavio Castelli (@flavio)
- Xynnn (@Xynnn007)
# v0.5.0
## Enhancements
- update user-agent value to be specific to sigstore-rs (https://github.com/sigstore/sigstore-rs/pull/122)
- remove /api/v1/version from client by (https://github.com/sigstore/sigstore-rs/pull/121)
- crate async fulcio client (https://github.com/sigstore/sigstore-rs/pull/132)
- Removed ring dependency (https://github.com/sigstore/sigstore-rs/pull/127)
## Others
- Update dependencies
- Refactoring and examples for key interface (https://github.com/sigstore/sigstore-rs/pull/123)
- Fix doc test failures (https://github.com/sigstore/sigstore-rs/pull/136)
## Contributors
- Bob Callaway (@bobcallaway)
- Bob McWhirter (@bobmcwhirter)
- Flavio Castelli (@flavio)
- Luke Hinds (@lukehinds)
- Xynnn (@Xynnn007)
# v0.4.0
## Enhancements
- feat: from and to interface for signing and verification keys (https://github.com/sigstore/sigstore-rs/pulls/115)
- Refactor examples to support subfolder execution (https://github.com/sigstore/sigstore-rs/pulls/111)
- Integrate Rekor with Sigstore-rs (https://github.com/sigstore/sigstore-rs/pulls/88)
- feat: add example case and docs for key interface (https://github.com/sigstore/sigstore-rs/pulls/99)
- feat: add signing key module (https://github.com/sigstore/sigstore-rs/pulls/87)
## Documention
- Update readme to include new features (https://github.com/sigstore/sigstore-rs/pulls/113)
## Others
- bump crate version (https://github.com/sigstore/sigstore-rs/pulls/118)
- Add RUSTSEC-2021-0139 to audit.toml (https://github.com/sigstore/sigstore-rs/pulls/112)
- Update xsalsa20poly1305 requirement from 0.7.1 to 0.9.0 (https://github.com/sigstore/sigstore-rs/pulls/101)
- ignore derive_partial_eq_without_eq (https://github.com/sigstore/sigstore-rs/pulls/102)
- fix clippy lints (https://github.com/sigstore/sigstore-rs/pulls/98)
## Contributors
- Carlos Tadeu Panato Junior (@cpanato)
- Flavio Castelli (@flavio)
- Jyotsna (@jyotsna-penumaka)
- Lily Sturmann (@lkatalin)
- Luke Hinds (@lukehinds)
- Tony Arcieri (@tarcieri)
- Xynnn\_ (@Xynnn007)
================================================
FILE: CODEOWNERS
================================================
# The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order):
#
# flavio
# lukehinds
# arsa
# viccuad
# Xynnn007
@sigstore-rs-codeowners
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <maintainers@sigstore.dev>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: CONTRIBUTORS.md
================================================
# Contributing
When contributing to this repository, please first discuss the change you wish
to make via an [issue](https://github.com/sigstore/sigstore-rs/issues).
## Building and testing
The Makefile contains useful targets for editing source code (`make lint`, `make fmt`), building executables
(`make build`) and testing (`make test`).
Full test suite requires Docker daemon to be running (and the user must have permissions to start a container).
## Pull Request Process
1. Create an [issue](https://github.com/sigstore/sigstore-rs/issues)
outlining the fix or feature.
2. Fork the sigstore-rs repository to your own github account and clone it locally.
3. Hack on your changes.
4. Update the README.md with details of changes to any interface, this includes new environment
variables, exposed ports, useful file locations, CLI parameters and
new or changed configuration values.
5. Correctly format your commit message see [Commit Messages](#commit-message-guidelines)
below.
6. Ensure that CI passes, if it fails, fix the failures.
7. Every pull request requires a review from the [core sigstore-rs team](https://github.com/orgs/github.com/sigstore/teams/sigstore-rs-codeowners)
before merging.
8. If your pull request consists of more than one commit, please squash your
commits as described in [Squash Commits](#squash-commits)
## Commit Message Guidelines
We follow the commit formatting recommendations found on [Chris Beams' How to Write a Git Commit Message article]((https://chris.beams.io/posts/git-commit/).
Well formed commit messages not only help reviewers understand the nature of
the Pull Request, but also assists the release process where commit messages
are used to generate release notes.
A good example of a commit message would be as follows:
```
Summarize changes in around 50 characters or less
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.
Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded
by a single space, with blank lines in between, but conventions
vary here
If you use an issue tracker, put references to them at the bottom,
like this:
Resolves: #123
See also: #456, #789
```
Note the `Resolves #123` tag, this references the issue raised and allows us to
ensure issues are associated and closed when a pull request is merged.
Please refer to [the github help page on message types](https://help.github.com/articles/closing-issues-using-keywords/)
for a complete list of issue references.
## Squash Commits
Should your pull request consist of more than one commit (perhaps due to
a change being requested during the review cycle), please perform a git squash
once a reviewer has approved your pull request.
A squash can be performed as follows. Let's say you have the following commits:
initial commit
second commit
final commit
Run the command below with the number set to the total commits you wish to
squash (in our case 3 commits):
git rebase -i HEAD~3
You default text editor will then open up and you will see the following::
pick eb36612 initial commit
pick 9ac8968 second commit
pick a760569 final commit
# Rebase eb1429f..a760569 onto eb1429f (3 commands)
We want to rebase on top of our first commit, so we change the other two commits
to `squash`:
pick eb36612 initial commit
squash 9ac8968 second commit
squash a760569 final commit
After this, should you wish to update your commit message to better summarise
all of your pull request, run:
git commit --amend
You will then need to force push (assuming your initial commit(s) were posted
to github):
git push origin your-branch --force
Alternatively, a core member can squash your commits within Github.
## Code of Conduct
sigstore-rs adheres to and enforces the [Contributor Covenant](http://contributor-covenant.org/version/1/4/) Code of Conduct.
Please take a moment to read the [CODE_OF_CONDUCT.md](https://github.com/sigstore/sigstore-rs/blob/master/CODE_OF_CONDUCT.md) document.
================================================
FILE: COPYRIGHT.txt
================================================
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.
================================================
FILE: Cargo.toml
================================================
[package]
authors = ["sigstore-rs developers"]
description = "An experimental crate to interact with sigstore"
edition = "2024"
license = "Apache-2.0"
name = "sigstore"
readme = "README.md"
repository = "https://github.com/sigstore/sigstore-rs"
version = "0.13.0"
[package.metadata.docs.rs]
all-features = true
[features]
default = ["full", "native-tls"]
bundle = ["sign", "verify"]
cached-client = ["dep:cached"]
cert = ["dep:aws-lc-rs", "rustls-webpki/aws-lc-rs"]
cosign = [
"cert",
"dep:async-trait",
"dep:cfg-if",
"dep:oci-client",
"dep:regex",
"dep:serde_json_canonicalizer",
"registry",
]
fulcio = [
"dep:reqwest",
"dep:serde_repr",
"dep:serde_with",
"dep:webbrowser",
"oauth",
]
full = [
"bundle",
"cached-client",
"cosign",
"fulcio",
"mock-client",
"rekor",
"sigstore-trust-root",
]
mock-client = ["dep:async-trait", "dep:oci-client"]
native-tls = ["oci-client?/native-tls", "reqwest?/native-tls"]
oauth = ["dep:openidconnect", "dep:reqwest", "reqwest?/blocking"]
registry = ["dep:async-trait", "dep:oci-client", "dep:serde_json_canonicalizer"]
rekor = [
"dep:hex",
"dep:hex-literal",
"dep:reqwest",
"dep:serde_json_canonicalizer",
"reqwest?/query",
]
rustls-tls = ["oci-client?/rustls-tls", "reqwest?/rustls"]
sign = [
"cert",
"dep:hex",
"dep:serde_json_canonicalizer",
"dep:sigstore_protobuf_specs",
"fulcio",
"rekor",
]
sigstore-trust-root = [
"dep:async-trait",
"dep:futures",
"dep:futures-util",
"dep:hex",
"dep:reqwest",
"dep:sigstore_protobuf_specs",
"dep:tough",
"reqwest?/stream",
"tokio/sync",
]
test-registry = [] # used for testing against a test registry
verify = [
"cert",
"dep:hex",
"dep:serde_json_canonicalizer",
"dep:sigstore_protobuf_specs",
"fulcio",
"rekor",
]
wasm = ["chrono/wasmbind", "ring/wasm32_unknown_unknown_js"]
[dependencies]
async-trait = { version = "0.1", optional = true, default-features = false }
base64 = { version = "0.22", default-features = false, features = ["std"] }
cached = { version = "0.59", optional = true, features = ["async"] }
cfg-if = { version = "1.0.0", optional = true, default-features = false }
chrono = { version = "0.4", default-features = false, features = [
"now",
"serde",
] }
const-oid = { version = "0.9", default-features = false, features = ["db"] }
crypto_secretbox = { version = "0.1", default-features = false, features = [
"alloc",
"salsa20",
] }
digest = { version = "0.10", default-features = false }
ecdsa = { version = "0.16", default-features = false, features = [
"der",
"digest",
"pkcs8",
"signing",
"std",
] }
ed25519 = { version = "2.2", default-features = false, features = ["alloc"] }
ed25519-dalek = { version = "2.1", default-features = false, features = [
"alloc",
"pkcs8",
"rand_core",
] }
elliptic-curve = { version = "0.13", default-features = false, features = [
"arithmetic",
"pem",
"std",
] }
futures = { version = "0.3", default-features = false, optional = true }
futures-util = { version = "0.3", default-features = false, optional = true }
hex = { version = "0.4", default-features = false, optional = true, features = [
"std",
] }
hex-literal = { version = "1.1", optional = true }
oci-client = { version = "0.16", default-features = false, optional = true }
openidconnect = { version = "4.0", default-features = false, optional = true }
p256 = { version = "0.13", default-features = false, features = [
"arithmetic",
"ecdsa",
"pem",
"std",
] }
p384 = { version = "0.13", default-features = false, features = [
"arithmetic",
"ecdsa",
"pem",
"std",
] }
pem = { version = "3.0", default-features = false, features = ["serde", "std"] }
pkcs1 = { version = "0.7", default-features = false, features = ["std"] }
pkcs8 = { version = "0.10", default-features = false, features = [
"encryption",
"pem",
"pkcs5",
"std",
] }
pki-types = { package = "rustls-pki-types", version = "1.11", default-features = false }
rand = { version = "0.8", default-features = false, features = ["std"] }
regex = { version = "1.10", default-features = false, optional = true }
reqwest = { version = "0.13", default-features = false, features = [
"json",
"multipart",
], optional = true }
# used only by the wasm feature
ring = { version = "0", default-features = false, optional = true }
rsa = { version = "0.9", default-features = false, features = ["std"] }
rustls-webpki = { version = "0.103", default-features = false, features = [
"std",
] }
scrypt = { version = "0.11", default-features = false, features = [
"simple",
"std",
] }
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_json = { version = "1.0", default-features = false, features = ["std"] }
serde_json_canonicalizer = { version = "0.3", optional = true }
serde_repr = { version = "0.1", default-features = false, optional = true }
serde_with = { version = "3.9", default-features = false, features = [
"base64",
"json",
], optional = true }
sha2 = { version = "0.10", default-features = false, features = ["oid"] }
signature = { version = "2.2", default-features = false }
sigstore_protobuf_specs = { version = "0.5", default-features = false, optional = true }
thiserror = { version = "2.0", default-features = false, features = ["std"] }
tls_codec = { version = "0.4", default-features = false, features = ["derive"] }
tokio = { version = "1", default-features = false, features = ["rt"] }
tokio-util = { version = "0.7", default-features = false, features = [
"io-util",
] }
tough = { version = "0.22", default-features = false, optional = true }
tracing = { version = "0.1", default-features = false }
url = { version = "2.5", default-features = false }
webbrowser = { version = "1.0", default-features = false, optional = true }
x509-cert = { version = "0.2", default-features = false, features = [
"builder",
"pem",
"sct",
"std",
] }
zeroize = { version = "1.8", default-features = false }
[dev-dependencies]
anyhow = { version = "1.0", default-features = false, features = [
"backtrace",
"std",
] }
assert-json-diff = { version = "2.0", default-features = false }
clap = { version = "4.5", default-features = false, features = [
"color",
"derive",
"error-context",
"help",
"std",
"suggestions",
"usage",
] }
docker_credential = { version = "1.3", default-features = false }
openssl = { version = "0.10", default-features = false }
rstest = { version = "0.26", default-features = false }
serial_test = { version = "3.1", default-features = false }
tempfile = { version = "3.12", default-features = false }
testcontainers = { version = "0.27", default-features = false, features = [
"aws-lc-rs",
] }
tracing-subscriber = { version = "0.3", default-features = false, features = [
"ansi",
"env-filter",
"fmt",
"smallvec",
"std",
"tracing-log",
] }
[target.'cfg(not(target_arch = "powerpc64"))'.dependencies]
aws-lc-rs = { version = "1", optional = true }
[target.'cfg(target_arch = "powerpc64")'.dependencies]
aws-lc-rs = { version = "1", optional = true, features = ["bindgen"] }
# cosign example mappings
[[example]]
name = "verify"
path = "examples/cosign/verify/main.rs"
[[example]]
name = "verify-blob"
path = "examples/cosign/verify-blob/main.rs"
[[example]]
name = "verify-bundle"
path = "examples/cosign/verify-bundle/main.rs"
[[example]]
name = "sign"
path = "examples/cosign/sign/main.rs"
# openidconnect example mappings
[[example]]
name = "openidconnect"
path = "examples/openidflow/openidconnect/main.rs"
# key interface mappings
[[example]]
name = "key_pair_gen_sign_verify"
path = "examples/key_interface/key_pair_gen_sign_verify/main.rs"
[[example]]
name = "key_pair_gen_and_export"
path = "examples/key_interface/key_pair_gen_and_export/main.rs"
[[example]]
name = "key_pair_import"
path = "examples/key_interface/key_pair_import/main.rs"
# rekor example mappings
[[example]]
name = "create_log_entry"
path = "examples/rekor/create_log_entry/main.rs"
[[example]]
name = "get_log_entry_by_index"
path = "examples/rekor/get_log_entry_by_index/main.rs"
[[example]]
name = "get_log_entry_by_uuid"
path = "examples/rekor/get_log_entry_by_uuid/main.rs"
[[example]]
name = "get_log_info"
path = "examples/rekor/get_log_info/main.rs"
[[example]]
name = "get_log_proof"
path = "examples/rekor/get_log_proof/main.rs"
[[example]]
name = "get_public_key"
path = "examples/rekor/get_public_key/main.rs"
[[example]]
name = "search_index"
path = "examples/rekor/search_index/main.rs"
[[example]]
name = "search_log_query"
path = "examples/rekor/search_log_query/main.rs"
[[example]]
name = "fulcio_cert"
path = "examples/fulcio/cert/main.rs"
[[example]]
name = "inclusion_proof"
path = "examples/rekor/merkle_proofs/inclusion.rs"
[[example]]
name = "consistency_proof"
path = "examples/rekor/merkle_proofs/consistency.rs"
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
================================================
FILE: Makefile
================================================
.PHONY: build
build:
cargo build --release
.PHONY: fmt
fmt:
cargo fmt --all -- --check
taplo fmt --check
.PHONY: lint
lint:
cargo clippy --all-targets -- -D warnings
.PHONY: doc
doc:
RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo +nightly doc --all-features --no-deps
.PHONY: check-features
check-features:
cargo hack check --each-feature --skip cosign --skip full --skip mock-client --skip registry
.PHONY: check-features-native-tls
check-features-native-tls:
cargo hack check --feature-powerset --features native-tls --skip wasm --skip test-registry --skip rustls-tls --skip rustls-tls-native-roots
.PHONY: check-features-rustls-tls
check-features-rustls-tls:
cargo hack check --feature-powerset --features rustls-tls --skip wasm --skip test-registry --skip native-tls --skip rustls-tls-native-roots
.PHONY: check-wasm
check-wasm:
cargo check --no-default-features --features wasm --target wasm32-unknown-unknown
.PHONY: test
test: fmt lint doc
cargo test --workspace --no-default-features --features full,native-tls,test-registry
cargo test --workspace --no-default-features --features full,rustls-tls,test-registry
.PHONY: clean
clean:
cargo clean
.PHONY: coverage
coverage:
cargo tarpaulin -o Html
================================================
FILE: README.md
================================================
Continuous integration | Docs | License | Crate version | Crate downloads
----------------------|------|---------|---------------|-----------------
[](https://github.com/sigstore/sigstore-rs/actions/workflows/tests.yml) | [](https://docs.rs/sigstore/latest/sigstore) | [](https://opensource.org/licenses/Apache-2.0) | [](https://crates.io/crates/sigstore) | [](https://crates.io/crates/sigstore)
A crate to interact with [sigstore](https://sigstore.dev/).
This crate is under active development and will not be considered
stable until the 1.0 release.
## Features
### Cosign Sign and Verify
The crate implements the following verification mechanisms:
* Sign using a cosign key and store the signature in a registry
* Verify using a given key
* Verify bundle produced by transparency log (Rekor)
* Verify signature produced in keyless mode, using Fulcio Web-PKI
Signature annotations and certificate email can be provided at verification time.
### Fulcio Integration
For use with Fulcio ephemeral key signing, an OpenID connect API is available,
along with a fulcio client implementation.
### Rekor Client
All rekor client APIs can be leveraged to interact with the transparency log.
### Key Interface
Cryptographic key management with the following key interfaces:
* Generate a key pair
* Sign data
* Verify signature
* Export public / (encrypted) private key in PEM / DER format
* Import public / (encrypted) private key in PEM / DER format
#### Known limitations
* The crate does not handle verification of attestations yet.
## Examples
The `examples` directory contains demo programs using the library.
* [`openidflow`](examples/openidflow/README.md)
* [`key_interface`](examples/key_interface/README.md)
* [`rekor`](examples/rekor/README.md)
* [`cosign/verify`](examples/cosign/verify/README.md)
* [`cosign/verify-blob`](examples/cosign/verify-blob/README.md)
* [`cosign/verify-bundle`](examples/cosign/verify-bundle/README.md)
* [`cosign/sign`](examples/cosign/sign/README.md)
Each example can be executed with the `cargo run --example <name>` command.
For example, `openidconnect` can be run with the following command:
```bash
cargo run --example openidconnect
```
## WebAssembly/WASM support
To embedded this crate in WASM modules, build it using the `wasm` cargo feature:
```bash
cargo build --no-default-features --features wasm --target wasm32-unknown-unknown
```
NOTE: The wasm32-wasi target architecture is not yet supported.
## Contributing
Contributions are welcome! Please see the [contributing guidelines](CONTRIBUTORS.md)
for more information.
## Security
Should you discover any security issues, please refer to sigstores [security
process](https://github.com/sigstore/community/security/policy)
================================================
FILE: clippy.toml
================================================
allow-panic-in-tests = true
allow-unwrap-in-tests = true
================================================
FILE: examples/README.md
================================================
# sigstore-rs code examples
This folder contains executable examples of the sigstore-rs library.
To run any given example, simply provide the subfolder name as an argument to the `cargo run` command.
```bash
cargo run --example <example_name> --all-features
```
e.g.
```bash
cargo run --example create_log_entry --all-features
```
================================================
FILE: examples/bundle/README.md
================================================
This example shows how to sign and verify Sigstore signature bundles. The bundle
format used here is supported by most Sigstore clients but notably cosign requires
`--new-bundle-format` to do so.
This example uses `sigstore::bundle` for signing and verification. The sign subcommand uses
`sigstore::oauth` for interactive OIDC authorization. In addition to the bundle format, a
notable difference compared to the "cosign" examples is that `sigstore::bundle` also handles
the Sigstore trust root update before signing or verifying.
### Sign README.md
```console
cargo run --example bundle \
sign README.md
```
A browser window will be opened to authorize signing with an OIDC identity.
After the authorization the signature bundle is created in `README.md.sigstore.json`.
### Verify README.md using the signature bundle
```console
cargo run --example bundle \
verify --identity <EMAIL> --issuer <URI> README.md
```console
`EMAIL` is the email address of the OIDC account and <URI> is the OIDC issuer URI that were used
during signing. As an example `cargo run --example bundle verify --identity name@example.com --issuer https://github.com/login/oauth README.md`
verifies that the bundle `README.md.sigstore.json` was signed by "name@example.com" as authenticated by GitHub.
================================================
FILE: examples/bundle/main.rs
================================================
use clap::{Parser, Subcommand};
use std::fs;
use std::path::PathBuf;
use tracing::debug;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};
use sigstore::bundle::sign::SigningContext;
use sigstore::bundle::verify::{blocking::Verifier, policy};
use sigstore::oauth;
#[derive(Parser, Debug)]
#[clap(about = "Signing and verification example for sigstore::bundle module")]
struct Cli {
/// Enable verbose mode
#[arg(short, long)]
verbose: bool,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Verify a signature for an artifact
Verify(VerifyArgs),
/// Create a signature for an artifact
Sign(SignArgs),
}
#[derive(Parser, Debug)]
struct SignArgs {
/// Path to the artifact to sign
artifact: PathBuf,
}
#[derive(Parser, Debug)]
struct VerifyArgs {
/// Path to the artifact to verify
artifact: PathBuf,
/// expected signing identity (email)
#[arg(long, value_name = "EMAIL")]
identity: String,
/// expected signing identity issuer (URI)
#[arg(long, value_name = "URI")]
issuer: String,
}
pub fn main() {
let cli = Cli::parse();
// setup logging
let level_filter = if cli.verbose { "debug" } else { "info" };
let filter_layer = EnvFilter::new(level_filter);
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt::layer().with_writer(std::io::stderr))
.init();
match cli.command {
Commands::Sign(args) => sign(&args.artifact),
Commands::Verify(args) => verify(&args.artifact, &args.identity, &args.issuer),
}
}
fn sign(artifact_path: &PathBuf) {
let filename = artifact_path
.file_name()
.and_then(|s| s.to_str())
.expect("Failed to parse artifact filename");
let mut artifact = fs::File::open(artifact_path)
.unwrap_or_else(|_| panic!("Failed to read artifact {}", artifact_path.display()));
let mut bundle_path = artifact_path.clone();
bundle_path.set_file_name(format!("{}.sigstore.json", filename));
let bundle = fs::File::create_new(&bundle_path).unwrap_or_else(|e| {
println!(
"Failed to create signature bundle {}: {}",
bundle_path.display(),
e
);
std::process::exit(1);
});
let token = authorize();
let email = &token.unverified_claims().email.clone();
debug!("Signing with {}", email);
let signing_artifact = SigningContext::production().and_then(|ctx| {
ctx.blocking_signer(token)
.and_then(|session| session.sign(&mut artifact))
});
match signing_artifact {
Ok(signing_artifact) => {
serde_json::to_writer(bundle, &signing_artifact.to_bundle())
.expect("Failed to write bundle to file");
}
Err(e) => {
panic!("Failed to sign: {}", e);
}
}
println!(
"Created signature bundle {} with identity {}",
bundle_path.display(),
email
);
}
fn verify(artifact_path: &PathBuf, identity: &str, issuer: &str) {
let filename = artifact_path
.file_name()
.and_then(|s| s.to_str())
.expect("Failed to parse artifact filename");
let mut bundle_path = artifact_path.clone();
bundle_path.set_file_name(format!("{}.sigstore.json", filename));
let bundle = fs::File::open(&bundle_path)
.unwrap_or_else(|_| panic!("Failed to open signature bundle {}", &bundle_path.display()));
let mut artifact = fs::File::open(artifact_path)
.unwrap_or_else(|_| panic!("Failed to read artifact {}", artifact_path.display()));
let bundle: sigstore::bundle::Bundle =
serde_json::from_reader(bundle).expect("Failed to parse the bundle");
let verifier = Verifier::production().expect("Failed to create a verifier");
debug!("Verifying with {} (issuer {})", identity, issuer);
let id_policy = policy::Identity::new(identity, issuer);
if let Err(e) = verifier.verify(&mut artifact, bundle, &id_policy, true) {
println!("Failed to verify: {}", e);
std::process::exit(1);
}
println!("Verified")
}
fn authorize() -> oauth::IdentityToken {
let oidc_url = oauth::openidflow::OpenIDAuthorize::new(
"sigstore",
"",
"https://oauth2.sigstore.dev/auth",
"http://localhost:8080",
)
.auth_url()
.expect("Failed to start OIDC authorization");
webbrowser::open(oidc_url.0.as_ref()).expect("Failed to open browser");
println!("Please authorize signing in web browser.");
let listener = oauth::openidflow::RedirectListener::new(
"127.0.0.1:8080",
oidc_url.1, // client
oidc_url.2, // nonce
oidc_url.3, // pkce_verifier
);
let (_, token) = listener
.redirect_listener()
.expect("Failed to receive a token");
oauth::IdentityToken::from(token)
}
================================================
FILE: examples/cosign/sign/README.md
================================================
This is a simple example program that shows how perform cosign signing.
The program allows also to use annotation, in the same way as `cosign sign -a key=value`
does.
The program prints to the standard output all the Simple Signing objects that
have been successfully pushed.
# Key based Signing
The implementation is in [main.rs](./main.rs).
Create a keypair using the official cosign client:
```console
cosign generate-key-pair
```
Because the default key pair generated by cosign is `ECDSA_P256` key,
so we choose to use `ECDSA_P256_SHA256_ASN1` as the signing scheme.
Suppose the password used to encrypt the private key is `123`, and the target
image to be signed is `172.17.0.2:5000/ubuntu`
Also, let us the annotation `a=1`.
Sign a container image:
```console
cargo run --example sign \
--all-features \
-- \
--key cosign.key \
--image 172.17.0.2:5000/ubuntu \
--signing-scheme ECDSA_P256_SHA256_ASN1 \
--password 123 \
--verbose \
--http \
--annotations a=1
```
Then the image will be signed.
Let us then verify it.
1. Using `cosign` (golang version)
```console
cosign verify --key cosign.pub \
-a a=1 \
172.17.0.2:5000/ubuntu
```
2. Or use `sigstore-rs`
```console
cargo run --example verify -- \
--key cosign.pub \
--annotations a=1 \
--http \
172.17.0.2:5000/ubuntu
```
================================================
FILE: examples/cosign/sign/main.rs
================================================
//
// 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.
use docker_credential::{CredentialRetrievalError, DockerCredential};
use sigstore::cosign::constraint::{AnnotationMarker, PrivateKeySigner};
use sigstore::cosign::{Constraint, CosignCapabilities, SignatureLayer};
use sigstore::crypto::SigningScheme;
use sigstore::registry::{Auth, ClientConfig, ClientProtocol, OciReference};
use tracing::{debug, warn};
use zeroize::Zeroizing;
extern crate anyhow;
use anyhow::anyhow;
extern crate clap;
use clap::Parser;
use std::{collections::HashMap, fs};
extern crate tracing_subscriber;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Verification key
#[clap(short, long, required(false))]
key: String,
/// Signing scheme when signing and verifying
#[clap(long, required(false))]
signing_scheme: Option<String>,
/// Password used to decrypt private key
#[clap(long, required(false))]
password: Option<String>,
/// Annotations that have to be satisfied
#[clap(short, long, required(false))]
annotations: Vec<String>,
/// Enable verbose mode
#[clap(short, long)]
verbose: bool,
/// Name of the image to verify
#[clap(short, long)]
image: OciReference,
/// Whether the registry uses HTTP
#[clap(long)]
http: bool,
}
async fn run_app(cli: &Cli) -> anyhow::Result<()> {
let auth = &sigstore::registry::Auth::Anonymous;
let mut oci_client_config = ClientConfig::default();
match cli.http {
false => oci_client_config.protocol = ClientProtocol::Https,
true => oci_client_config.protocol = ClientProtocol::Http,
}
let client_builder =
sigstore::cosign::ClientBuilder::default().with_oci_client_config(oci_client_config);
let mut client = client_builder.build()?;
let image = &cli.image;
let (cosign_signature_image, source_image_digest) = client.triangulate(image, auth).await?;
debug!(cosign_signature_image= ?cosign_signature_image, source_image_digest= ?source_image_digest);
let mut signature_layer = SignatureLayer::new_unsigned(image, &source_image_digest)?;
let auth = build_auth(&cosign_signature_image);
debug!(auth = ?auth, "use auth");
if !cli.annotations.is_empty() {
let mut values: HashMap<String, String> = HashMap::new();
for annotation in &cli.annotations {
let tmp: Vec<_> = annotation.splitn(2, '=').collect();
if tmp.len() == 2 {
values.insert(String::from(tmp[0]), String::from(tmp[1]));
}
}
if !values.is_empty() {
let annotations_marker = AnnotationMarker {
annotations: values,
};
annotations_marker
.add_constraint(&mut signature_layer)
.expect("add annotations failed");
}
}
let key = Zeroizing::new(fs::read(&cli.key).map_err(|e| anyhow!("Cannot read key: {:?}", e))?);
let signing_scheme = if let Some(ss) = &cli.signing_scheme {
&ss[..]
} else {
"ECDSA_P256_SHA256_ASN1"
};
let signing_scheme = SigningScheme::try_from(signing_scheme).map_err(anyhow::Error::msg)?;
let password = Zeroizing::new(cli.password.clone().unwrap_or_default().as_bytes().to_vec());
let signer = PrivateKeySigner::new_with_raw(key, password, &signing_scheme)
.map_err(|e| anyhow!("Cannot create private key signer: {}", e))?;
signer
.add_constraint(&mut signature_layer)
.expect("sign image failed");
// Suppose there is only one SignatureLayer in the cosign image
client
.push_signature(None, &auth, &cosign_signature_image, vec![signature_layer])
.await?;
Ok(())
}
/// This function helps to get the auth of the given image reference.
/// Now only `UsernamePassword` and `Anonymous` is supported. If an
/// `IdentityToken` is found, this function will return an `Anonymous`
/// auth.
///
/// Any error will return an `Anonymous`.
fn build_auth(reference: &OciReference) -> Auth {
let server = reference
.resolve_registry()
.strip_suffix('/')
.unwrap_or_else(|| reference.resolve_registry());
match docker_credential::get_credential(server) {
Err(CredentialRetrievalError::ConfigNotFound) => Auth::Anonymous,
Err(CredentialRetrievalError::NoCredentialConfigured) => Auth::Anonymous,
Err(e) => {
warn!("Error handling docker configuration file: {}", e);
Auth::Anonymous
}
Ok(DockerCredential::UsernamePassword(username, password)) => {
debug!("Found docker credentials");
Auth::Basic(username, password)
}
Ok(DockerCredential::IdentityToken(_)) => {
warn!(
"Cannot use contents of docker config, identity token not supported. Using anonymous auth"
);
Auth::Anonymous
}
}
}
#[tokio::main]
pub async fn main() {
let cli = Cli::parse();
// setup logging
let level_filter = if cli.verbose { "debug" } else { "info" };
let filter_layer = EnvFilter::new(level_filter);
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt::layer().with_writer(std::io::stderr))
.init();
match run_app(&cli).await {
Ok(_) => println!("Costraints successfully applied"),
Err(err) => {
eprintln!("Image signing failed: {:?}", err);
}
}
}
================================================
FILE: examples/cosign/trustroot/main.rs
================================================
use anyhow::Result;
use sigstore::trust::{TrustRoot, sigstore::SigstoreTrustRoot};
#[tokio::main]
pub async fn main() -> Result<()> {
let root = SigstoreTrustRoot::new(None).await?;
let fulcio_certs = root.fulcio_certs()?;
println!("Fulcio Certificates found: {}", fulcio_certs.len());
let rekor_keys = root.rekor_keys()?;
println!("Rekor Public Keys found: {}", rekor_keys.len());
Ok(())
}
================================================
FILE: examples/cosign/verify/README.md
================================================
This is a simple example program that shows how perform cosign verification.
The program allows also to use annotation, in the same way as `cosign verify -a key=value`
does.
The program prints to the standard output all the Simple Signing objects that
have been successfully verified.
# Key based verification
Create a keypair using the official cosign client:
```console
cosign generate-key-pair
```
Sign a container image:
```console
cosign sign --key cosign.key registry-testing.svc.lan/busybox
```
Verify the image signature using the example program defined in
[main.rs](./main.rs):
```console
cargo run --example verify \
--all-features \
-- \
-k cosign.pub \
--rekor-pub-key ~/.sigstore/root/targets/rekor.pub \
--fulcio-cert ~/.sigstore/root/targets/fulcio.crt.pem \
registry-testing.svc.lan/busybox
```
================================================
FILE: examples/cosign/verify/main.rs
================================================
//
// 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.
extern crate sigstore;
use sigstore::cosign::verification_constraint::cert_subject_email_verifier::StringVerifier;
use sigstore::cosign::verification_constraint::{
AnnotationVerifier, CertSubjectEmailVerifier, CertSubjectUrlVerifier, CertificateVerifier,
PublicKeyVerifier, VerificationConstraintVec,
};
use sigstore::cosign::{CosignCapabilities, SignatureLayer};
use sigstore::crypto::SigningScheme;
use sigstore::errors::SigstoreVerifyConstraintsError;
use sigstore::registry::{ClientConfig, ClientProtocol, OciReference};
use sigstore::trust::sigstore::SigstoreTrustRoot;
use std::time::Instant;
use std::{collections::BTreeMap, fs};
extern crate anyhow;
use anyhow::{Result, anyhow};
extern crate clap;
use clap::Parser;
extern crate tracing_subscriber;
use tracing::{info, warn};
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Verification key
#[clap(short, long, required(false))]
key: Option<String>,
/// Path to verification certificate
#[clap(long, required(false))]
cert: Option<String>,
/// Path to certificate chain bundle file
#[clap(long, required(false))]
cert_chain: Option<String>,
/// Signing scheme when signing and verifying
#[clap(long, required(false))]
signing_scheme: Option<String>,
/// Fetch Rekor and Fulcio data from Sigstore's TUF repository"
#[clap(long)]
use_sigstore_tuf_data: bool,
/// Rekor's public key ID (in hex format) and path to the public key, separated by the ':' symbol (e.g.: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d:~/.sigstore/root/targets/rekor.pub)
#[clap(long, required(false))]
rekor_pub_keys: Vec<String>,
/// File containing Fulcio's certificate (e.g.: ~/.sigstore/root/targets/fulcio.crt.pem)
#[clap(long, required(false))]
fulcio_certs: Vec<String>,
/// The issuer of the OIDC token used by the user to authenticate against Fulcio
#[clap(long, required(false))]
cert_issuer: Option<String>,
/// The email expected in a valid fulcio cert
#[clap(long, required(false))]
cert_email: Option<String>,
/// The URL expected in a valid fulcio cert
#[clap(long, required(false))]
cert_url: Option<String>,
/// Annotations that have to be satisfied
#[clap(short, long, required(false))]
annotations: Vec<String>,
/// Enable verbose mode
#[clap(short, long)]
verbose: bool,
/// Enable caching of registry operations
#[clap(long)]
enable_registry_caching: bool,
/// Number of loops to be done. Useful only for testing `enable-registry-caching`
#[clap(long, default_value = "1")]
loops: u32,
/// Name of the image to verify
image: OciReference,
/// Whether the registry uses HTTP
#[clap(long)]
http: bool,
}
async fn run_app(
cli: &Cli,
frd: &dyn sigstore::trust::TrustRoot,
) -> anyhow::Result<(Vec<SignatureLayer>, VerificationConstraintVec)> {
// Note well: this a limitation deliberately introduced by this example.
if cli.cert_email.is_some() && cli.cert_url.is_some() {
return Err(anyhow!(
"The 'cert-email' and 'cert-url' flags cannot be used at the same time"
));
}
if cli.key.is_some() && cli.cert.is_some() {
return Err(anyhow!("'key' and 'cert' cannot be used at the same time"));
}
let auth = &sigstore::registry::Auth::Anonymous;
let mut oci_client_config = ClientConfig::default();
match cli.http {
false => oci_client_config.protocol = ClientProtocol::Https,
true => oci_client_config.protocol = ClientProtocol::Http,
}
let mut client_builder =
sigstore::cosign::ClientBuilder::default().with_oci_client_config(oci_client_config);
client_builder = client_builder.with_trust_repository(frd)?;
let cert_chain: Option<Vec<sigstore::registry::Certificate>> = match cli.cert_chain.as_ref() {
None => None,
Some(cert_chain_path) => Some(parse_cert_bundle(cert_chain_path)?),
};
if cli.enable_registry_caching {
client_builder = client_builder.enable_registry_caching();
}
let mut client = client_builder.build()?;
// Build verification constraints
let mut verification_constraints: VerificationConstraintVec = Vec::new();
if let Some(cert_email) = cli.cert_email.as_ref() {
let issuer = cli
.cert_issuer
.as_ref()
.map(|i| StringVerifier::ExactMatch(i.to_string()));
verification_constraints.push(Box::new(CertSubjectEmailVerifier {
email: StringVerifier::ExactMatch(cert_email.to_string()),
issuer,
}));
}
if let Some(cert_url) = cli.cert_url.as_ref() {
let issuer = cli.cert_issuer.as_ref().map(|i| i.to_string());
if issuer.is_none() {
return Err(anyhow!(
"'cert-issuer' is required when 'cert-url' is specified"
));
}
verification_constraints.push(Box::new(CertSubjectUrlVerifier {
url: cert_url.to_string(),
issuer: issuer.unwrap(),
}));
}
if let Some(path_to_key) = cli.key.as_ref() {
let key = fs::read(path_to_key).map_err(|e| anyhow!("Cannot read key: {:?}", e))?;
let verifier = match &cli.signing_scheme {
Some(scheme) => {
let signing_scheme =
SigningScheme::try_from(&scheme[..]).map_err(anyhow::Error::msg)?;
PublicKeyVerifier::new(&key, &signing_scheme)
.map_err(|e| anyhow!("Cannot create public key verifier: {}", e))?
}
None => PublicKeyVerifier::try_from(&key)
.map_err(|e| anyhow!("Cannot create public key verifier: {}", e))?,
};
verification_constraints.push(Box::new(verifier));
}
if let Some(path_to_cert) = cli.cert.as_ref() {
let cert = fs::read(path_to_cert).map_err(|e| anyhow!("Cannot read cert: {:?}", e))?;
let require_rekor_bundle = if !frd.rekor_keys()?.is_empty() {
true
} else {
warn!("certificate based verification is weaker when Rekor integration is disabled");
false
};
let verifier =
CertificateVerifier::from_pem(&cert, require_rekor_bundle, cert_chain.as_deref())
.map_err(|e| anyhow!("Cannot create certificate verifier: {}", e))?;
verification_constraints.push(Box::new(verifier));
}
if !cli.annotations.is_empty() {
let mut values: BTreeMap<String, String> = BTreeMap::new();
for annotation in &cli.annotations {
let tmp: Vec<_> = annotation.splitn(2, '=').collect();
if tmp.len() == 2 {
values.insert(String::from(tmp[0]), String::from(tmp[1]));
}
}
if !values.is_empty() {
let annotations_verifier = AnnotationVerifier {
annotations: values,
};
verification_constraints.push(Box::new(annotations_verifier));
}
}
let image = &cli.image;
let (cosign_signature_image, source_image_digest) = client.triangulate(image, auth).await?;
let trusted_layers = client
.trusted_signature_layers(auth, &source_image_digest, &cosign_signature_image)
.await?;
Ok((trusted_layers, verification_constraints))
}
async fn fulcio_and_rekor_data(cli: &Cli) -> anyhow::Result<Box<dyn sigstore::trust::TrustRoot>> {
if cli.use_sigstore_tuf_data {
info!("Downloading data from Sigstore TUF repository");
let trust_root: sigstore::errors::Result<SigstoreTrustRoot> =
SigstoreTrustRoot::new(None).await;
return Ok(Box::new(trust_root?));
};
let mut trust_root = sigstore::trust::ManualTrustRoot::default();
for id_and_path in cli.rekor_pub_keys.iter() {
let (id, path) = id_and_path
.split_once(':')
.ok_or_else(|| anyhow!("Invalid format for rekor public key"))?;
trust_root.rekor_keys.insert(
id.to_string(),
fs::read(path)
.map_err(|e| anyhow!("Error reading rekor public key from disk: {}", e))?,
);
}
for path in cli.fulcio_certs.iter() {
let cert_data = fs::read(path)
.map_err(|e| anyhow!("Error reading fulcio certificate from disk: {}", e))?;
let certificate = sigstore::registry::Certificate {
encoding: sigstore::registry::CertificateEncoding::Pem,
data: cert_data,
};
trust_root.fulcio_certs.push(certificate.try_into()?);
}
Ok(Box::new(trust_root))
}
#[tokio::main]
pub async fn main() {
let cli = Cli::parse();
// setup logging
let level_filter = if cli.verbose { "debug" } else { "info" };
let filter_layer = EnvFilter::new(level_filter);
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt::layer().with_writer(std::io::stderr))
.init();
let frd = match fulcio_and_rekor_data(&cli).await {
Ok(sr) => sr,
Err(e) => {
eprintln!("Cannot build sigstore repo data: {}", e);
std::process::exit(1);
}
};
for n in 0..(cli.loops) {
let now = Instant::now();
if cli.loops != 1 {
println!("Loop {}/{}", n + 1, cli.loops);
}
match run_app(&cli, frd.as_ref()).await {
Ok((trusted_layers, verification_constraints)) => {
let filter_result = sigstore::cosign::verify_constraints(
&trusted_layers,
verification_constraints.iter(),
);
match filter_result {
Ok(()) => {
println!("Image successfully verified");
}
Err(SigstoreVerifyConstraintsError {
unsatisfied_constraints,
}) => {
eprintln!("Image verification failed: not all constraints satisfied.");
eprintln!("{:?}", unsatisfied_constraints);
}
}
}
Err(err) => {
eprintln!("Image verification failed: {:?}", err);
}
}
let elapsed = now.elapsed();
if cli.loops != 1 {
println!("Elapsed: {:.2?}", elapsed);
println!("------");
}
}
}
fn parse_cert_bundle(bundle_path: &str) -> Result<Vec<sigstore::registry::Certificate>> {
let data =
fs::read(bundle_path).map_err(|e| anyhow!("Error reading {}: {}", bundle_path, e))?;
let pems = pem::parse_many(data)?;
Ok(pems
.iter()
.map(|pem| sigstore::registry::Certificate {
encoding: sigstore::registry::CertificateEncoding::Der,
data: pem.contents().to_vec(),
})
.collect())
}
================================================
FILE: examples/cosign/verify-blob/.gitignore
================================================
signature
certificate
artifact.txt
================================================
FILE: examples/cosign/verify-blob/README.md
================================================
This example shows how to verify a blob signature that was created by the
`cosign sign-blob` command.
### Create the artifact to be signed.
```console
cd examples/cosign/verify-blob
echo something > artifact.txt
```
### Sign the artifact.txt file using cosign
```
cosign sign-blob \
--output-signature signature \
--output-certificate certificate \
artifact.txt
Using payload from: artifact.txt
Generating ephemeral keys...
Retrieving signed certificate...
Note that there may be personally identifiable information associated with this signed artifact.
This may include the email address associated with the account with which you authenticate.
This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.
By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.
Are you sure you want to continue? (y/[N]): y
Your browser will now be opened to:
https://oauth2.sigstore.dev/auth/auth?access_type=online&client_id=sigstore&code_challenge=o2zGqxFdnIMy2n31excKZGDd25nj9bRocuCK_oSTKDk&code_challenge_method=S256&nonce=2MxS5IYq7wviqRPvAKMeSUcQiBS&redirect_uri=http%3A%2F%2Flocalhost%3A36653%2Fauth%2Fcallback&response_type=code&scope=openid+email&state=2MxS5NQBiv0oTvB0oU88qRbaKEk
Successfully verified SCT...
using ephemeral certificate:
-----BEGIN CERTIFICATE-----
MIICqTCCAi6gAwIBAgIUc4soYChsRq4lWUu990I7GrErO9IwCgYIKoZIzj0EAwMw
NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl
cm1lZGlhdGUwHhcNMjMwMzEzMTEzOTIwWhcNMjMwMzEzMTE0OTIwWjAAMFkwEwYH
KoZIzj0CAQYIKoZIzj0DAQcDQgAE7zhgP7vhI8QzXm0nMC6wvj1c/82sRx4ozvIB
6od9xfiNofmjlDJtdG+IrObrxONhAXffZWDB2N8SmjAcHVz85qOCAU0wggFJMA4G
A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU3U2j
b80jcAEZIXWnZgIjGEJ39EcwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y
ZD8wJwYDVR0RAQH/BB0wG4EZZGFuaWVsLmJldmVuaXVzQGdtYWlsLmNvbTAsBgor
BgEEAYO/MAEBBB5odHRwczovL2dpdGh1Yi5jb20vbG9naW4vb2F1dGgwgYoGCisG
AQQB1nkCBAIEfAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynu
jgAAAYbaxJHJAAAEAwBHMEUCIFsrHqZF6pqZotjvHvvSPxk7jdtWkAPLn55APKmj
lD72AiEA3807EnFi2HLZcoP+85fmCH5awXDX1KLPUW7kibOwKpAwCgYIKoZIzj0E
AwMDaQAwZgIxAOf6C68qm6r7Rovurc7j+JQkki8hsoWd68vC+VvSazSFMpCxrvm7
HlrW7oMAzjlCzwIxANQWgC60eNi7QNeqlMlo/UraZz8xFho2d0Fr5fa0ZfALBE82
I9TvCXsVua7/ERp+eQ==
-----END CERTIFICATE-----
tlog entry created with index: 15311440
MEYCIQDSsR/enheXGrFNLtgEVNLvLFTYPa1cWOTBZBqNYv/kQQIhALFxLx27ECqtVyM3jGedhharRngiHJ4EMdfvA6Bl3+pm
```
The above command will have saved two files, one containing the signature
(which can also be seen as the last line of the output above), and one which
contains the certificate.
### Verify using sigstore-rs:
To verify the blob using this example use the following command:
```console
cd examples/cosign/verify-blob
cargo run --example verify-blob -- \
--certificate certificate \
--signature signature \
artifact.txt
Verification succeeded
```
### Verify using cosign
To verify the blob using `cosign verify-blob` we need to specify a
`--certificate-oidc-issuer` which currently can be one of:
the following:
* https://github.com/login/oauth
* https://accounts.google.com
* https://login.microsoftonline.com
And we also have to specify the email address we used as the
`--certificate-identity`:
```console
cosign verify-blob \
--cert certificate \
--signature signature \
--certificate-identity <email address> \
--certificate-oidc-issuer https://github.com/login/oauth \
artifact.txt
Verified OK
```
================================================
FILE: examples/cosign/verify-blob/main.rs
================================================
//
// 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.
extern crate clap;
extern crate sigstore;
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STD_ENGINE};
use clap::Parser;
use sigstore::cosign::CosignCapabilities;
use sigstore::cosign::client::Client;
extern crate tracing_subscriber;
use std::fs;
use std::path::PathBuf;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// The certificate generate from the `cosign sign-blob` command
#[clap(short, long)]
certificate: PathBuf,
/// The signature generated from the `cosign sign-blob` command
#[clap(long, required(false))]
signature: PathBuf,
/// The blob to verify
blob: String,
/// Enable verbose mode
#[clap(short, long)]
verbose: bool,
}
#[tokio::main]
pub async fn main() {
let cli = Cli::parse();
// setup logging
let level_filter = if cli.verbose { "debug" } else { "info" };
let filter_layer = EnvFilter::new(level_filter);
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt::layer().with_writer(std::io::stderr))
.init();
// certificate may be PEM or "double base64 encoded PEM" (cosign).
let cert_input = fs::read_to_string(&cli.certificate).expect("error reading certificate");
let certificate = match BASE64_STD_ENGINE.decode(cert_input.clone()) {
Ok(res) => String::from_utf8(res).expect("error stringifying PEM certificate"),
Err(_) => cert_input,
};
let signature = fs::read_to_string(&cli.signature).expect("error reading signature");
let blob = fs::read(cli.blob.as_str()).expect("error reading blob file");
match Client::verify_blob(&certificate, signature.trim(), &blob) {
Ok(_) => println!("Verification succeeded"),
Err(e) => eprintln!("Verification failed {:?}", e),
}
}
================================================
FILE: examples/cosign/verify-bundle/.gitignore
================================================
artifact.bundle
artifact.txt
================================================
FILE: examples/cosign/verify-bundle/README.md
================================================
This example shows how to verify a blob, using a bundle that was created by the
`cosign sign-blob` command.
### Sign README.md file using cosign
```
cd examples/cosign/verify-bundle
cosign sign-blob --bundle=artifact.bundle README.md
```
### Verify using sigstore-rs:
```console
cargo run --example verify-bundle -- \
--rekor-pub-key ~/.sigstore/root/targets/rekor.pub \
--bundle artifact.bundle \
README.md
```
================================================
FILE: examples/cosign/verify-bundle/main.rs
================================================
//
// 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.
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STD_ENGINE};
use clap::Parser;
use sigstore::cosign::CosignCapabilities;
use sigstore::cosign::bundle::SignedArtifactBundle;
use sigstore::cosign::client::Client;
use sigstore::crypto::{CosignVerificationKey, SigningScheme};
use std::fs;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Path to bundle file
#[clap(short, long)]
bundle: String,
/// Path to artifact to be verified
blob: String,
/// File containing Rekor's public key (e.g.: ~/.sigstore/root/targets/rekor.pub)
#[clap(long, required = true)]
rekor_pub_key: String,
/// Rekor public key ID
#[clap(long, required = true)]
rekor_pub_key_id: String,
/// Enable verbose mode
#[clap(short, long)]
verbose: bool,
}
#[tokio::main]
pub async fn main() {
let cli = Cli::parse();
// setup logging
let level_filter = if cli.verbose { "debug" } else { "info" };
let filter_layer = EnvFilter::new(level_filter);
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt::layer().with_writer(std::io::stderr))
.init();
let rekor_pub_pem =
fs::read_to_string(&cli.rekor_pub_key).expect("error reading rekor's public key");
let rekor_pub_key =
CosignVerificationKey::from_pem(rekor_pub_pem.as_bytes(), &SigningScheme::default())
.expect("Cannot create Rekor verification key");
let bundle_json = fs::read_to_string(&cli.bundle).expect("error reading bundle json file");
let blob = fs::read(cli.blob.as_str()).expect("error reading blob file");
let rekor_pub_keys = [(cli.rekor_pub_key_id, rekor_pub_key)]
.into_iter()
.collect();
let bundle = SignedArtifactBundle::new_verified(&bundle_json, &rekor_pub_keys).unwrap();
// certificate in bundle is double base64 encoded, remove one layer:
let cert_data = BASE64_STD_ENGINE
.decode(bundle.cert)
.expect("Error decoding base64 certificate");
let cert = String::from_utf8(cert_data).expect("error stringifying PEM certificate");
match Client::verify_blob(&cert, &bundle.base64_signature, &blob) {
Ok(_) => println!("Verification succeeded"),
Err(e) => eprintln!("Verification failed: {}", e),
}
}
================================================
FILE: examples/cosign/verify-bundle/run.sh
================================================
BLOB="README.md"
BUNDLE="artifact.bundle"
echo -e "\nSign README.md file using sign-blob"
cosign sign-blob --bundle=$BUNDLE $BLOB
echo -e "\nRun examples/cosign/verify-bundle"
cargo run --example verify-bundle -- \
--rekor-pub-key ~/.sigstore/root/targets/rekor.pub \
--bundle $BUNDLE \
$BLOB
================================================
FILE: examples/fulcio/cert/main.rs
================================================
use pkcs8::der::Decode;
use sigstore::crypto::SigningScheme;
use sigstore::fulcio::oauth::OauthTokenProvider;
use sigstore::fulcio::{FULCIO_ROOT, FulcioClient, TokenProvider};
use url::Url;
use x509_cert::Certificate;
use x509_cert::ext::pkix::SubjectAltName;
#[tokio::main]
async fn main() {
let fulcio = FulcioClient::new(
Url::parse(FULCIO_ROOT).unwrap(),
TokenProvider::Oauth(OauthTokenProvider::default()),
);
if let Ok((_signer, cert)) = fulcio
.request_cert(SigningScheme::ECDSA_P256_SHA256_ASN1)
.await
{
println!("Received certificate chain");
let pems = pem::parse_many(cert.as_ref()).expect("parse pem failed");
for pem in &pems {
let cert = Certificate::from_der(pem.contents()).expect("parse certificate from der");
let (_, san) = cert
.tbs_certificate
.get::<SubjectAltName>()
.expect("get SAN failed")
.expect("No SAN found");
for name in &san.0 {
println!("SAN: {name:?}");
}
}
}
}
================================================
FILE: examples/key_interface/README.md
================================================
# Example Key Interface
This is a simple example program that shows how to use the key interfaces.
The key interfaces covers:
* Generating Asymmetric encryption key pair
* Signing with private key
* Exporting the (encrypted) private/public key
* Importing the (encrypted) private/public key
* Verifying signature with public key
The basic implementation for key-interface can be shown in the following diagram

The exposed interfaces (marked as `pub`) include:
* `SigStoreSigner` enum: wrapper for `Signer`s of different kinds of signing algorithm.
* `SigStoreKeyPair` enum: wrapper for `KeyPair`s of different kinds of asymmetric encryption algorithm.
* `SigningScheme` enum: Different kinds of signing algorithm.
* `CosignVerificationKey` struct: Public key types to verify signatures for different signing algorithm.
To show the different usages for them, there will be three typical scenarios.
## Key Pair Generation, Signing and Verification
This example shows the following operations
* Generating Asymmetric encryption key pair due to given `SigningScheme`.
* Signing the given test data using private key. The signature will be printed
in hex.
* Verifying the signature generated.
The signing process is performed by `SigStoreSigner`.
The verifying process is performed by `CosignVerificationKey`.
### Run the example case
The following example will create a ECDSA_P256_ASN1 keypair and sign the given
data.
```bash
cargo run --example key_pair_gen_sign_verify
```
This example includes the following steps:
* Randomly generate an `ECDSA_P256_ASN1` key pair, which is represented as `signer` of type
`SigStoreSigner` and includes a private key and a public key. Here, the type of the key
pair is influenced by the given `SigningScheme`.
* Sign the given data `DATA_TO_BE_SIGNED` using the `signer`'s private key.
* Derive [`verification_key`](../../src/crypto/verification_key.rs) from the `signer`.
* Verify the signature generated before using the `verification_key`.
## Key Pair Generation and Exporting
This example shows the following operations
* Generating Asymmetric encryption key pair due to given `SigningScheme`.
* Export the public key in both DER and PEM format.
* Export the private key in both DER and PEM format.
* Export the encrypted private key in PEM format.
The key-related operations are performed by `SigStoreKeyPair`.
### Run the example case
The following example will create a ECDSA_P256_ASN1 keypair and sign the given
data.
```bash
cargo run --example key_pair_gen_and_export
```
This example includes the following steps:
* Randomly generate an `ECDSA_P256_ASN1` key pair, which is represented as `signer` of type
`SigStoreSigner` and includes a private key and a public key. Here, the type of the key
pair is influenced by the given `SigningScheme`.
* Export the public key in PEM format and DER format. The result
will be printed (PEM as string, DER as hex).
* Export the private key in PEM format and DER format. The result
will be printed (PEM as string, DER as hex).
* Export the encrypted private key in PEM format. The result
will be printed.
## Key Pair Importing
This example shows the following operations
* Import the public key in both DER and PEM format to `CosignVerificationKey`.
* Import the private key in both DER and PEM format to `SigStoreKeyPair/ECDSAKeys`.
* Import the encrypted private key in PEM format to `SigStoreKeyPair/ECDSAKeys`.
* Convert the `SigStoreKeyPair` to `SigStoreSigner`.
### Run the example case
The following example will create a ECDSA_P256_ASN1 keypair and sign the given
data.
```bash
cargo run --example key_pair_import
```
This example includes the following steps:
* Import the public key `ECDSA_P256_ASN1_PUBLIC_PEM.pub` as `CosignVerificationKey`.
* Import the public key `ECDSA_P256_ASN1_PUBLIC_DER.pub` as `CosignVerificationKey`.
* Import the private key `ECDSA_P256_ASN1_PRIVATE_PEM.key` as `SigStoreKeyPair`.
* Import the private key `ECDSA_P256_ASN1_PRIVATE_PEM.key` as `ECDSAKeys`.
* Import the private key `ECDSA_P256_ASN1_PRIVATE_DER.key` as `SigStoreKeyPair`.
* Import the private key `ECDSA_P256_ASN1_PRIVATE_DER.key` as `ECDSAKeys`.
* Import the encrypted private key `ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key` as `SigStoreKeyPair`.
* Import the encrypted private key `ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key` as `ECDSAKeys`.
* Convert the last `SigStoreKeyPair` to `SigStoreSigner`.
================================================
FILE: examples/key_interface/key_pair_gen_and_export/main.rs
================================================
//
// 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.
use anyhow::Result;
use sigstore::crypto::SigningScheme;
const PASSWORD: &str = "example password";
fn main() -> Result<()> {
let signer = SigningScheme::ECDSA_P256_SHA256_ASN1.create_signer()?;
println!("Created a new key pair for ECDSA_P256_SHA256_ASN1.\n");
let key_pair = signer.to_sigstore_keypair()?;
println!("Derived `SigStoreKeyPair` from the `SigStoreSigner`.\n");
let pub_pem = key_pair.public_key_to_pem()?;
println!("Exported the public key in PEM format.");
println!("public key:\n {}", pub_pem);
let pub_der = key_pair.public_key_to_der()?;
println!("Exported the public key in DER format.");
println!("public key:\n {:x?}", pub_der);
let pri_pem = key_pair.private_key_to_pem()?;
println!("Exported the private key in PEM format.");
println!("private key:\n {}", *pri_pem);
let pri_der = key_pair.private_key_to_der()?;
println!("Exported the private key in DER format.");
println!("private key:\n {:x?}", *pri_der);
let encrypted_pri_pem = key_pair.private_key_to_encrypted_pem(PASSWORD.as_bytes())?;
println!("Exported the encrypted private key in PEM format.");
println!("private key:\n {}", *encrypted_pri_pem);
Ok(())
}
================================================
FILE: examples/key_interface/key_pair_gen_sign_verify/main.rs
================================================
//
// 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.
use anyhow::{Result, anyhow};
use sigstore::crypto::{Signature, SigningScheme};
const DATA_TO_BE_SIGNED: &str = "this is an example data to be signed";
fn main() -> Result<()> {
let signer = SigningScheme::ECDSA_P256_SHA256_ASN1.create_signer()?;
println!("Created a new key pair for ECDSA_P256_SHA256_ASN1.\n");
let signature_data = signer.sign(DATA_TO_BE_SIGNED.as_bytes())?;
println!("Signed the example data.");
println!("Data: {}", DATA_TO_BE_SIGNED);
println!("Signature: {:x?}\n", &signature_data);
let verification_key = signer.to_verification_key()?;
println!("Derive verification key from the signer.\n");
println!("Verifying the signature of the example data...");
match verification_key.verify_signature(
Signature::Raw(&signature_data),
DATA_TO_BE_SIGNED.as_bytes(),
) {
Ok(_) => {
println!("Verification Succeeded.");
Ok(())
}
Err(e) => Err(anyhow!("Verifycation failed: {}", e)),
}
}
================================================
FILE: examples/key_interface/key_pair_import/ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key
================================================
-----BEGIN ENCRYPTED COSIGN PRIVATE KEY-----
eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6
OCwicCI6MX0sInNhbHQiOiI3eWtwR1NRNVBpVWJZb1B0eXZ4cnhHWjcrM2NtZmdM
WmwwQnhDQlVHRUdZPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94
Iiwibm9uY2UiOiI0N2dPOVNCd0FueXVOZlQxVzlzcFVYOGxCREVnckgwZyJ9LCJj
aXBoZXJ0ZXh0IjoiRHhmenJlWis5eXNLdVlHOU02L0F1dVl1bVVFa2tHcFdWUmhK
V242dGp0VW1RTzBqNTJSa1RXZTYwVTk2bFMzelVldm9BUGU2MjhPMHFQODlkdkwv
MEJObjljdWZYUVZObnAxVWJsUVBaQm9tRFRsUFR6NnZFa3doMS9XTFhTa2NKekdW
ZnpqN3ZQSDRaVFhqRjBVRnRqYzZ6QmhqZFk5ZjhnRklzVERiYSs3S013eWxPUGhW
ditpakl3R0R5Zk43RGNlWTJzYTdNZHM5Q2c9PSJ9
-----END ENCRYPTED COSIGN PRIVATE KEY-----
================================================
FILE: examples/key_interface/key_pair_import/ECDSA_P256_ASN1_PRIVATE_PEM.key
================================================
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg5qt7YAIL9zSg38Pi
5DX7rHjEcQAZkDk5MulVsr6x3QehRANCAASXe5tGHMHmug4BWmGl2HtIJlG8AIEV
pWZ895mqN6Yv2X6HA1n7yxjDQdqJMmFmvQm9C7Z8HGR3kbj1LQyi+DaY
-----END PRIVATE KEY-----
================================================
FILE: examples/key_interface/key_pair_import/ECDSA_P256_ASN1_PUBLIC_PEM.pub
================================================
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE10MJqZ6tgxCxOvANHgfKMY90bso8
H+Iq3rPfT6GrFbYAgckw24H69hgnTHrujYAtjhK6csqLXkgwFzYh2Hdckw==
-----END PUBLIC KEY-----
================================================
FILE: examples/key_interface/key_pair_import/main.rs
================================================
//
// 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.
use anyhow::{Result, bail};
use sigstore::crypto::{
CosignVerificationKey, SigningScheme,
signing_key::{SigStoreKeyPair, ecdsa::ECDSAKeys},
};
const PASSWORD: &str = "password";
const ECDSA_P256_ASN1_PUBLIC_PEM: &[u8] = include_bytes!("./ECDSA_P256_ASN1_PUBLIC_PEM.pub");
const ECDSA_P256_ASN1_PUBLIC_DER: &[u8] = include_bytes!("./ECDSA_P256_ASN1_PUBLIC_DER.pub");
const ECDSA_P256_ASN1_PRIVATE_PEM: &[u8] = include_bytes!("./ECDSA_P256_ASN1_PRIVATE_PEM.key");
const ECDSA_P256_ASN1_PRIVATE_DER: &[u8] = include_bytes!("./ECDSA_P256_ASN1_PRIVATE_DER.key");
const ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM: &[u8] =
include_bytes!("./ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key");
fn main() -> Result<()> {
let _ = CosignVerificationKey::from_pem(ECDSA_P256_ASN1_PUBLIC_PEM, &SigningScheme::default())?;
println!(
"Imported PEM encoded public key as CosignVerificationKey using ECDSA_P256_ASN1_PUBLIC_PEM as verification algorithm."
);
let _ = CosignVerificationKey::from_der(ECDSA_P256_ASN1_PUBLIC_DER, &SigningScheme::default())?;
println!(
"Imported DER encoded public key as CosignVerificationKey using ECDSA_P256_ASN1_PUBLIC_PEM as verification algorithm."
);
let _ = CosignVerificationKey::try_from_pem(ECDSA_P256_ASN1_PUBLIC_PEM)?;
println!("Imported PEM encoded public key as CosignVerificationKey.");
let _ = CosignVerificationKey::try_from_der(ECDSA_P256_ASN1_PUBLIC_DER)?;
println!("Imported DER encoded public key as CosignVerificationKey.");
let _ = SigStoreKeyPair::from_pem(ECDSA_P256_ASN1_PRIVATE_PEM)?;
println!("Imported PEM encoded private key as SigStoreKeyPair.");
let _ = ECDSAKeys::from_pem(ECDSA_P256_ASN1_PRIVATE_PEM)?;
println!("Imported PEM encoded private key as ECDSAKeys.");
let _ = SigStoreKeyPair::from_der(ECDSA_P256_ASN1_PRIVATE_DER)?;
println!("Imported DER encoded private key as SigStoreKeyPair.");
let _ = ECDSAKeys::from_der(ECDSA_P256_ASN1_PRIVATE_DER)?;
println!("Imported DER encoded private key as ECDSAKeys.");
let key_pair = SigStoreKeyPair::from_encrypted_pem(
ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM,
PASSWORD.as_bytes(),
)?;
println!("Imported encrypted PEM encoded private key as SigStoreKeyPair.");
let ecdsa_key_pair =
ECDSAKeys::from_encrypted_pem(ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM, PASSWORD.as_bytes())?;
println!("Imported encrypted PEM encoded private key as ECDSAKeys.");
let _ = ecdsa_key_pair.to_sigstore_signer()?;
println!("Converted ECDSAKeys to SigStoreSigner.");
match key_pair {
SigStoreKeyPair::ECDSA(inner) => {
inner.to_sigstore_signer()?;
println!("Converted SigStoreKeyPair to SigStoreSigner.");
}
_ => bail!("Wrong key pair type."),
}
Ok(())
}
================================================
FILE: examples/openidflow/README.md
================================================
# Open ID Connect Flow for Fulcio Signing Certificates
This is an example of the fulcio OpenID connect flow.
The general idea is to return an access_token and the email via a scope.
Both values can then be made to form a POST request to fulcio for a software
signing certificate
`cargo run --example openidconnect --all-features`
The implementation contains a `redirect_listener` function that will create
a local listening server to incept the ID token and scopes returned from
sigstores OIDC service. However should you prefer, you can implement your
own redirect service and simply pass along the required values:
* client: CoreClient,
* nonce: Nonce,
* pkce_verifier: PkceCodeVerifier
================================================
FILE: examples/openidflow/openidconnect/main.rs
================================================
//
// 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.
use anyhow::Result;
use sigstore::oauth;
fn main() -> Result<(), anyhow::Error> {
let oidc_url = oauth::openidflow::OpenIDAuthorize::new(
"sigstore",
"",
"https://oauth2.sigstore.dev/auth",
"http://localhost:8080",
)
.auth_url();
match oidc_url.as_ref() {
Ok(url) => {
webbrowser::open(url.0.as_ref())?;
println!(
"Open this URL in a browser if it does not automatically open for you:\n{}\n",
url.0
);
}
Err(e) => println!("{}", e),
}
let oidc_url = oidc_url?;
let result = oauth::openidflow::RedirectListener::new(
"127.0.0.1:8080",
oidc_url.1, // client
oidc_url.2, // nonce
oidc_url.3, // pkce_verifier
)
.redirect_listener();
match result {
Ok((token_response, id_token)) => {
println!("Email {:?}", token_response.email().unwrap());
println!(
"Access Token:{:?}",
token_response.access_token_hash().unwrap()
);
println!("id_token: {:?}", id_token.to_string());
}
Err(err) => {
println!("{}", err);
}
}
anyhow::Ok(())
}
================================================
FILE: examples/rekor/README.md
================================================
# Rekor Transparency Log Client
The following examples all interface with the Rekor Transparency Log Client.
================================================
FILE: examples/rekor/create_log_entry/main.rs
================================================
//
// 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.
use base64::{Engine as _, engine::general_purpose};
use sha2::Digest;
use sha2::Sha256;
use sigstore::crypto::SigningScheme;
use sigstore::crypto::signing_key::SigStoreSigner;
use sigstore::rekor::apis::{configuration::Configuration, entries_api};
use sigstore::rekor::models::{
ProposedEntry,
hashedrekord::{AlgorithmKind, Data, Hash, PublicKey, Signature, Spec},
};
use clap::{Arg, Command};
async fn create_signer() -> SigStoreSigner {
SigningScheme::ECDSA_P256_SHA256_ASN1
.create_signer()
.expect("cannot create sigstore signer")
}
// function to fetch data and generate the hash of it to be signed and upload to the transparency log
async fn get_file_sha256sum(url: String) -> Result<(Vec<u8>, String), reqwest::Error> {
let body = reqwest::get(&url).await?.bytes().await?;
let mut digester = Sha256::new();
digester.update(body.clone());
let digest = format!("{:x}", digester.finalize());
Ok((body.to_vec(), digest))
}
#[tokio::main]
async fn main() {
/*
Creates an entry in the transparency log. If no command line arguments is provided,
the program will generate a key pair, download the file available at URL constant, sign it
and create an entry in the transparency log. In the other hand, if the user sets the
command line flags, the program will use that info to create the entry. Therefore,
if the user use information of an entry already present in the transparency log, this
program can print an error. See an example:
Example command :
cargo run --example create_log_entry -- \
--hash c7ead87fa5c82d2b17feece1c2ee1bda8e94788f4b208de5057b3617a42b7413\
--url https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/data\
--public_key LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFeEhUTWRSQk80ZThCcGZ3cG5KMlozT2JMRlVrVQpaUVp6WGxtKzdyd1lZKzhSMUZpRWhmS0JZclZraGpHL2lCUjZac2s3Z01iYWZPOG9FM01lUEVvWU93PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==\
--signature MEUCIHWACbBnw+YkJCy2tVQd5i7VH6HgkdVBdP7HRV1IEsDuAiEA19iJNvmkE6We7iZGjHsTkjXV8QhK9iXu0ArUxvJF1N8=\
--api_version 0.0.1
When the example code is run with the default values, the following error message gets returned:
Err(
ResponseError(
ResponseContent {
status: 409,
content: "{\"code\":409,\"message\":\"An equivalent entry already exists in the transparency log with UUID 1377da9d9dbad451a5a8acdd28add750815d34e8205f1b8a35a67b8a27dae9bf\"}\n",
entity: Some(
Status400(
Error {
code: Some(
409,
),
message: Some(
"An equivalent entry already exists in the transparency log with UUID 1377da9d9dbad451a5a8acdd28add750815d34e8205f1b8a35a67b8a27dae9bf",
),
},
),
),
},
),
)
This is because an equivalent entry with the provided meta data already exists in the transparency log.
When you use the example code to create a new entry with fresh set of input values or leaving the program
to generate the required data, you should be able to run the code without any errors. See an example:
Example command :
cargo run --example create_log_entry --
The expected output will be something similar to:
Ok(
LogEntry {
uuid: "24296fb24b8ad77afa01e2c1f5555326e4fc32a942b40a2d798ae72a8f10c801f6e8dee771dfbacc",
attestation: None,
body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjN2VhZDg3ZmE1YzgyZDJiMTdmZWVjZTFjMmVlMWJkYThlOTQ3ODhmNGIyMDhkZTUwNTdiMzYxN2E0MmI3NDEzIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQWh4elhWZnRyMWpyS0k3dEluWW5iR1pNMDZybFhpQ1lUMTRJbFdFazF4QkFpRUE0SGllM2l4cTRyOG9tVVgwclRDV2o3UmducVhqUEFZTmlkaDlQVllrQXFVPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGYjNCRmJGTlJlbGRTTUM5Sk5raEJZbm9yV21sVmFsVlhWR051WlFvdlUwUndWV1ZOVUhGR04wUXlZbU5xV2tKRlYweGhiak5XTjB3cmVHNW5jVFJHYW1wRGVtdHlLMFkwYlc5bFNEaFJTbWhNYUV0SlQzWlJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=",
integrated_time: 1675277501,
log_i_d: "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
log_index: 12425816,
verification: Verification {
inclusion_proof: Some(
InclusionProof {
hashes: [
"a0b75928818e5fa302c3690a895e0385803a079391a79cf9f25b08a51eebc338",
"3a39532ac61bf4d3f9a982e38f1b3166a3222e9d8a081d31f67d0da745117dc5",
"96ff049c2d122233d7e44b49d5df16b0901dbf85523d90bd739a3a25d26a974c",
"09805d1e21e395d8b82e7269c7ddff2941564f925145196273a993c452059a85",
"37ca98bdb80bdc45768539d15117b2b57531b3ad1f051aaa4f58d030f868f86e",
"e81e08afa83961c36e2a6961f66859620c9ee4ed9be5631ace9f3c27c72f66fb",
"2f01e165e3758aba5fd53d0c03c88b84ccbed7334173d9159d87fed5930bfe03",
"d0509b1c0bde3ba0517efcc5d3e8d2007fe86e5e055cebd5e94307cd0394c22d",
"8a84151f9b8fbbf7b3e77cb658535ec46d27c1cdd1cab714558dc51114922e7a",
"5eb43eca7a763e2eaafb2bc2fc963e7802283cf1a9076638242177b1669942c0",
"5523cd019fea93d01834fc429f708b700aeb72c835a73161cdb9003f8f4e8072",
"4b6df664d9552bc24d48a4c7d5659a8270065e1fedbc39103b010ab235a87850",
"616429db6c7d20c5b0eff1a6e512ea57a0734b94ae0bc7c914679463e01a7fba",
"5a4ad1534b1e770f02bfde0de15008a6971cf1ffbfa963fc9c2a644973a8d2d1",
],
log_index: 8262385,
root_hash: "41b3e1294d122b2190396de7de92731a378378ac2d7f620eb01d653838e88219",
tree_size: 8262387,
},
),
signed_entry_timestamp: "MEUCIG/vIwjuQoiVZtxw48KSMYyxXlpHA/y8kxYTJh46qbejAiEAyFAP5oQjxT6xFK7wKYW33sa/5wFQvqtKsdTLnitrzWA=",
},
},
)
*/
const URL: &str = "https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/data";
const API_VERSION: &str = "0.0.1";
let data_job = get_file_sha256sum(URL.to_string());
let signer_job = create_signer();
let matches = Command::new("cmd")
.arg(Arg::new("hash")
.long("hash")
.value_name("HASH")
.help("hash of the artifact"))
.arg(Arg::new("url")
.long("url")
.value_name("URL")
.help("url containing the contents of the artifact (raw github url)"))
.arg(Arg::new("public_key")
.long("public_key")
.value_name("PUBLIC_KEY")
.help("base64 encoded public_key. Look at https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/create_log_entry.md for more details on generating keys."))
.arg(Arg::new("signature")
.long("signature")
.value_name("SIGNATURE")
.help("base64 encoded signature of the artifact. Look at https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/create_log_entry.md for more details on generating keys."))
.arg(Arg::new("api_version")
.long("api_version")
.value_name("API_VERSION")
.help("Rekor-rs open api version"));
let flags = matches.get_matches();
let configuration = Configuration::default();
let (data_bytes, digest) = data_job.await.expect("Cannot get data digest");
let signer = signer_job.await;
let public_key_base64 = general_purpose::STANDARD.encode(
signer
.to_sigstore_keypair()
.expect("Cannot get sigstore keypair")
.public_key_to_pem()
.expect("Cannot set public key"),
);
let sig = general_purpose::STANDARD.encode(signer.sign(&data_bytes).expect("Cannot sign data"));
let hash = Hash::new(
AlgorithmKind::sha256,
flags
.get_one::<String>("hash")
.unwrap_or(&digest)
.to_owned(),
);
let data = Data::new(hash);
let public_key = PublicKey::new(
flags
.get_one::<String>("public_key")
.unwrap_or(&public_key_base64)
.to_owned(),
);
let signature = Signature::new(
flags.get_one("signature").unwrap_or(&sig).to_owned(),
public_key,
);
let spec = Spec::new(signature, data);
let proposed_entry = ProposedEntry::Hashedrekord {
api_version: flags
.get_one::<String>("api_version")
.unwrap_or(&API_VERSION.to_string())
.to_owned(),
spec,
};
let log_entry = entries_api::create_log_entry(&configuration, proposed_entry).await;
println!("{:#?}", log_entry);
}
================================================
FILE: examples/rekor/get_log_entry_by_index/main.rs
================================================
//
// 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.
use clap::{Arg, Command};
use sigstore::rekor::apis::{configuration::Configuration, entries_api};
use sigstore::rekor::models::log_entry::LogEntry;
use std::str::FromStr;
#[tokio::main]
async fn main() {
/*
Retrieves an entry and inclusion proof from the transparency log (if it exists) by index
Example command :
cargo run --example get_log_entry_by_index -- --log_index 99
*/
let matches = Command::new("cmd").arg(
Arg::new("log_index")
.long("log_index")
.value_name("LOG_INDEX")
.help("log_index of the artifact"),
);
// The following default value will be used if the user does not input values using cli flags
const LOG_INDEX: &str = "1";
let flags = matches.get_matches();
let index = i32::from_str(
flags
.get_one::<String>("log_index")
.unwrap_or(&LOG_INDEX.to_string()),
)
.unwrap();
let configuration = Configuration::default();
let message: LogEntry = entries_api::get_log_entry_by_index(&configuration, index)
.await
.unwrap();
println!("{:#?}", message);
}
================================================
FILE: examples/rekor/get_log_entry_by_uuid/main.rs
================================================
//
// 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.
use clap::{Arg, Command};
use sigstore::rekor::apis::{configuration::Configuration, entries_api};
use sigstore::rekor::models::log_entry::LogEntry;
#[tokio::main]
async fn main() {
/*
Get log entry and information required to generate an inclusion proof for the entry in the transparency log
Example command :
cargo run --example get_log_entry_by_uuid -- --uuid 073970a07c978b7a9ff15b69fe15d87dfb58fd5756086e3d1fb671c2d0bd95c0
*/
let matches = Command::new("cmd").arg(
Arg::new("uuid")
.long("uuid")
.value_name("UUID")
.help("uuid of the artifact"),
);
// The following default value will be used if the user does not input values using cli flags
const UUID: &str = "073970a07c978b7a9ff15b69fe15d87dfb58fd5756086e3d1fb671c2d0bd95c0";
let flags = matches.get_matches();
let uuid = flags
.get_one::<String>("uuid")
.unwrap_or(&UUID.to_string())
.to_owned();
let configuration = Configuration::default();
let message: LogEntry = entries_api::get_log_entry_by_uuid(&configuration, &uuid)
.await
.unwrap();
println!("{:#?}", message);
}
================================================
FILE: examples/rekor/get_log_info/main.rs
================================================
//
// 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.
use sigstore::rekor::apis::{configuration::Configuration, tlog_api};
use sigstore::rekor::models::LogInfo;
#[tokio::main]
async fn main() {
/*
Gets information about the current state of the transparency log.
Returns the current root hash and size of the merkle tree used to store the log entries.
Example command :
cargo run --example get_log_info
The server might return an error sometimes,
this is because the result depends on the kind of rekor object that gets returned.
*/
let configuration = Configuration::default();
let log_info: LogInfo = tlog_api::get_log_info(&configuration).await.unwrap();
println!("{:#?}", log_info);
}
================================================
FILE: examples/rekor/get_log_proof/main.rs
================================================
//
// 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.
use clap::{Arg, Command};
use sigstore::rekor::apis::{configuration::Configuration, tlog_api};
use sigstore::rekor::models::ConsistencyProof;
use std::str::FromStr;
#[tokio::main]
async fn main() {
/*
Get information required to generate a consistency proof for the transparency log.
Returns a list of hashes for specified tree sizes that can be used to confirm the consistency of the transparency log.
Example command :
cargo run --example get_log_proof -- --last_size 10
cargo run --example get_log_proof -- --last_size 10 --first_size 1
*/
let matches = Command::new("cmd")
.arg(Arg::new("last_size")
.long("last_size")
.value_name("LAST_SIZE")
.help("The size of the tree that you wish to prove consistency to"))
.arg(Arg::new("first_size")
.long("first_size")
.value_name("FIRST_SIZE")
.help("The size of the tree that you wish to prove consistency from (1 means the beginning of the log). Defaults to 1. To use the default value, do not input any value"))
.arg(Arg::new("tree_id")
.long("tree_id")
.value_name("TREE_ID")
.help("The tree ID of the tree that you wish to prove consistency for. To use the default value, do not input any value."));
let configuration = Configuration::default();
let flags = matches.get_matches();
// The following default value will be used if the user does not input values using cli flags
const LAST_SIZE: &str = "10";
let log_proof: ConsistencyProof = tlog_api::get_log_proof(
&configuration,
i32::from_str(
flags
.get_one::<String>("last_size")
.unwrap_or(&LAST_SIZE.to_string()),
)
.unwrap(),
flags.get_one::<String>("first_size").map(|s| s.as_str()),
flags.get_one::<String>("tree_id").map(|s| s.as_str()),
)
.await
.unwrap();
println!("{:#?}", log_proof);
}
================================================
FILE: examples/rekor/get_public_key/main.rs
================================================
//
// 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.
use std::{fs::write, process};
use clap::{Arg, Command};
use sigstore::rekor::apis::{configuration::Configuration, pubkey_api};
#[tokio::main]
async fn main() {
/*
Returns the public key that can be used to validate the signed tree head
Example command :
cargo run --example get_public_key
*/
let matches = Command::new("cmd")
.arg(Arg::new("tree_id")
.long("tree_id")
.value_name("TREE_ID")
.help("The tree ID of the tree that you wish to prove consistency for. To use the default value, do not input any value."))
.arg(Arg::new("output")
.short('o')
.long("output")
.value_name("OUTPUT_FILE")
.num_args(0..=1)
.require_equals(true)
.default_missing_value("key.pub")
.help("The path to the output file that you wish to store the public key in. To use the default value (pub.key), do not provide OUTPUT_FILE."));
let flags = matches.get_matches();
let configuration = Configuration::default();
let pubkey = pubkey_api::get_public_key(
&configuration,
flags.get_one::<String>("tree_id").map(|s| s.as_str()),
)
.await
.expect("Unable to retrieve public key");
if let Some(out_path) = flags.get_one::<String>("output") {
match write(out_path, pubkey) {
Ok(_) => (),
Err(e) => {
eprintln!("Could not write to {out_path}: {e}");
process::exit(1);
}
}
} else {
print!("{}", pubkey);
}
}
================================================
FILE: examples/rekor/merkle_proofs/consistency.rs
================================================
use clap::Parser;
use sigstore::crypto::CosignVerificationKey;
use sigstore::rekor::apis::configuration::Configuration;
use sigstore::rekor::apis::tlog_api::{get_log_info, get_log_proof};
use std::fs::read_to_string;
use std::path::PathBuf;
#[derive(Parser)]
struct Args {
#[arg(long, value_name = "REKOR PUBLIC KEY")]
rekor_key: PathBuf,
#[arg(long, value_name = "HEX ENCODED HASH")]
old_root: String,
#[arg(long)]
old_size: u64,
#[arg(long, value_name = "TREE ID")]
tree_id: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
let tree_id = args.tree_id.as_deref();
// read verification key
let rekor_key = read_to_string(&args.rekor_key)
.map_err(Into::into)
.and_then(|k| CosignVerificationKey::from_pem(k.as_bytes(), &Default::default()))?;
// fetch log info
let rekor_config = Configuration::default();
let log_info = get_log_info(&rekor_config).await?;
let proof = get_log_proof(
&rekor_config,
log_info.tree_size as _,
Some(&args.old_size.to_string()),
tree_id,
)
.await?;
let old_root_bytes: [u8; 32] = hex::FromHex::from_hex(&args.old_root)?;
log_info
.verify_consistency(args.old_size, &old_root_bytes, &proof, &rekor_key)
.expect("failed to verify log consistency");
println!("Successfully verified consistency");
Ok(())
}
================================================
FILE: examples/rekor/merkle_proofs/inclusion.rs
================================================
use clap::Parser;
use sigstore::crypto::CosignVerificationKey;
use sigstore::rekor::apis::configuration::Configuration;
use sigstore::rekor::apis::entries_api::get_log_entry_by_index;
use std::fs::read_to_string;
use std::path::PathBuf;
#[derive(Parser)]
struct Args {
#[arg(long, value_name = "INDEX")]
log_index: usize,
#[arg(long, value_name = "REKOR PUBLIC KEY")]
rekor_key: PathBuf,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
// read verification key
let rekor_key = read_to_string(&args.rekor_key)
.map_err(Into::into)
.and_then(|k| CosignVerificationKey::from_pem(k.as_bytes(), &Default::default()))?;
// fetch entry from log
let rekor_config = Configuration::default();
let log_entry = get_log_entry_by_index(&rekor_config, args.log_index as i32).await?;
// verify inclusion with key
log_entry
.verify_inclusion(&rekor_key)
.expect("failed to verify log inclusion");
println!("Successfully verified inclusion.");
Ok(())
}
================================================
FILE: examples/rekor/search_index/main.rs
================================================
//
// 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.
use clap::{Arg, Command};
use sigstore::rekor::apis::{configuration::Configuration, index_api};
use sigstore::rekor::models::{
SearchIndex, search_index_public_key, search_index_public_key::Format,
};
#[tokio::main]
async fn main() {
/*
Searches index by entry metadata
Example command:
cargo run --example search_index -- \
--hash e2535d638859bb63ea9ea5cf467562cba63b007eae1acd0d73a3f259c582561f \
--public_key c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSVA3M2tuT0tKYVNyVEtEa2U2OEgvRlJoODRZWU5CU0tBN1hPVWRpWmJjeG8gdGVzdEByZWtvci5kZXYK \
--key_format ssh \
--email jpenumak@redhat.com
cargo run --example search_index -- \
--public_key c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSVA3M2tuT0tKYVNyVEtEa2U2OEgvRlJoODRZWU5CU0tBN1hPVWRpWmJjeG8gdGVzdEByZWtvci5kZXYK \
--key_format ssh \
--email jpenumak@redhat.com
The server might return an error sometimes,
this is because the result depends on the kind of rekor object that gets returned.
*/
let matches = Command::new("cmd")
.arg(Arg::new("hash")
.long("hash")
.value_name("HASH")
.help("hash of the artifact"))
.arg(Arg::new("url")
.long("url")
.value_name("URL")
.help("url containing the contents of the artifact (raw github url)"))
.arg(Arg::new("public_key")
.long("public_key")
.value_name("PUBLIC_KEY")
.help("base64 encoded public_key. Look at https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/create_log_entry.md for more details on generating keys."))
.arg(Arg::new("key_format")
.long("key_format")
.value_name("KEY_FORMAT")
.help("Accepted formats are : pgp / x509 / minsign / ssh / tuf"))
.arg(Arg::new("email")
.long("email")
.value_name("EMAIL")
.help("Author's email"));
let flags = matches.get_matches();
// The following default values will be used if the user does not input values using cli flags
const HASH: &str = "c7ead87fa5c82d2b17feece1c2ee1bda8e94788f4b208de5057b3617a42b7413";
const PUBLIC_KEY: &str = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFeEhUTWRSQk80ZThCcGZ3cG5KMlozT2JMRlVrVQpaUVp6WGxtKzdyd1lZKzhSMUZpRWhmS0JZclZraGpHL2lCUjZac2s3Z01iYWZPOG9FM01lUEVvWU93PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==";
const KEY_FORMAT: &str = "x509";
const EMAIL: &str = "jpenumak@redhat.com";
let key_format = match flags
.get_one::<String>("key_format")
.unwrap_or(&KEY_FORMAT.to_string())
.as_str()
{
"pgp" => Format::Pgp,
"x509" => Format::X509,
"minisign" => Format::Minisign,
"ssh" => Format::Ssh,
_ => Format::Tuf,
};
let public_key = search_index_public_key::SearchIndexPublicKey {
format: key_format,
content: Some(
flags
.get_one::<String>("public_key")
.unwrap_or(&PUBLIC_KEY.to_string())
.to_owned(),
),
url: None,
};
let query = SearchIndex {
email: Some(
flags
.get_one::<String>("email")
.unwrap_or(&EMAIL.to_string())
.to_owned(),
),
public_key: Some(public_key),
hash: Some(
flags
.get_one("hash")
.unwrap_or(&HASH.to_string())
.to_owned(),
),
};
let configuration = Configuration::default();
let uuid_vec = index_api::search_index(&configuration, query).await;
println!("{:#?}", uuid_vec);
}
================================================
FILE: examples/rekor/search_log_query/main.rs
================================================
//
// 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.
use clap::{Arg, Command};
use sigstore::rekor::apis::{configuration::Configuration, entries_api};
use sigstore::rekor::models::{
ProposedEntry, SearchLogQuery,
hashedrekord::{AlgorithmKind, Data, Hash, PublicKey, Signature, Spec},
};
use std::str::FromStr;
#[tokio::main]
async fn main() {
/*
Searches transparency log for one or more log entries.
Returns zero or more entries from the transparency log, according to how many were included in request query.
Example command :
cargo run --example search_log_query -- \
--hash c7ead87fa5c82d2b17feece1c2ee1bda8e94788f4b208de5057b3617a42b7413\
--url https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/data\
--public_key LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFeEhUTWRSQk80ZThCcGZ3cG5KMlozT2JMRlVrVQpaUVp6WGxtKzdyd1lZKzhSMUZpRWhmS0JZclZraGpHL2lCUjZac2s3Z01iYWZPOG9FM01lUEVvWU93PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==\
--signature MEUCIHWACbBnw+YkJCy2tVQd5i7VH6HgkdVBdP7HRV1IEsDuAiEA19iJNvmkE6We7iZGjHsTkjXV8QhK9iXu0ArUxvJF1N8=\
--key_format x509\
--api_version 0.0.1\
--entry_uuids 1377da9d9dbad451a5a8acdd28add750815d34e8205f1b8a35a67b8a27dae9bf\
--log_indexes 2922253
*/
// The following default values will be used if the user does not input values using cli flags
const HASH: &str = "c7ead87fa5c82d2b17feece1c2ee1bda8e94788f4b208de5057b3617a42b7413";
const PUBLIC_KEY: &str = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFeEhUTWRSQk80ZThCcGZ3cG5KMlozT2JMRlVrVQpaUVp6WGxtKzdyd1lZKzhSMUZpRWhmS0JZclZraGpHL2lCUjZac2s3Z01iYWZPOG9FM01lUEVvWU93PT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==";
const SIGNATURE: &str = "MEUCIHWACbBnw+YkJCy2tVQd5i7VH6HgkdVBdP7HRV1IEsDuAiEA19iJNvmkE6We7iZGjHsTkjXV8QhK9iXu0ArUxvJF1N8=";
const API_VERSION: &str = "0.0.1";
const ENTRY_UUIDS: &str = "1377da9d9dbad451a5a8acdd28add750815d34e8205f1b8a35a67b8a27dae9bf";
const LOG_INDEXES: &str = "2922253";
let matches = Command::new("cmd")
.arg(Arg::new("hash")
.long("hash")
.value_name("HASH")
.help("hash of the artifact"))
.arg(Arg::new("url")
.long("url")
.value_name("URL")
.help("url containing the contents of the artifact (raw github url)"))
.arg(Arg::new("public_key")
.long("public_key")
.value_name("PUBLIC_KEY")
.help("base64 encoded public_key. Look at https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/create_log_entry.md for more details on generating keys."))
.arg(Arg::new("key_format")
.long("key_format")
.value_name("KEY_FORMAT")
.help("Accepted formats are : pgp / x509 / minsign / ssh / tuf"))
.arg(Arg::new("signature")
.long("signature")
.value_name("SIGNATURE")
.help("base64 encoded signature of the artifact. Look at https://raw.githubusercontent.com/jyotsna-penumaka/rekor-rs/rekor-functionality/test_data/create_log_entry.md for more details on generating keys."))
.arg(Arg::new("api_version")
.long("api_version")
.value_name("API_VERSION")
.help("Rekor-rs open api version"))
.arg(Arg::new("entry_uuids")
.long("entry_uuids")
.value_name("ENTRY_UUIDS")
.help("the uuids of the entries to search for"))
.arg(Arg::new("log_indexes")
.long("log_indexes")
.value_name("LOG_INDEXES")
.help("the log_indexes of the entries to search for"));
let flags = matches.get_matches();
let hash = Hash::new(
AlgorithmKind::sha256,
flags
.get_one::<String>("hash")
.unwrap_or(&HASH.to_string())
.to_owned(),
);
let data = Data::new(hash);
let public_key = PublicKey::new(
flags
.get_one::<String>("public_key")
.unwrap_or(&PUBLIC_KEY.to_string())
.to_owned(),
);
let signature = Signature::new(
flags
.get_one::<String>("signature")
.unwrap_or(&SIGNATURE.to_string())
.to_owned(),
public_key,
);
let spec = Spec::new(signature, data);
let proposed_entry = ProposedEntry::Hashedrekord {
api_version: flags
.get_one::<String>("api_version")
.unwrap_or(&API_VERSION.to_string())
.to_owned(),
spec,
};
let query = SearchLogQuery {
entry_uuids: Some(vec![
flags
.get_one::<String>("entry_uuids")
.unwrap_or(&ENTRY_UUIDS.to_string())
.to_owned(),
]),
log_indexes: Some(vec![
i32::from_str(
flags
.get_one::<String>("log_indexes")
.unwrap_or(&LOG_INDEXES.to_string()),
)
.unwrap(),
]),
entries: Some(vec![proposed_entry]),
};
let configuration = Configuration::default();
let message = entries_api::search_log_query(&configuration, query)
.await
.unwrap();
println!("{}", message);
}
================================================
FILE: rust-toolchain.toml
================================================
[toolchain]
# Pin to a specific stable version for consistent clippy/fmt across contributors
# Update this deliberately when ready to adopt new Rust features or fix new warnings
# Minimum 1.89.0 required for edition 2024 support
channel = "1.95.0"
components = ["clippy", "rustfmt"]
================================================
FILE: src/bundle/mod.rs
================================================
// 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.
//! Sigstore bundle support.
pub use sigstore_protobuf_specs::dev::sigstore::bundle::v1::Bundle;
mod models;
#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
#[cfg(feature = "sign")]
pub mod sign;
#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
#[cfg(feature = "verify")]
pub mod verify;
================================================
FILE: src/bundle/models.rs
================================================
use std::fmt::Display;
use std::str::FromStr;
use base64::{Engine as _, engine::general_purpose::STANDARD as base64};
use sigstore_protobuf_specs::dev::sigstore::{
common::v1::LogId,
rekor::v1::{Checkpoint, InclusionPromise, InclusionProof, KindVersion, TransparencyLogEntry},
};
use crate::rekor::models::{LogEntry as RekorLogEntry, log_entry::RekorInclusionProof};
// Known Sigstore bundle media types.
#[derive(Clone, Copy, Debug)]
pub enum Version {
Bundle0_1,
Bundle0_2,
}
impl Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match &self {
Version::Bundle0_1 => "application/vnd.dev.sigstore.bundle+json;version=0.1",
Version::Bundle0_2 => "application/vnd.dev.sigstore.bundle+json;version=0.2",
})
}
}
impl FromStr for Version {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"application/vnd.dev.sigstore.bundle+json;version=0.1" => Ok(Version::Bundle0_1),
"application/vnd.dev.sigstore.bundle+json;version=0.2" => Ok(Version::Bundle0_2),
_ => Err(()),
}
}
}
#[inline]
fn decode_hex<S: AsRef<str>>(hex: S) -> Result<Vec<u8>, ()> {
hex::decode(hex.as_ref()).or(Err(()))
}
impl TryFrom<RekorInclusionProof> for InclusionProof {
type Error = ();
fn try_from(value: RekorInclusionProof) -> Result<Self, Self::Error> {
let hashes = value
.hashes
.iter()
.map(decode_hex)
.collect::<Result<Vec<_>, _>>()?;
Ok(InclusionProof {
checkpoint: Some(Checkpoint {
envelope: value.checkpoint,
}),
hashes,
log_index: value.log_index,
root_hash: decode_hex(value.root_hash)?,
tree_size: value.tree_size as i64,
})
}
}
/// Convert log entries returned from Rekor into Sigstore Bundle format entries.
impl TryFrom<RekorLogEntry> for TransparencyLogEntry {
type Error = ();
fn try_from(value: RekorLogEntry) -> Result<Self, Self::Error> {
let canonicalized_body = serde_json_canonicalizer::to_string(&value.body)
.map_err(|_| ())?
.into_bytes();
let inclusion_promise = Some(InclusionPromise {
signed_entry_timestamp: base64
.decode(value.verification.signed_entry_timestamp)
.or(Err(()))?,
});
let inclusion_proof = value
.verification
.inclusion_proof
.map(|p| p.try_into())
.transpose()?;
Ok(TransparencyLogEntry {
canonicalized_body,
inclusion_promise,
inclusion_proof,
integrated_time: value.integrated_time,
kind_version: Some(KindVersion {
kind: "hashedrekord".to_owned(),
version: "0.0.1".to_owned(),
}),
log_id: Some(LogId {
key_id: decode_hex(value.log_i_d)?,
}),
log_index: value.log_index,
})
}
}
================================================
FILE: src/bundle/sign.rs
================================================
// 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.
//! Types for signing artifacts and producing Sigstore bundles.
use std::{
io::{self, Read},
time::SystemTime,
};
use base64::{Engine as _, engine::general_purpose::STANDARD as base64};
use hex;
use p256::NistP256;
use pkcs8::der::{Encode, EncodePem};
use sha2::{Digest, Sha256};
use signature::DigestSigner;
use sigstore_protobuf_specs::dev::sigstore::bundle::v1::bundle;
use sigstore_protobuf_specs::dev::sigstore::bundle::v1::{
Bundle, VerificationMaterial, verification_material,
};
use sigstore_protobuf_specs::dev::sigstore::common::v1::{
HashAlgorithm, HashOutput, MessageSignature, X509Certificate, X509CertificateChain,
};
use sigstore_protobuf_specs::dev::sigstore::rekor::v1::TransparencyLogEntry;
use tokio::io::AsyncRead;
use tokio_util::io::SyncIoBridge;
use url::Url;
use x509_cert::attr::{AttributeTypeAndValue, AttributeValue};
use x509_cert::builder::{Builder, RequestBuilder as CertRequestBuilder};
use x509_cert::ext::pkix as x509_ext;
use crate::bundle::models::Version;
use crate::crypto::keyring::Keyring;
use crate::crypto::transparency::{CertificateEmbeddedSCT, verify_sct};
use crate::errors::{Result as SigstoreResult, SigstoreError};
use crate::fulcio::oauth::OauthTokenProvider;
use crate::fulcio::{self, FULCIO_ROOT, FulcioClient};
use crate::oauth::IdentityToken;
use crate::rekor::apis::configuration::Configuration as RekorConfiguration;
use crate::rekor::apis::entries_api::create_log_entry;
use crate::rekor::models::{hashedrekord, proposed_entry::ProposedEntry as ProposedLogEntry};
use crate::trust::TrustRoot;
#[cfg(feature = "sigstore-trust-root")]
use crate::trust::sigstore::SigstoreTrustRoot;
/// An asynchronous Sigstore signing session.
///
/// Sessions hold a provided user identity and key materials tied to that identity. A single
/// session may be used to sign multiple items. For more information, see [`SigningSession::sign`].
///
/// This signing session operates asynchronously. To construct a synchronous [`blocking::SigningSession`],
/// use [`SigningContext::blocking_signer()`].
pub struct SigningSession<'ctx> {
context: &'ctx SigningContext,
identity_token: IdentityToken,
private_key: ecdsa::SigningKey<NistP256>,
certs: fulcio::CertificateResponse,
}
impl<'ctx> SigningSession<'ctx> {
async fn new(
context: &'ctx SigningContext,
identity_token: IdentityToken,
) -> SigstoreResult<SigningSession<'ctx>> {
let (private_key, certs) = Self::materials(&context.fulcio, &identity_token).await?;
Ok(Self {
context,
identity_token,
private_key,
certs,
})
}
async fn materials(
fulcio: &FulcioClient,
token: &IdentityToken,
) -> SigstoreResult<(ecdsa::SigningKey<NistP256>, fulcio::CertificateResponse)> {
let subject =
// SEQUENCE OF RelativeDistinguishedName
vec![
// SET OF AttributeTypeAndValue
vec![
// AttributeTypeAndValue, `emailAddress=...`
AttributeTypeAndValue {
oid: const_oid::db::rfc3280::EMAIL_ADDRESS,
value: AttributeValue::new(
pkcs8::der::Tag::Utf8String,
token.unverified_claims().email.as_ref(),
)?,
}
].try_into()?
].into();
let mut rng = rand::thread_rng();
let private_key = ecdsa::SigningKey::from(p256::SecretKey::random(&mut rng));
let mut builder = CertRequestBuilder::new(subject, &private_key)?;
builder.add_extension(&x509_ext::BasicConstraints {
ca: false,
path_len_constraint: None,
})?;
let cert_req = builder.build::<p256::ecdsa::DerSignature>()?;
Ok((private_key, fulcio.request_cert_v2(cert_req, token).await?))
}
/// Check if the session's identity token or key material is expired.
///
/// If the session is expired, it cannot be used for signing operations, and a new session
/// must be created with a fresh identity token.
pub fn is_expired(&self) -> bool {
let not_after = self
.certs
.cert
.tbs_certificate
.validity
.not_after
.to_system_time();
!self.identity_token.in_validity_period() || SystemTime::now() > not_after
}
async fn sign_digest(&self, hasher: Sha256) -> SigstoreResult<SigningArtifact> {
if self.is_expired() {
return Err(SigstoreError::ExpiredSigningSession());
}
if let Some(detached_sct) = &self.certs.detached_sct {
verify_sct(detached_sct, &self.context.ctfe_keyring)?;
} else {
let sct = CertificateEmbeddedSCT::new(&self.certs.cert, &self.certs.chain)?;
verify_sct(&sct, &self.context.ctfe_keyring)?;
}
// Sign artifact.
let input_hash: &[u8] = &hasher.clone().finalize();
let artifact_signature: p256::ecdsa::Signature = self.private_key.sign_digest(hasher);
let signature_bytes = artifact_signature.to_der().as_bytes().to_owned();
let cert = &self.certs.cert;
// Create the transparency log entry.
let proposed_entry = ProposedLogEntry::Hashedrekord {
api_version: "0.0.1".to_owned(),
spec: hashedrekord::Spec {
signature: hashedrekord::Signature {
content: base64.encode(&signature_bytes),
public_key: hashedrekord::PublicKey::new(
base64.encode(cert.to_pem(pkcs8::LineEnding::LF)?),
),
},
data: hashedrekord::Data {
hash: hashedrekord::Hash {
algorithm: hashedrekord::AlgorithmKind::sha256,
value: hex::encode(input_hash),
},
},
},
};
let log_entry = create_log_entry(&self.context.rekor_config, proposed_entry)
.await
.map_err(|err| SigstoreError::RekorClientError(err.to_string()))?;
let log_entry = log_entry
.try_into()
.or(Err(SigstoreError::RekorClientError(
"Rekor returned malformed LogEntry".into(),
)))?;
// TODO(tnytown): Maybe run through the verification flow here? See sigstore-rs#296.
Ok(SigningArtifact {
input_digest: input_hash.to_owned(),
cert: cert.to_der()?,
signature: signature_bytes,
log_entry,
})
}
/// Signs for the input with the session's identity. If the identity is expired,
/// [`SigstoreError::ExpiredSigningSession`] is returned.
pub async fn sign<R: AsyncRead + Unpin + Send + 'static>(
&self,
input: R,
) -> SigstoreResult<SigningArtifact> {
if self.is_expired() {
return Err(SigstoreError::ExpiredSigningSession());
}
let mut sync_input = SyncIoBridge::new(input);
let hasher = tokio::task::spawn_blocking(move || -> SigstoreResult<_> {
let mut hasher = Sha256::new();
io::copy(&mut sync_input, &mut hasher)?;
Ok(hasher)
})
.await??;
self.sign_digest(hasher).await
}
}
pub mod blocking {
use super::{SigningSession as AsyncSigningSession, *};
/// A synchronous Sigstore signing session.
///
/// Sessions hold a provided user identity and key materials tied to that identity. A single
/// session may be used to sign multiple items. For more information, see [`SigningSession::sign`].
///
/// This signing session operates synchronously, thus it cannot be used in an asynchronous context.
/// To construct an asynchronous [`SigningSession`], use [`SigningContext::signer()`].
pub struct SigningSession<'ctx> {
inner: AsyncSigningSession<'ctx>,
rt: tokio::runtime::Runtime,
}
impl<'ctx> SigningSession<'ctx> {
pub(crate) fn new(ctx: &'ctx SigningContext, token: IdentityToken) -> SigstoreResult<Self> {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
let inner = rt.block_on(AsyncSigningSession::new(ctx, token))?;
Ok(Self { inner, rt })
}
/// Check if the session's identity token or key material is expired.
///
/// If the session is expired, it cannot be used for signing operations, and a new session
/// must be created with a fresh identity token.
pub fn is_expired(&self) -> bool {
self.inner.is_expired()
}
/// Signs for the input with the session's identity. If the identity is expired,
/// [`SigstoreError::ExpiredSigningSession`] is returned.
pub fn sign<R: Read>(&self, mut input: R) -> SigstoreResult<SigningArtifact> {
let mut hasher = Sha256::new();
io::copy(&mut input, &mut hasher)?;
self.rt.block_on(self.inner.sign_digest(hasher))
}
}
}
/// A Sigstore signing context.
///
/// Contexts hold Fulcio (CA) and Rekor (CT) configurations which signing sessions can be
/// constructed against. Use [`SigningContext::production`] to create a context against
/// the public-good Sigstore infrastructure.
pub struct SigningContext {
fulcio: FulcioClient,
rekor_config: RekorConfiguration,
ctfe_keyring: Keyring,
}
impl SigningContext {
/// Manually constructs a [`SigningContext`] from its constituent data.
pub fn new(
fulcio: FulcioClient,
rekor_config: RekorConfiguration,
ctfe_keyring: Keyring,
) -> Self {
Self {
fulcio,
rekor_config,
ctfe_keyring,
}
}
/// Returns a [`SigningContext`] configured against the public-good production Sigstore
/// infrastructure.
#[cfg_attr(docsrs, doc(cfg(feature = "sigstore-trust-root")))]
#[cfg(feature = "sigstore-trust-root")]
pub async fn async_production() -> SigstoreResult<Self> {
let trust_root = SigstoreTrustRoot::new(None).await?;
Ok(Self::new(
FulcioClient::new(
Url::parse(FULCIO_ROOT).expect("constant FULCIO root fails to parse!"),
crate::fulcio::TokenProvider::Oauth(OauthTokenProvider::default()),
),
Default::default(),
Keyring::new(trust_root.ctfe_keys()?.values().copied())?,
))
}
/// Returns a [`SigningContext`] configured against the public-good production Sigstore
/// infrastructure.
///
/// Async callers should use [`SigningContext::async_production`].
#[cfg_attr(docsrs, doc(cfg(feature = "sigstore-trust-root")))]
#[cfg(feature = "sigstore-trust-root")]
pub fn production() -> SigstoreResult<Self> {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
rt.block_on(Self::async_production())
}
/// Configures and returns a [`SigningSession`] with the held context.
pub async fn signer(
&self,
identity_token: IdentityToken,
) -> SigstoreResult<SigningSession<'_>> {
SigningSession::new(self, identity_token).await
}
/// Configures and returns a [`blocking::SigningSession`] with the held context.
///
/// Async contexts must use [`SigningContext::signer`].
pub fn blocking_signer(
&self,
identity_token: IdentityToken,
) -> SigstoreResult<blocking::SigningSession<'_>> {
blocking::SigningSession::new(self, identity_token)
}
}
/// A signature and its associated metadata.
pub struct SigningArtifact {
input_digest: Vec<u8>,
cert: Vec<u8>,
signature: Vec<u8>,
log_entry: TransparencyLogEntry,
}
impl SigningArtifact {
/// Consumes the signing artifact and produces a Sigstore [`Bundle`].
///
/// The resulting bundle can be serialized with [`serde_json`].
pub fn to_bundle(self) -> Bundle {
// NOTE: We explicitly only include the leaf certificate in the bundle's "chain"
// here: the specs explicitly forbid the inclusion of the root certificate,
// and discourage inclusion of any intermediates (since they're in the root of
// trust already).
let x509_certificate_chain = X509CertificateChain {
certificates: vec![X509Certificate {
raw_bytes: self.cert,
}],
};
let verification_material = Some(VerificationMaterial {
timestamp_verification_data: None,
tlog_entries: vec![self.log_entry],
content: Some(verification_material::Content::X509CertificateChain(
x509_certificate_chain,
)),
});
let message_signature = MessageSignature {
message_digest: Some(HashOutput {
algorithm: HashAlgorithm::Sha2256.into(),
digest: self.input_digest,
}),
signature: self.signature,
};
Bundle {
media_type: Version::Bundle0_2.to_string(),
verification_material,
content: Some(bundle::Content::MessageSignature(message_signature)),
}
}
}
================================================
FILE: src/bundle/verify/mod.rs
================================================
//
// 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.
//! Types for verifying Sigstore bundles with policies.
mod models;
pub use models::{VerificationError, VerificationResult};
pub mod policy;
pub use policy::{PolicyError, VerificationPolicy};
mod verifier;
pub use verifier::*;
================================================
FILE: src/bundle/verify/models.rs
================================================
//
// 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.
use std::str::FromStr;
use crate::{
bundle::{Bundle, models::Version as BundleVersion},
crypto::certificate::{CertificateValidationError, is_leaf, is_root_ca},
rekor::models as rekor,
};
use base64::{Engine as _, engine::general_purpose::STANDARD as base64};
use sigstore_protobuf_specs::dev::sigstore::{
bundle::v1::{bundle, verification_material},
rekor::v1::{InclusionProof, TransparencyLogEntry},
};
use thiserror::Error;
use tracing::{debug, error, warn};
use x509_cert::{
Certificate,
der::{Decode, EncodePem},
};
use super::policy::PolicyError;
#[derive(Error, Debug)]
pub enum Bundle01ProfileErrorKind {
#[error("bundle must contain inclusion promise")]
InclusionPromiseMissing,
}
#[derive(Error, Debug)]
pub enum Bundle02ProfileErrorKind {
#[error("bundle must contain inclusion proof")]
InclusionProofMissing,
#[error("bundle must contain checkpoint")]
CheckpointMissing,
}
#[derive(Error, Debug)]
#[error(transparent)]
pub enum BundleProfileErrorKind {
Bundle01Profile(#[from] Bundle01ProfileErrorKind),
Bundle02Profile(#[from] Bundle02ProfileErrorKind),
#[error("unknown bundle profile {0}")]
Unknown(String),
}
#[derive(Error, Debug)]
pub enum BundleErrorKind {
#[error("bundle missing VerificationMaterial")]
VerificationMaterialMissing,
#[error("bundle includes unsupported VerificationMaterial::Content")]
VerificationMaterialContentUnsupported,
#[error("bundle's certificate(s) are malformed")]
CertificateMalformed(#[source] x509_cert::der::Error),
#[error("bundle contains a root certificate")]
RootInChain,
#[error("bundle does not contain the signing (leaf) certificate")]
NoLeaf(#[source] CertificateValidationError),
#[error("bundle does not contain any certificates")]
CertificatesMissing,
#[error("bundle does not contain signature")]
SignatureMissing,
#[error("bundle includes unsupported DSSE signature")]
DsseUnsupported,
#[error("bundle needs 1 tlog entry, got {0}")]
TlogEntry(usize),
#[error(transparent)]
BundleProfile(#[from] BundleProfileErrorKind),
}
#[derive(Error, Debug)]
pub enum CertificateErrorKind {
#[error("certificate malformed")]
Malformed(#[source] webpki::Error),
#[error("certificate expired before time of signing")]
Expired,
#[error("certificate SCT verification failed")]
Sct(#[source] crate::crypto::transparency::SCTError),
#[error("certificate verification failed")]
VerificationFailed(#[source] webpki::Error),
}
#[derive(Error, Debug)]
pub enum SignatureErrorKind {
#[error("unsupported signature algorithm")]
AlgoUnsupported(#[source] crate::errors::SigstoreError),
#[error("signature verification failed")]
VerificationFailed(#[source] crate::errors::SigstoreError),
#[error("signature transparency materials are inconsistent")]
Transparency,
}
#[derive(Error, Debug)]
#[error(transparent)]
pub enum VerificationError {
#[error("unable to read input")]
Input(#[source] std::io::Error),
Bundle(#[from] BundleErrorKind),
Certificate(#[from] CertificateErrorKind),
Signature(#[from] SignatureErrorKind),
Policy(#[from] PolicyError),
}
pub type VerificationResult = Result<(), VerificationError>;
pub struct CheckedBundle {
pub(crate) certificate: Certificate,
pub(crate) signature: Vec<u8>,
tlog_entry: TransparencyLogEntry,
}
impl TryFrom<Bundle> for CheckedBundle {
type Error = BundleErrorKind;
fn try_from(input: Bundle) -> Result<Self, Self::Error> {
let (content, mut tlog_entries) = match input.verification_material {
Some(m) => (m.content, m.tlog_entries),
_ => return Err(BundleErrorKind::VerificationMaterialMissing),
};
// Parse the certificates. The first entry in the chain MUST be a leaf certificate, and the
// rest of the chain MUST NOT include a root CA or any intermediate CAs that appear in an
// independent root of trust.
let certs = match content {
Some(verification_material::Content::X509CertificateChain(ch)) => ch.certificates,
Some(verification_material::Content::Certificate(cert)) => {
vec![cert]
}
_ => return Err(BundleErrorKind::VerificationMaterialContentUnsupported),
};
let certs = certs
.iter()
.map(|c| c.raw_bytes.as_slice())
.map(Certificate::from_der)
.collect::<Result<Vec<_>, _>>()
.map_err(BundleErrorKind::CertificateMalformed)?;
let [leaf_cert, chain_certs @ ..] = &certs[..] else {
return Err(BundleErrorKind::CertificatesMissing);
};
is_leaf(leaf_cert).map_err(BundleErrorKind::NoLeaf)?;
for chain_cert in chain_certs {
if is_root_ca(chain_cert).is_ok() {
return Err(BundleErrorKind::RootInChain);
}
}
let signature = match input.content.ok_or(BundleErrorKind::SignatureMissing)? {
bundle::Content::MessageSignature(s) => s.signature,
_ => return Err(BundleErrorKind::DsseUnsupported),
};
if tlog_entries.len() != 1 {
return Err(BundleErrorKind::TlogEntry(tlog_entries.len()));
}
let tlog_entry = tlog_entries.remove(0);
let (inclusion_promise, inclusion_proof) =
(&tlog_entry.inclusion_promise, &tlog_entry.inclusion_proof);
// `inclusion_proof` is a required field in the current protobuf spec,
// but older versions of Rekor didn't provide it. Check invariants
// here and selectively allow for this case.
//
// https://github.com/sigstore/sigstore-python/pull/634#discussion_r1182769140
let check_01_bundle = || -> Result<(), BundleProfileErrorKind> {
if inclusion_promise.is_none() {
return Err(Bundle01ProfileErrorKind::InclusionPromiseMissing)?;
}
if matches!(
inclusion_proof,
Some(InclusionProof {
checkpoint: None,
..
})
) {
debug!("0.1 bundle contains inclusion proof without checkpoint");
}
Ok(())
};
let check_02_bundle = || -> Result<(), BundleProfileErrorKind> {
if inclusion_proof.is_none() {
error!("bundle must contain inclusion proof");
return Err(Bundle02ProfileErrorKind::InclusionProofMissing)?;
}
if matches!(
inclusion_proof,
Some(InclusionProof {
checkpoint: None,
..
})
) {
error!("bundle must contain checkpoint");
return Err(Bundle02ProfileErrorKind::CheckpointMissing)?;
}
Ok(())
};
match BundleVersion::from_str(&input.media_type) {
Ok(BundleVersion::Bundle0_1) => check_01_bundle()?,
Ok(BundleVersion::Bundle0_2) => check_02_bundle()?,
Err(_) => return Err(BundleProfileErrorKind::Unknown(input.media_type))?,
}
Ok(Self {
certificate: leaf_cert.clone(),
signature,
tlog_entry,
})
}
}
impl CheckedBundle {
/// Retrieves and checks consistency of the bundle's [TransparencyLogEntry].
pub fn tlog_entry(&self, offline: bool, input_digest: &[u8]) -> Option<&TransparencyLogEntry> {
let base64_pem_certificate =
base64.encode(self.certificate.to_pem(pkcs8::LineEnding::LF).ok()?);
let expected_entry = rekor::Hashedrekord {
kind: "hashedrekord".to_owned(),
api_version: "0.0.1".to_owned(),
spec: rekor::hashedrekord::Spec {
signature: rekor::hashedrekord::Signature {
content: base64.encode(&self.signature),
public_key: rekor::hashedrekord::PublicKey::new(base64_pem_certificate),
},
data: rekor::hashedrekord::Data {
hash: rekor::hashedrekord::Hash {
algorithm: rekor::hashedrekord::AlgorithmKind::sha256,
value: hex::encode(input_digest),
},
},
},
};
let entry = if !offline && self.tlog_entry.inclusion_proof.is_none() {
warn!("online rekor fetching is not implemented yet, but is necessary for this bundle");
return None;
} else {
&self.tlog_entry
};
let actual: serde_json::Value =
serde_json::from_slice(&self.tlog_entry.canonicalized_body).ok()?;
let expected: serde_json::Value = serde_json::to_value(expected_entry).ok()?;
if actual != expected {
return None;
}
Some(entry)
}
}
================================================
FILE: src/bundle/verify/policy.rs
================================================
// 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.
//! Verification constraints for certificate metadata.
//!
//! <https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md#extension-values>
use const_oid::ObjectIdentifier;
use thiserror::Error;
use tracing::warn;
use x509_cert::ext::pkix::{SubjectAltName, name::GeneralName};
macro_rules! oids {
($($name:ident = $value:literal),+) => {
$(const $name: ObjectIdentifier = ObjectIdentifier::new_unwrap($value);)+
};
}
macro_rules! impl_policy {
($policy:ident, $oid:expr, $doc:literal) => {
#[doc = $doc]
pub struct $policy(pub String);
impl const_oid::AssociatedOid for $policy {
const OID: ObjectIdentifier = $oid;
}
impl SingleX509ExtPolicy for $policy {
fn new<S: AsRef<str>>(val: S) -> Self {
Self(val.as_ref().to_owned())
}
fn name() -> &'static str {
stringify!($policy)
}
fn value(&self) -> &str {
&self.0
}
}
};
}
oids! {
OIDC_ISSUER_OID = "1.3.6.1.4.1.57264.1.1",
OIDC_GITHUB_WORKFLOW_TRIGGER_OID = "1.3.6.1.4.1.57264.1.2",
OIDC_GITHUB_WORKFLOW_SHA_OID = "1.3.6.1.4.1.57264.1.3",
OIDC_GITHUB_WORKFLOW_NAME_OID = "1.3.6.1.4.1.57264.1.4",
OIDC_GITHUB_WORKFLOW_REPOSITORY_OID = "1.3.6.1.4.1.57264.1.5",
OIDC_GITHUB_WORKFLOW_REF_OID = "1.3.6.1.4.1.57264.1.6",
OTHERNAME_OID = "1.3.6.1.4.1.57264.1.7"
}
#[derive(Error, Debug)]
pub enum PolicyError {
#[error("did not find exactly 1 of the required extension in the certificate")]
ExtensionNotFound,
#[error("certificate's {extension} does not match (got {actual}, expected {expected})")]
ExtensionCheckFailed {
extension: String,
expected: String,
actual: String,
},
#[error("{0} of {total} policies failed: {1}\n- ",
errors.len(),
errors.iter().map(|e| e.to_string()).collect::<Vec<_>>().join("\n- ")
)]
AllOf {
total: usize,
errors: Vec<PolicyError>,
},
#[error("0 of {total} policies succeeded")]
AnyOf { total: usize },
}
pub type PolicyResult = Result<(), PolicyError>;
/// A policy that checks a single textual value against a X.509 extension.
pub trait SingleX509ExtPolicy {
fn new<S: AsRef<str>>(val: S) -> Self;
fn name() -> &'static str;
fn value(&self) -> &str;
}
impl<T: SingleX509ExtPolicy + const_oid::AssociatedOid> VerificationPolicy for T {
fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
let extensions = cert.tbs_certificate.extensions.as_deref().unwrap_or(&[]);
let mut extensions = extensions.iter().filter(|ext| ext.extn_id == T::OID);
// Check for exactly one extension.
let (Some(ext), None) = (extensions.next(), extensions.next()) else {
return Err(PolicyError::ExtensionNotFound);
};
// Parse raw string without DER encoding.
let val = std::str::from_utf8(ext.extn_value.as_bytes())
.or(Err(PolicyError::ExtensionNotFound))?;
if val != self.value() {
return Err(PolicyError::ExtensionCheckFailed {
extension: T::name().to_owned(),
expected: self.value().to_owned(),
actual: val.to_owned(),
});
}
Ok(())
}
}
impl_policy!(
OIDCIssuer,
OIDC_ISSUER_OID,
"Checks the certificate's OIDC issuer."
);
impl_policy!(
GitHubWorkflowTrigger,
OIDC_GITHUB_WORKFLOW_TRIGGER_OID,
"Checks the certificate's GitHub Actions workflow trigger."
);
impl_policy!(
GitHubWorkflowSHA,
OIDC_GITHUB_WORKFLOW_SHA_OID,
"Checks the certificate's GitHub Actions workflow commit SHA."
);
impl_policy!(
GitHubWorkflowName,
OIDC_GITHUB_WORKFLOW_NAME_OID,
"Checks the certificate's GitHub Actions workflow name."
);
impl_policy!(
GitHubWorkflowRepository,
OIDC_GITHUB_WORKFLOW_REPOSITORY_OID,
"Checks the certificate's GitHub Actions workflow repository."
);
impl_policy!(
GitHubWorkflowRef,
OIDC_GITHUB_WORKFLOW_REF_OID,
"Checks the certificate's GitHub Actions workflow ref."
);
/// An interface that all policies must conform to.
pub trait VerificationPolicy {
fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult;
}
/// The "any of" policy, corresponding to a logical OR between child policies.
///
/// An empty list of child policies is considered trivially invalid.
pub struct AnyOf<'a> {
children: Vec<&'a dyn VerificationPolicy>,
}
impl<'a> AnyOf<'a> {
pub fn new<I>(policies: I) -> Self
where
I: IntoIterator<Item = &'a dyn VerificationPolicy>,
{
Self {
children: policies.into_iter().collect(),
}
}
}
impl VerificationPolicy for AnyOf<'_> {
fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
self.children
.iter()
.find(|policy| policy.verify(cert).is_err())
.map_or(Ok(()), |_| {
Err(PolicyError::AnyOf {
total: self.children.len(),
})
})
}
}
/// The "all of" policy, corresponding to a logical AND between child policies.
///
/// An empty list of child policies is considered trivially invalid.
pub struct AllOf<'a> {
children: Vec<&'a dyn VerificationPolicy>,
}
impl<'a> AllOf<'a> {
pub fn new<I>(policies: I) -> Option<Self>
where
I: IntoIterator<Item = &'a dyn VerificationPolicy>,
{
let children: Vec<_> = policies.into_iter().collect();
// Without this, we'd be able to construct an `AllOf` containing an empty list of child
// policies. This is almost certainly not what the user wants and is a potential source
// of API misuse, so we explicitly disallow it.
if children.is_empty() {
warn!("attempted to construct an AllOf with an empty list of child policies");
return None;
}
Some(Self { children })
}
}
impl VerificationPolicy for AllOf<'_> {
fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
let results = self.children.iter().map(|policy| policy.verify(cert).err());
let failures: Vec<_> = results.flatten().collect();
if !failures.is_empty() {
return Err(PolicyError::AllOf {
total: self.children.len(),
errors: failures,
});
}
Ok(())
}
}
/// Verifies the certificate's "identity", corresponding to the X.509v3 SAN.
/// Identities are verified modulo an OIDC issuer, so the issuer's URI
/// is also required.
///
/// Supported SAN types include emails, URIs, and Sigstore-specific "other names".
pub struct Identity {
identity: String,
issuer: OIDCIssuer,
}
impl Identity {
pub fn new<A, B>(identity: A, issuer: B) -> Self
where
A: AsRef<str>,
B: AsRef<str>,
{
Self {
identity: identity.as_ref().to_owned(),
issuer: OIDCIssuer::new(issuer),
}
}
}
impl VerificationPolicy for Identity {
fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
self.issuer.verify(cert)?;
let (_, san): (bool, SubjectAltName) = match cert.tbs_certificate.get() {
Ok(Some(result)) => result,
_ => return Err(PolicyError::ExtensionNotFound),
};
let names: Vec<_> = san
.0
.iter()
.filter_map(|name| match name {
GeneralName::Rfc822Name(name) => Some(name.as_str()),
GeneralName::UniformResourceIdentifier(name) => Some(name.as_str()),
GeneralName::OtherName(name) if name.type_id == OTHERNAME_OID => {
std::str::from_utf8(name.value.value()).ok()
}
_ => None,
})
.collect();
if !names.contains(&self.identity.as_str()) {
return Err(PolicyError::ExtensionCheckFailed {
extension: "SubjectAltName".to_owned(),
expected: self.identity.clone(),
actual: names.join(", "),
});
}
Ok(())
}
}
================================================
FILE: src/bundle/verify/verifier.rs
================================================
// 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.
//! Verifiers: async and blocking.
use std::io::{self, Read};
use pki_types::{CertificateDer, UnixTime};
use sha2::{Digest, Sha256};
use tokio::io::{AsyncRead, AsyncReadExt};
use tracing::debug;
use x509_cert::der::Encode;
use crate::{
bundle::Bundle,
crypto::{
CertificatePool, CosignVerificationKey, Signature,
keyring::Keyring,
transparency::{CertificateEmbeddedSCT, verify_sct},
},
errors::Result as SigstoreResult,
rekor::apis::configuration::Configuration as RekorConfiguration,
trust::TrustRoot,
};
#[cfg(feature = "sigstore-trust-root")]
use crate::trust::sigstore::SigstoreTrustRoot;
use super::{
VerificationError, VerificationResult,
models::{CertificateErrorKind, CheckedBundle, SignatureErrorKind},
policy::VerificationPolicy,
};
/// An asynchronous Sigstore verifier.
///
/// For synchronous usage, see [`Verifier`].
pub struct Verifier {
#[allow(dead_code)]
rekor_config: RekorConfiguration,
cert_pool: CertificatePool,
ctfe_keyring: Keyring,
}
impl Verifier {
/// Constructs a [`Verifier`].
///
/// For verifications against the public-good trust root, use [`Verifier::production()`].
pub fn new<R: TrustRoot>(
rekor_config: RekorConfiguration,
trust_repo: R,
) -> SigstoreResult<Self> {
let cert_pool = CertificatePool::from_certificates(trust_repo.fulcio_certs()?, [])?;
let ctfe_keyring = Keyring::new(trust_repo.ctfe_keys()?.values().copied())?;
Ok(Self {
rekor_config,
cert_pool,
ctfe_keyring,
})
}
/// Verifies an input digest against the given Sigstore Bundle, ensuring conformanc
gitextract_mgzc87yz/
├── .cargo/
│ └── audit.toml
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── auto-publish-crates-upon-release.yml
│ ├── conformance.yml
│ ├── security-audit.yml
│ ├── tests.yml
│ └── zizmor.yml
├── .gitignore
├── .taplo.toml
├── CHANGELOG.md
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTORS.md
├── COPYRIGHT.txt
├── Cargo.toml
├── LICENSE
├── Makefile
├── README.md
├── clippy.toml
├── examples/
│ ├── README.md
│ ├── bundle/
│ │ ├── README.md
│ │ └── main.rs
│ ├── cosign/
│ │ ├── sign/
│ │ │ ├── README.md
│ │ │ └── main.rs
│ │ ├── trustroot/
│ │ │ └── main.rs
│ │ ├── verify/
│ │ │ ├── README.md
│ │ │ └── main.rs
│ │ ├── verify-blob/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ └── main.rs
│ │ └── verify-bundle/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── main.rs
│ │ └── run.sh
│ ├── fulcio/
│ │ └── cert/
│ │ └── main.rs
│ ├── key_interface/
│ │ ├── README.md
│ │ ├── key_pair_gen_and_export/
│ │ │ └── main.rs
│ │ ├── key_pair_gen_sign_verify/
│ │ │ └── main.rs
│ │ └── key_pair_import/
│ │ ├── ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key
│ │ ├── ECDSA_P256_ASN1_PRIVATE_DER.key
│ │ ├── ECDSA_P256_ASN1_PRIVATE_PEM.key
│ │ ├── ECDSA_P256_ASN1_PUBLIC_DER.pub
│ │ ├── ECDSA_P256_ASN1_PUBLIC_PEM.pub
│ │ └── main.rs
│ ├── openidflow/
│ │ ├── README.md
│ │ └── openidconnect/
│ │ └── main.rs
│ └── rekor/
│ ├── README.md
│ ├── create_log_entry/
│ │ └── main.rs
│ ├── get_log_entry_by_index/
│ │ └── main.rs
│ ├── get_log_entry_by_uuid/
│ │ └── main.rs
│ ├── get_log_info/
│ │ └── main.rs
│ ├── get_log_proof/
│ │ └── main.rs
│ ├── get_public_key/
│ │ └── main.rs
│ ├── merkle_proofs/
│ │ ├── consistency.rs
│ │ └── inclusion.rs
│ ├── search_index/
│ │ └── main.rs
│ └── search_log_query/
│ └── main.rs
├── rust-toolchain.toml
├── src/
│ ├── bundle/
│ │ ├── mod.rs
│ │ ├── models.rs
│ │ ├── sign.rs
│ │ └── verify/
│ │ ├── mod.rs
│ │ ├── models.rs
│ │ ├── policy.rs
│ │ └── verifier.rs
│ ├── cosign/
│ │ ├── bundle.rs
│ │ ├── client.rs
│ │ ├── client_builder.rs
│ │ ├── constants.rs
│ │ ├── constraint/
│ │ │ ├── annotation.rs
│ │ │ ├── mod.rs
│ │ │ └── signature.rs
│ │ ├── mod.rs
│ │ ├── payload/
│ │ │ ├── mod.rs
│ │ │ └── simple_signing.rs
│ │ ├── signature_layers.rs
│ │ └── verification_constraint/
│ │ ├── annotation_verifier.rs
│ │ ├── cert_subject_email_verifier.rs
│ │ ├── cert_subject_url_verifier.rs
│ │ ├── certificate_verifier.rs
│ │ ├── mod.rs
│ │ └── public_key_verifier.rs
│ ├── crypto/
│ │ ├── certificate.rs
│ │ ├── certificate_pool.rs
│ │ ├── keyring.rs
│ │ ├── merkle/
│ │ │ ├── mod.rs
│ │ │ ├── proof_verification.rs
│ │ │ └── rfc6962.rs
│ │ ├── mod.rs
│ │ ├── signing_key/
│ │ │ ├── ecdsa/
│ │ │ │ ├── ec.rs
│ │ │ │ └── mod.rs
│ │ │ ├── ed25519.rs
│ │ │ ├── kdf.rs
│ │ │ ├── mod.rs
│ │ │ └── rsa/
│ │ │ ├── keypair.rs
│ │ │ └── mod.rs
│ │ ├── transparency.rs
│ │ └── verification_key.rs
│ ├── errors.rs
│ ├── fulcio/
│ │ ├── mod.rs
│ │ ├── models.rs
│ │ └── oauth.rs
│ ├── lib.rs
│ ├── mock_client.rs
│ ├── oauth/
│ │ ├── http_client.rs
│ │ ├── mod.rs
│ │ ├── openidflow.rs
│ │ └── token.rs
│ ├── registry/
│ │ ├── config.rs
│ │ ├── mod.rs
│ │ ├── oci_caching_client.rs
│ │ ├── oci_client.rs
│ │ └── oci_reference.rs
│ ├── rekor/
│ │ ├── apis/
│ │ │ ├── configuration.rs
│ │ │ ├── entries_api.rs
│ │ │ ├── index_api.rs
│ │ │ ├── mod.rs
│ │ │ ├── pubkey_api.rs
│ │ │ └── tlog_api.rs
│ │ ├── mod.rs
│ │ └── models/
│ │ ├── alpine.rs
│ │ ├── alpine_all_of.rs
│ │ ├── checkpoint.rs
│ │ ├── consistency_proof.rs
│ │ ├── error.rs
│ │ ├── hashedrekord.rs
│ │ ├── hashedrekord_all_of.rs
│ │ ├── helm.rs
│ │ ├── helm_all_of.rs
│ │ ├── inactive_shard_log_info.rs
│ │ ├── inclusion_proof.rs
│ │ ├── intoto.rs
│ │ ├── intoto_all_of.rs
│ │ ├── jar.rs
│ │ ├── jar_all_of.rs
│ │ ├── log_entry.rs
│ │ ├── log_info.rs
│ │ ├── mod.rs
│ │ ├── proposed_entry.rs
│ │ ├── rekord.rs
│ │ ├── rekord_all_of.rs
│ │ ├── rfc3161.rs
│ │ ├── rfc3161_all_of.rs
│ │ ├── rpm.rs
│ │ ├── rpm_all_of.rs
│ │ ├── search_index.rs
│ │ ├── search_index_public_key.rs
│ │ ├── search_log_query.rs
│ │ ├── tuf.rs
│ │ └── tuf_all_of.rs
│ └── trust/
│ ├── mod.rs
│ └── sigstore/
│ ├── constants.rs
│ ├── mod.rs
│ └── transport.rs
├── tests/
│ ├── conformance/
│ │ ├── Cargo.toml
│ │ └── conformance.rs
│ └── data/
│ └── keys/
│ ├── cosign_generated_encrypted_empty_private.key
│ ├── ecdsa_encrypted_private.key
│ ├── ecdsa_private.key
│ ├── ed25519_encrypted_private.key
│ ├── ed25519_private.key
│ ├── rsa_encrypted_private.key
│ └── rsa_private.key
└── trust_root/
└── prod/
├── root.json
└── trusted_root.json
SYMBOL INDEX (919 symbols across 112 files)
FILE: examples/bundle/main.rs
type Cli (line 14) | struct Cli {
type Commands (line 24) | enum Commands {
type SignArgs (line 32) | struct SignArgs {
type VerifyArgs (line 38) | struct VerifyArgs {
function main (line 51) | pub fn main() {
function sign (line 68) | fn sign(artifact_path: &PathBuf) {
function verify (line 112) | fn verify(artifact_path: &PathBuf, identity: &str, issuer: &str) {
function authorize (line 139) | fn authorize() -> oauth::IdentityToken {
FILE: examples/cosign/sign/main.rs
type Cli (line 38) | struct Cli {
function run_app (line 68) | async fn run_app(cli: &Cli) -> anyhow::Result<()> {
function build_auth (line 139) | fn build_auth(reference: &OciReference) -> Auth {
function main (line 165) | pub async fn main() {
FILE: examples/cosign/trustroot/main.rs
function main (line 5) | pub async fn main() -> Result<()> {
FILE: examples/cosign/verify-blob/main.rs
type Cli (line 31) | struct Cli {
function main (line 49) | pub async fn main() {
FILE: examples/cosign/verify-bundle/main.rs
type Cli (line 28) | struct Cli {
function main (line 50) | pub async fn main() {
FILE: examples/cosign/verify/main.rs
type Cli (line 43) | struct Cli {
function run_app (line 108) | async fn run_app(
function fulcio_and_rekor_data (line 231) | async fn fulcio_and_rekor_data(cli: &Cli) -> anyhow::Result<Box<dyn sigs...
function main (line 268) | pub async fn main() {
function parse_cert_bundle (line 326) | fn parse_cert_bundle(bundle_path: &str) -> Result<Vec<sigstore::registry...
FILE: examples/fulcio/cert/main.rs
function main (line 10) | async fn main() {
FILE: examples/key_interface/key_pair_gen_and_export/main.rs
constant PASSWORD (line 19) | const PASSWORD: &str = "example password";
function main (line 21) | fn main() -> Result<()> {
FILE: examples/key_interface/key_pair_gen_sign_verify/main.rs
constant DATA_TO_BE_SIGNED (line 19) | const DATA_TO_BE_SIGNED: &str = "this is an example data to be signed";
function main (line 21) | fn main() -> Result<()> {
FILE: examples/key_interface/key_pair_import/main.rs
constant PASSWORD (line 22) | const PASSWORD: &str = "password";
constant ECDSA_P256_ASN1_PUBLIC_PEM (line 24) | const ECDSA_P256_ASN1_PUBLIC_PEM: &[u8] = include_bytes!("./ECDSA_P256_A...
constant ECDSA_P256_ASN1_PUBLIC_DER (line 25) | const ECDSA_P256_ASN1_PUBLIC_DER: &[u8] = include_bytes!("./ECDSA_P256_A...
constant ECDSA_P256_ASN1_PRIVATE_PEM (line 26) | const ECDSA_P256_ASN1_PRIVATE_PEM: &[u8] = include_bytes!("./ECDSA_P256_...
constant ECDSA_P256_ASN1_PRIVATE_DER (line 27) | const ECDSA_P256_ASN1_PRIVATE_DER: &[u8] = include_bytes!("./ECDSA_P256_...
constant ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM (line 28) | const ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM: &[u8] =
function main (line 31) | fn main() -> Result<()> {
FILE: examples/openidflow/openidconnect/main.rs
function main (line 19) | fn main() -> Result<(), anyhow::Error> {
FILE: examples/rekor/create_log_entry/main.rs
function create_signer (line 29) | async fn create_signer() -> SigStoreSigner {
function get_file_sha256sum (line 36) | async fn get_file_sha256sum(url: String) -> Result<(Vec<u8>, String), re...
function main (line 45) | async fn main() {
FILE: examples/rekor/get_log_entry_by_index/main.rs
function main (line 22) | async fn main() {
FILE: examples/rekor/get_log_entry_by_uuid/main.rs
function main (line 21) | async fn main() {
FILE: examples/rekor/get_log_info/main.rs
function main (line 20) | async fn main() {
FILE: examples/rekor/get_log_proof/main.rs
function main (line 22) | async fn main() {
FILE: examples/rekor/get_public_key/main.rs
function main (line 22) | async fn main() {
FILE: examples/rekor/merkle_proofs/consistency.rs
type Args (line 9) | struct Args {
function main (line 21) | async fn main() -> Result<(), Box<dyn std::error::Error>> {
FILE: examples/rekor/merkle_proofs/inclusion.rs
type Args (line 9) | struct Args {
function main (line 17) | async fn main() -> Result<(), Box<dyn std::error::Error>> {
FILE: examples/rekor/search_index/main.rs
function main (line 23) | async fn main() {
FILE: examples/rekor/search_log_query/main.rs
function main (line 25) | async fn main() {
FILE: src/bundle/models.rs
type Version (line 15) | pub enum Version {
method fmt (line 21) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type Err (line 30) | type Err = ();
method from_str (line 32) | fn from_str(s: &str) -> Result<Self, Self::Err> {
function decode_hex (line 42) | fn decode_hex<S: AsRef<str>>(hex: S) -> Result<Vec<u8>, ()> {
type Error (line 47) | type Error = ();
method try_from (line 49) | fn try_from(value: RekorInclusionProof) -> Result<Self, Self::Error> {
type Error (line 70) | type Error = ();
method try_from (line 72) | fn try_from(value: RekorLogEntry) -> Result<Self, Self::Error> {
FILE: src/bundle/sign.rs
type SigningSession (line 65) | pub struct SigningSession<'ctx> {
function new (line 73) | async fn new(
function materials (line 86) | async fn materials(
function is_expired (line 122) | pub fn is_expired(&self) -> bool {
function sign_digest (line 134) | async fn sign_digest(&self, hasher: Sha256) -> SigstoreResult<SigningArt...
function sign (line 193) | pub async fn sign<R: AsyncRead + Unpin + Send + 'static>(
type SigningSession (line 223) | pub struct SigningSession<'ctx> {
function new (line 229) | pub(crate) fn new(ctx: &'ctx SigningContext, token: IdentityToken) -> Si...
function is_expired (line 241) | pub fn is_expired(&self) -> bool {
function sign (line 247) | pub fn sign<R: Read>(&self, mut input: R) -> SigstoreResult<SigningArtif...
type SigningContext (line 260) | pub struct SigningContext {
method new (line 268) | pub fn new(
method async_production (line 284) | pub async fn async_production() -> SigstoreResult<Self> {
method production (line 302) | pub fn production() -> SigstoreResult<Self> {
method signer (line 311) | pub async fn signer(
method blocking_signer (line 321) | pub fn blocking_signer(
type SigningArtifact (line 330) | pub struct SigningArtifact {
method to_bundle (line 341) | pub fn to_bundle(self) -> Bundle {
FILE: src/bundle/verify/models.rs
type Bundle01ProfileErrorKind (line 39) | pub enum Bundle01ProfileErrorKind {
type Bundle02ProfileErrorKind (line 45) | pub enum Bundle02ProfileErrorKind {
type BundleProfileErrorKind (line 55) | pub enum BundleProfileErrorKind {
type BundleErrorKind (line 65) | pub enum BundleErrorKind {
type CertificateErrorKind (line 98) | pub enum CertificateErrorKind {
type SignatureErrorKind (line 113) | pub enum SignatureErrorKind {
type VerificationError (line 126) | pub enum VerificationError {
type VerificationResult (line 139) | pub type VerificationResult = Result<(), VerificationError>;
type CheckedBundle (line 141) | pub struct CheckedBundle {
type Error (line 149) | type Error = BundleErrorKind;
method try_from (line 151) | fn try_from(input: Bundle) -> Result<Self, Self::Error> {
method tlog_entry (line 256) | pub fn tlog_entry(&self, offline: bool, input_digest: &[u8]) -> Option...
FILE: src/bundle/verify/policy.rs
type PolicyError (line 67) | pub enum PolicyError {
type PolicyResult (line 91) | pub type PolicyResult = Result<(), PolicyError>;
type SingleX509ExtPolicy (line 94) | pub trait SingleX509ExtPolicy {
method new (line 95) | fn new<S: AsRef<str>>(val: S) -> Self;
method name (line 96) | fn name() -> &'static str;
method value (line 97) | fn value(&self) -> &str;
type VerificationPolicy (line 163) | pub trait VerificationPolicy {
method verify (line 101) | fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
method verify (line 164) | fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult;
method verify (line 186) | fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
method verify (line 225) | fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
method verify (line 264) | fn verify(&self, cert: &x509_cert::Certificate) -> PolicyResult {
type AnyOf (line 170) | pub struct AnyOf<'a> {
function new (line 175) | pub fn new<I>(policies: I) -> Self
type AllOf (line 201) | pub struct AllOf<'a> {
function new (line 206) | pub fn new<I>(policies: I) -> Option<Self>
type Identity (line 245) | pub struct Identity {
method new (line 251) | pub fn new<A, B>(identity: A, issuer: B) -> Self
FILE: src/bundle/verify/verifier.rs
type Verifier (line 49) | pub struct Verifier {
method new (line 60) | pub fn new<R: TrustRoot>(
method verify_digest (line 76) | pub async fn verify_digest<P>(
method verify (line 187) | pub async fn verify<R, P>(
method production (line 221) | pub async fn production() -> SigstoreResult<Verifier> {
method new (line 241) | pub fn new<R: TrustRoot>(
method verify_digest (line 255) | pub fn verify_digest<P>(
method verify (line 273) | pub fn verify<R, P>(
method production (line 295) | pub fn production() -> SigstoreResult<Verifier> {
type Verifier (line 232) | pub struct Verifier {
method new (line 60) | pub fn new<R: TrustRoot>(
method verify_digest (line 76) | pub async fn verify_digest<P>(
method verify (line 187) | pub async fn verify<R, P>(
method production (line 221) | pub async fn production() -> SigstoreResult<Verifier> {
method new (line 241) | pub fn new<R: TrustRoot>(
method verify_digest (line 255) | pub fn verify_digest<P>(
method verify (line 273) | pub fn verify<R, P>(
method production (line 295) | pub fn production() -> SigstoreResult<Verifier> {
FILE: src/cosign/bundle.rs
type SignedArtifactBundle (line 33) | pub struct SignedArtifactBundle {
method new_verified (line 48) | pub fn new_verified(
type Bundle (line 61) | pub struct Bundle {
method new_verified (line 71) | pub(crate) fn new_verified(
method verify_bundle (line 85) | pub(crate) fn verify_bundle(
type Payload (line 109) | pub struct Payload {
function build_correct_bundle (line 125) | fn build_correct_bundle() -> String {
function bundle_new_verified_success (line 139) | fn bundle_new_verified_success() {
function bundle_new_verified_failure_because_different_key_signed_the_bundle (line 150) | fn bundle_new_verified_failure_because_different_key_signed_the_bundle() {
function bundle_new_verified_failure_because_rekor_key_id_is_unknown (line 168) | fn bundle_new_verified_failure_because_rekor_key_id_is_unknown() {
function signedartifactbundle_new_verified_success (line 183) | fn signedartifactbundle_new_verified_success() {
FILE: src/cosign/client.rs
constant CONFIG_DATA (line 35) | pub const CONFIG_DATA: &str = "{}";
type Client (line 40) | pub struct Client {
method fetch_manifest_and_layers (line 144) | async fn fetch_manifest_and_layers(
method triangulate (line 49) | async fn triangulate(
method trusted_signature_layers (line 68) | async fn trusted_signature_layers(
method push_signature (line 97) | async fn push_signature(
function build_test_client (line 181) | fn build_test_client(mock_client: MockOciClient) -> Client {
function triangulate_sigstore_object (line 193) | async fn triangulate_sigstore_object() {
FILE: src/cosign/client_builder.rs
type ClientBuilder (line 58) | pub struct ClientBuilder<'a> {
function enable_registry_caching (line 70) | pub fn enable_registry_caching(mut self) -> Self {
function with_trust_repository (line 79) | pub fn with_trust_repository<R: TrustRoot + ?Sized>(mut self, repo: &'a ...
function with_oci_client_config (line 93) | pub fn with_oci_client_config(mut self, config: ClientConfig) -> Self {
function build (line 98) | pub fn build(self) -> Result<Client> {
constant OLD_REKOR_ED25519_KEY_DER (line 159) | const OLD_REKOR_ED25519_KEY_DER: &[u8] = &[
constant OLD_REKOR_ED25519_KEY_ID (line 165) | const OLD_REKOR_ED25519_KEY_ID: &str =
function client_builder_parses_ed25519_rekor_key (line 172) | fn client_builder_parses_ed25519_rekor_key() {
FILE: src/cosign/constants.rs
constant SIGSTORE_ISSUER_OID (line 18) | pub(crate) const SIGSTORE_ISSUER_OID: ObjectIdentifier =
constant SIGSTORE_GITHUB_WORKFLOW_TRIGGER_OID (line 20) | pub(crate) const SIGSTORE_GITHUB_WORKFLOW_TRIGGER_OID: ObjectIdentifier =
constant SIGSTORE_GITHUB_WORKFLOW_SHA_OID (line 22) | pub(crate) const SIGSTORE_GITHUB_WORKFLOW_SHA_OID: ObjectIdentifier =
constant SIGSTORE_GITHUB_WORKFLOW_NAME_OID (line 24) | pub(crate) const SIGSTORE_GITHUB_WORKFLOW_NAME_OID: ObjectIdentifier =
constant SIGSTORE_GITHUB_WORKFLOW_REPOSITORY_OID (line 26) | pub(crate) const SIGSTORE_GITHUB_WORKFLOW_REPOSITORY_OID: ObjectIdentifi...
constant SIGSTORE_GITHUB_WORKFLOW_REF_OID (line 28) | pub(crate) const SIGSTORE_GITHUB_WORKFLOW_REF_OID: ObjectIdentifier =
constant ED25519 (line 31) | pub(crate) const ED25519: ObjectIdentifier = ObjectIdentifier::new_unwra...
constant SIGSTORE_OCI_MEDIA_TYPE (line 33) | pub(crate) const SIGSTORE_OCI_MEDIA_TYPE: &str = "application/vnd.dev.co...
constant SIGSTORE_SIGNATURE_ANNOTATION (line 34) | pub(crate) const SIGSTORE_SIGNATURE_ANNOTATION: &str = "dev.cosignprojec...
constant SIGSTORE_BUNDLE_ANNOTATION (line 35) | pub(crate) const SIGSTORE_BUNDLE_ANNOTATION: &str = "dev.sigstore.cosign...
constant SIGSTORE_CERT_ANNOTATION (line 36) | pub(crate) const SIGSTORE_CERT_ANNOTATION: &str = "dev.sigstore.cosign/c...
FILE: src/cosign/constraint/annotation.rs
type AnnotationMarker (line 36) | pub struct AnnotationMarker {
method new (line 41) | pub fn new(annotations: HashMap<String, String>) -> Self {
method add_constraint (line 47) | fn add_constraint(&self, signature_layer: &mut SignatureLayer) -> Result...
FILE: src/cosign/constraint/mod.rs
type SignConstraintVec (line 37) | pub type SignConstraintVec = Vec<Box<dyn Constraint>>;
type SignConstraintRefVec (line 38) | pub type SignConstraintRefVec<'a> = Vec<&'a Box<dyn Constraint>>;
type Constraint (line 40) | pub trait Constraint: std::fmt::Debug {
method add_constraint (line 66) | fn add_constraint(&self, signature_layer: &mut SignatureLayer) -> Resu...
FILE: src/cosign/constraint/signature.rs
type PrivateKeySigner (line 34) | pub struct PrivateKeySigner {
method new_with_raw (line 41) | pub fn new_with_raw(
method new_with_signer (line 57) | pub fn new_with_signer(signer: SigStoreSigner) -> Self {
method add_constraint (line 63) | fn add_constraint(&self, signature_layer: &mut SignatureLayer) -> Result...
FILE: src/cosign/mod.rs
type CosignCapabilities (line 77) | pub trait CosignCapabilities {
method triangulate (line 80) | async fn triangulate(
method trusted_signature_layers (line 119) | async fn trusted_signature_layers(
method push_signature (line 146) | async fn push_signature(
method verify_blob (line 163) | fn verify_blob(cert: &str, signature: &str, blob: &[u8]) -> Result<()> {
method verify_blob_with_public_key (line 184) | fn verify_blob_with_public_key(public_key: &str, signature: &str, blob...
function verify_constraints (line 206) | pub fn verify_constraints<'a, 'b, I>(
function apply_constraints (line 256) | pub fn apply_constraints<'a, 'b, I>(
constant REKOR_PUB_KEY (line 302) | pub(crate) const REKOR_PUB_KEY: &str = r#"-----BEGIN PUBLIC KEY-----
constant REKOR_PUB_KEY_ID (line 307) | pub(crate) const REKOR_PUB_KEY_ID: &str =
constant FULCIO_CRT_1_PEM (line 310) | const FULCIO_CRT_1_PEM: &str = r#"-----BEGIN CERTIFICATE-----
constant FULCIO_CRT_2_PEM (line 324) | const FULCIO_CRT_2_PEM: &str = r#"-----BEGIN CERTIFICATE-----
constant SIGNED_IMAGE (line 339) | const SIGNED_IMAGE: &str = "busybox:1.34";
function get_fulcio_cert_pool (line 341) | pub(crate) fn get_fulcio_cert_pool() -> CertificatePool {
function get_rekor_public_key (line 352) | pub(crate) fn get_rekor_public_key() -> (String, CosignVerificationKey) {
function verify_constraints_all_satisfied (line 360) | fn verify_constraints_all_satisfied() {
function verify_constraints_none_satisfied (line 415) | fn verify_constraints_none_satisfied() {
function verify_constraints_some_unsatisfied (line 463) | fn verify_constraints_some_unsatisfied() {
function add_constrains_all_succeed (line 511) | fn add_constrains_all_succeed() {
function add_constrain_some_failed (line 531) | fn add_constrain_some_failed() {
function sign_verify_image (line 573) | async fn sign_verify_image(#[case] signing_scheme: SigningScheme) {
function prepare_image_to_be_signed (line 654) | async fn prepare_image_to_be_signed(client: &mut Client, image_ref: &Oci...
function registry_image (line 679) | fn registry_image() -> testcontainers::GenericImage {
FILE: src/cosign/payload/simple_signing.rs
constant CRITICAL_TYPE_NAME (line 28) | pub const CRITICAL_TYPE_NAME: &str = "cosign container image signature";
type SimpleSigning (line 31) | pub struct SimpleSigning {
method fmt (line 37) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method new (line 52) | pub fn new(image_ref: &OciReference, manifest_digest: &str) -> Self {
method satisfies_annotations (line 68) | pub fn satisfies_annotations(&self, annotations: &BTreeMap<String, Str...
method satisfies_manifest_digest (line 89) | pub fn satisfies_manifest_digest(&self, expected_digest: &str) -> bool {
type Critical (line 103) | pub struct Critical {
type Image (line 113) | pub struct Image {
type Identity (line 119) | pub struct Identity {
type Optional (line 124) | pub struct Optional {
method satisfies_annotations (line 136) | pub fn satisfies_annotations(&self, annotations: &BTreeMap<String, Str...
function simple_signing_does_not_satisfy_annotations_when_optional_is_none (line 213) | fn simple_signing_does_not_satisfy_annotations_when_optional_is_none() {
function simple_signing_satisfies_empty_annotations_even_when_optional_is_none (line 234) | fn simple_signing_satisfies_empty_annotations_even_when_optional_is_none...
function optional_has_all_the_required_annotations (line 253) | fn optional_has_all_the_required_annotations() {
function optional_does_not_satisfy_annotations_because_one_annotation_is_missing (line 270) | fn optional_does_not_satisfy_annotations_because_one_annotation_is_missi...
function optional_does_not_satisfy_annotations_because_one_annotation_has_different_value (line 285) | fn optional_does_not_satisfy_annotations_because_one_annotation_has_diff...
function optional_satisfies_annotations_when_no_annotation_is_provided (line 301) | fn optional_satisfies_annotations_when_no_annotation_is_provided() {
function simple_signing_satisfy_manifest_digest_works_as_expected (line 315) | fn simple_signing_satisfy_manifest_digest_works_as_expected() {
FILE: src/cosign/signature_layers.rs
type CertificateSignature (line 46) | pub struct CertificateSignature {
method fmt (line 67) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method from_certificate (line 426) | pub(crate) fn from_certificate(
type CertificateSubject (line 94) | pub enum CertificateSubject {
method from_certificate (line 523) | pub fn from_certificate(certificate: &Certificate) -> Result<Certifica...
type SignatureLayer (line 116) | pub struct SignatureLayer {
method fmt (line 150) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method new_unsigned (line 210) | pub fn new_unsigned(image_ref: &OciReference, manifest_digest: &str) -...
method new (line 241) | pub(crate) fn new(
method get_signature_from_annotations (line 293) | fn get_signature_from_annotations(annotations: &BTreeMap<String, Strin...
method get_bundle_from_annotations (line 301) | fn get_bundle_from_annotations(
method get_certificate_signature_from_annotations (line 318) | fn get_certificate_signature_from_annotations(
method is_signed_by_key (line 359) | pub(crate) fn is_signed_by_key(&self, verification_key: &CosignVerific...
function build_signature_layers (line 386) | pub(crate) fn build_signature_layers(
function get_cert_extension_by_oid (line 499) | fn get_cert_extension_by_oid(
function build_correct_signature_layer_without_bundle (line 552) | pub(crate) fn build_correct_signature_layer_without_bundle()
function build_bundle (line 591) | pub(crate) fn build_bundle() -> Bundle {
function build_correct_signature_layer_with_certificate (line 605) | pub(crate) fn build_correct_signature_layer_with_certificate() -> Signat...
function is_signed_by_key_fails_when_signature_is_not_valid (line 658) | fn is_signed_by_key_fails_when_signature_is_not_valid() {
function new_signature_layer_fails_because_bad_descriptor (line 675) | fn new_signature_layer_fails_because_bad_descriptor() {
function new_signature_layer_fails_because_bad_layer (line 705) | fn new_signature_layer_fails_because_bad_layer() {
function new_signature_layer_fails_because_checksum_mismatch (line 735) | fn new_signature_layer_fails_because_checksum_mismatch() {
function get_signature_from_annotations_success (line 766) | fn get_signature_from_annotations_success() {
function get_signature_from_annotations_failure (line 775) | fn get_signature_from_annotations_failure() {
function get_bundle_from_annotations_works (line 783) | fn get_bundle_from_annotations_works() {
function get_certificate_signature_from_annotations_returns_none (line 801) | fn get_certificate_signature_from_annotations_returns_none() {
function get_certificate_signature_from_annotations_fails_when_no_bundle_is_given (line 815) | fn get_certificate_signature_from_annotations_fails_when_no_bundle_is_gi...
function get_certificate_signature_from_annotations_fails_when_no_fulcio_pub_key_is_given (line 832) | fn get_certificate_signature_from_annotations_fails_when_no_fulcio_pub_k...
function is_signed_by_key (line 849) | fn is_signed_by_key() {
type Error (line 877) | type Error = anyhow::Error;
function try_from (line 879) | fn try_from(value: X509) -> std::result::Result<Self, Self::Error> {
function certificate_signature_from_certificate_using_email (line 887) | fn certificate_signature_from_certificate_using_email() -> anyhow::Resul...
function certificate_signature_from_certificate_using_uri (line 939) | fn certificate_signature_from_certificate_using_uri() -> anyhow::Result<...
function certificate_signature_from_certificate_without_email_and_uri (line 992) | fn certificate_signature_from_certificate_without_email_and_uri() -> any...
FILE: src/cosign/verification_constraint/annotation_verifier.rs
type AnnotationVerifier (line 18) | pub struct AnnotationVerifier {
method verify (line 23) | fn verify(&self, signature_layer: &SignatureLayer) -> Result<bool> {
FILE: src/cosign/verification_constraint/cert_subject_email_verifier.rs
type CertSubjectEmailVerifier (line 114) | pub struct CertSubjectEmailVerifier {
method fmt (line 120) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type StringVerifier (line 133) | pub enum StringVerifier {
method verify (line 139) | fn verify(&self, s: &str) -> bool {
method fmt (line 148) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method verify (line 157) | fn verify(&self, signature_layer: &SignatureLayer) -> Result<bool> {
function cert_email_verifier_only_email (line 196) | fn cert_email_verifier_only_email() {
function cert_email_verifier_email_and_issuer (line 219) | fn cert_email_verifier_email_and_issuer() {
function cert_email_verifier_no_signature (line 265) | fn cert_email_verifier_no_signature() {
function cert_email_verifier_only_email_regex (line 276) | fn cert_email_verifier_only_email_regex() {
function cert_email_verifier_email_and_issuer_regex (line 306) | fn cert_email_verifier_email_and_issuer_regex() {
FILE: src/cosign/verification_constraint/cert_subject_url_verifier.rs
type CertSubjectUrlVerifier (line 47) | pub struct CertSubjectUrlVerifier {
method verify (line 53) | fn verify(&self, signature_layer: &SignatureLayer) -> Result<bool> {
function cert_subject_url_verifier (line 84) | fn cert_subject_url_verifier() {
function cert_subject_verifier_no_signature (line 122) | fn cert_subject_verifier_no_signature() {
FILE: src/cosign/verification_constraint/certificate_verifier.rs
type CertificateVerifier (line 14) | pub struct CertificateVerifier {
method from_pem (line 32) | pub fn from_pem(
method from_der (line 52) | pub fn from_der(
method verify (line 84) | fn verify(&self, signature_layer: &SignatureLayer) -> Result<bool> {
function verify_certificate_ (line 146) | fn verify_certificate_() -> anyhow::Result<()> {
function test_data (line 180) | fn test_data() -> (SignatureLayer, String) {
function build_bundle (line 231) | fn build_bundle() -> Bundle {
function verify_correct_layer (line 246) | fn verify_correct_layer() {
function rekor_integration (line 255) | fn rekor_integration() {
function detect_signature_created_at_invalid_time (line 283) | fn detect_signature_created_at_invalid_time() {
FILE: src/cosign/verification_constraint/mod.rs
type VerificationConstraintVec (line 35) | pub type VerificationConstraintVec = Vec<Box<dyn VerificationConstraint>>;
type VerificationConstraintRefVec (line 38) | pub type VerificationConstraintRefVec<'a> = Vec<&'a Box<dyn Verification...
type VerificationConstraint (line 42) | pub trait VerificationConstraint: std::fmt::Debug {
method verify (line 66) | fn verify(&self, signature_layer: &SignatureLayer) -> Result<bool>;
FILE: src/cosign/verification_constraint/public_key_verifier.rs
type PublicKeyVerifier (line 8) | pub struct PublicKeyVerifier {
method new (line 16) | pub fn new(key_raw: &[u8], signing_scheme: &SigningScheme) -> Result<S...
method try_from (line 29) | pub fn try_from(key_raw: &[u8]) -> Result<Self> {
method verify (line 36) | fn verify(&self, signature_layer: &SignatureLayer) -> Result<bool> {
function pub_key_verifier (line 50) | fn pub_key_verifier() {
FILE: src/crypto/certificate.rs
function is_trusted (line 32) | pub(crate) fn is_trusted(certificate: &Certificate, integrated_time: i64...
function verify_key_usages (line 41) | pub(crate) fn verify_key_usages(certificate: &Certificate) -> Result<()> {
function verify_has_san (line 66) | pub(crate) fn verify_has_san(certificate: &Certificate) -> Result<()> {
function verify_validity (line 79) | pub(crate) fn verify_validity(certificate: &Certificate) -> Result<()> {
function verify_expiration (line 94) | fn verify_expiration(certificate: &Certificate, integrated_time: i64) ->...
type ExtensionErrorKind (line 126) | pub enum ExtensionErrorKind {
type NotLeafErrorKind (line 138) | pub enum NotLeafErrorKind {
type NotCAErrorKind (line 144) | pub enum NotCAErrorKind {
type CertificateValidationError (line 157) | pub enum CertificateValidationError {
function is_leaf (line 178) | pub(crate) fn is_leaf(
function is_ca (line 235) | pub(crate) fn is_ca(
function is_root_ca (line 292) | pub(crate) fn is_root_ca(
function verify_cert_key_usages_success (line 326) | fn verify_cert_key_usages_success() -> anyhow::Result<()> {
function verify_cert_key_usages_failure_because_no_digital_signature (line 339) | fn verify_cert_key_usages_failure_because_no_digital_signature() -> anyh...
function verify_cert_key_usages_failure_because_no_code_signing (line 364) | fn verify_cert_key_usages_failure_because_no_code_signing() -> anyhow::R...
function verify_cert_failure_because_no_san (line 386) | fn verify_cert_failure_because_no_san() -> anyhow::Result<()> {
function verify_cert_validity_success (line 412) | fn verify_cert_validity_success() -> anyhow::Result<()> {
function verify_cert_validity_failure (line 426) | fn verify_cert_validity_failure() -> anyhow::Result<()> {
function verify_cert_expiration_success (line 453) | fn verify_cert_expiration_success() -> anyhow::Result<()> {
function verify_cert_expiration_failure (line 480) | fn verify_cert_expiration_failure() -> anyhow::Result<()> {
FILE: src/crypto/certificate_pool.rs
type CertificatePool (line 24) | pub(crate) struct CertificatePool {
method from_certificates (line 31) | pub(crate) fn from_certificates<'r, 'i, R, I>(
method verify_pem_cert (line 59) | pub(crate) fn verify_pem_cert(
method verify_der_cert (line 82) | pub(crate) fn verify_der_cert(
method verify_cert_with_time (line 99) | pub(crate) fn verify_cert_with_time<'a, 'cert>(
FILE: src/crypto/keyring.rs
type KeyringError (line 28) | pub enum KeyringError {
type Result (line 39) | type Result<T> = std::result::Result<T, KeyringError>;
type Key (line 42) | struct Key {
method new (line 51) | pub fn new(spki_bytes: &[u8]) -> Result<Self> {
type Keyring (line 85) | pub struct Keyring(HashMap<[u8; 32], Key>);
method new (line 89) | pub fn new<'a>(keys: impl IntoIterator<Item = &'a [u8]>) -> Result<Sel...
method verify (line 99) | pub fn verify(&self, key_id: &[u8; 32], signature: &[u8], data: &[u8])...
function verify_keyring (line 118) | fn verify_keyring() {
FILE: src/crypto/merkle/mod.rs
function hex_to_hash_output (line 18) | pub(crate) fn hex_to_hash_output(
FILE: src/crypto/merkle/proof_verification.rs
type MerkleProofError (line 16) | pub enum MerkleProofError {
type MerkleProofVerifier (line 26) | pub(crate) trait MerkleProofVerifier<O>: Rfc6269HasherTrait<O>
method verify_match (line 31) | fn verify_match(a: &O, b: &O) -> Result<(), ()> {
method verify_inclusion (line 44) | fn verify_inclusion(
method root_from_inclusion_proof (line 67) | fn root_from_inclusion_proof(
method verify_consistency (line 100) | fn verify_consistency(
method chain_inner (line 202) | fn chain_inner(seed: &O, proof_hashes: &[O], index: u64) -> O {
method chain_inner_right (line 221) | fn chain_inner_right(seed: &O, proof_hashes: &[O], index: u64) -> O {
method chain_border_right (line 239) | fn chain_border_right(seed: &O, proof_hashes: &[O]) -> O {
method decomp_inclusion_proof (line 251) | fn decomp_inclusion_proof(index: u64, tree_size: u64) -> (u64, u64) {
method inner_proof_size (line 259) | fn inner_proof_size(index: u64, tree_size: u64) -> u64 {
type InclusionProofTestVector (line 275) | struct InclusionProofTestVector<'a> {
type ConsistencyTestVector (line 282) | struct ConsistencyTestVector<'a> {
type InclusionProbe (line 290) | struct InclusionProbe {
type ConsistencyProbe (line 301) | struct ConsistencyProbe<'a> {
constant SHA256_SOME_HASH (line 310) | const SHA256_SOME_HASH: [u8; 32] =
constant SHA256_EMPTY_TREE_HASH (line 313) | const SHA256_EMPTY_TREE_HASH: [u8; 32] =
constant ZERO_HASH (line 316) | const ZERO_HASH: [u8; 32] = [0; 32];
constant INCLUSION_PROOFS (line 318) | const INCLUSION_PROOFS: [InclusionProofTestVector; 6] = [
constant CONSISTENCY_PROOFS (line 365) | const CONSISTENCY_PROOFS: [ConsistencyTestVector; 5] = [
constant ROOTS (line 408) | const ROOTS: [[u8; 32]; 8] = [
constant LEAVES (line 419) | const LEAVES: &[&[u8]] = &[
function corrupt_inclusion_proof (line 430) | fn corrupt_inclusion_proof(
function verifier_check (line 540) | fn verifier_check(
function verifier_consistency_check (line 587) | fn verifier_consistency_check(
function corrupt_consistency_proof (line 620) | fn corrupt_consistency_proof<'a>(
function test_verify_inclusion_single_entry (line 792) | fn test_verify_inclusion_single_entry() {
function test_verify_inclusion (line 813) | fn test_verify_inclusion() {
function test_verify_consistency (line 857) | fn test_verify_consistency() {
FILE: src/crypto/merkle/rfc6962.rs
type Rfc6269HashPrefix (line 7) | enum Rfc6269HashPrefix {
type Rfc6269HasherTrait (line 13) | pub(crate) trait Rfc6269HasherTrait<O> {
method empty_root (line 15) | fn empty_root() -> O;
method hash_leaf (line 17) | fn hash_leaf(leaf: impl AsRef<[u8]>) -> O;
method hash_children (line 19) | fn hash_children(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> O;
method empty_root (line 26) | fn empty_root() -> Output<T> {
method hash_leaf (line 29) | fn hash_leaf(leaf: impl AsRef<[u8]>) -> Output<T> {
method hash_children (line 35) | fn hash_children(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> Out...
type Rfc6269Default (line 45) | pub(crate) type Rfc6269Default = Sha256;
type TestCase (line 55) | struct TestCase {
function test_hasher (line 62) | fn test_hasher() {
function test_collisions (line 94) | fn test_collisions() {
FILE: src/crypto/mod.rs
type SigningScheme (line 51) | pub enum SigningScheme {
method fmt (line 64) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type Error (line 80) | type Error = String;
method try_from (line 82) | fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
method create_signer (line 100) | pub fn create_signer(&self) -> Result<SigStoreSigner> {
method default (line 162) | fn default() -> Self {
type Signature (line 168) | pub enum Signature<'a> {
constant PUBLIC_KEY (line 213) | pub(crate) const PUBLIC_KEY: &str = r#"-----BEGIN PUBLIC KEY-----
type CertData (line 218) | pub(crate) struct CertData {
type CertGenerationOptions (line 223) | pub(crate) struct CertGenerationOptions {
method default (line 239) | fn default() -> Self {
function generate_ecdsa_p256_keypair (line 267) | pub(crate) fn generate_ecdsa_p256_keypair()
function generate_ecdsa_p384_keypair (line 281) | pub(crate) fn generate_ecdsa_p384_keypair()
function generate_ed25519_keypair (line 295) | pub(crate) fn generate_ed25519_keypair() -> (pkey::PKey<pkey::Private>, ...
function generate_rsa_keypair (line 307) | pub(crate) fn generate_rsa_keypair(
function generate_dsa_keypair (line 325) | pub(crate) fn generate_dsa_keypair(
function generate_certificate (line 343) | pub(crate) fn generate_certificate(
FILE: src/crypto/signing_key/ecdsa/ec.rs
type EcdsaKeys (line 115) | pub struct EcdsaKeys<C>
function new (line 134) | pub fn new() -> Result<Self> {
function from_encrypted_pem (line 147) | pub fn from_encrypted_pem(private_key: &[u8], password: &[u8]) -> Result...
function from_pem (line 172) | pub fn from_pem(pem_data: &[u8]) -> Result<Self> {
function from_der (line 193) | pub fn from_der(private_key: &[u8]) -> Result<Self> {
function from_private_key (line 203) | fn from_private_key(ec_seckey: SecretKey<C>) -> Result<Self> {
function to_wrapped_ecdsa_keys (line 212) | pub fn to_wrapped_ecdsa_keys(&self) -> Result<ECDSAKeys> {
method public_key_to_pem (line 225) | fn public_key_to_pem(&self) -> Result<String> {
method private_key_to_pem (line 232) | fn private_key_to_pem(&self) -> Result<Zeroizing<String>> {
method public_key_to_der (line 239) | fn public_key_to_der(&self) -> Result<Vec<u8>> {
method private_key_to_der (line 248) | fn private_key_to_der(&self) -> Result<Zeroizing<Vec<u8>>> {
method private_key_to_encrypted_pem (line 257) | fn private_key_to_encrypted_pem(&self, password: &[u8]) -> Result<Zeroiz...
method to_verification_key (line 268) | fn to_verification_key(&self, signing_scheme: &SigningScheme) -> Result<...
type EcdsaSigner (line 289) | pub struct EcdsaSigner<C, D>
function from_ecdsa_keys (line 314) | pub fn from_ecdsa_keys(ecdsa_keys: &EcdsaKeys<C>) -> Result<Self> {
function ecdsa_keys (line 332) | pub fn ecdsa_keys(&self) -> &EcdsaKeys<C> {
method sign (line 362) | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> {
method key_pair (line 371) | fn key_pair(&self) -> &dyn KeyPair {
constant PASSWORD (line 390) | const PASSWORD: &[u8] = b"123";
constant EMPTY_PASSWORD (line 391) | const EMPTY_PASSWORD: &[u8] = b"";
function ecdsa_from_unencrypted_pem (line 396) | fn ecdsa_from_unencrypted_pem() {
function ecdsa_from_encrypted_pem (line 415) | fn ecdsa_from_encrypted_pem(#[case] keypath: &str, #[case] password: &[u...
function ecdsa_to_encrypted_pem (line 429) | fn ecdsa_to_encrypted_pem(#[case] password: &[u8]) {
function ecdsa_error_unencrypted_pem_password (line 443) | fn ecdsa_error_unencrypted_pem_password() {
function ecdsa_to_and_from_pem (line 458) | fn ecdsa_to_and_from_pem() {
function ecdsa_to_and_from_encrypted_pem (line 474) | fn ecdsa_to_and_from_encrypted_pem(#[case] password: &[u8]) {
function ecdsa_to_and_from_der (line 488) | fn ecdsa_to_and_from_der() {
function ecdsa_generate_public_key (line 502) | fn ecdsa_generate_public_key() {
function ecdsa_derive_verification_key (line 523) | fn ecdsa_derive_verification_key() {
function ecdsa_sign_and_verify (line 538) | fn ecdsa_sign_and_verify() {
FILE: src/crypto/signing_key/ecdsa/mod.rs
type ECDSAKeys (line 84) | pub enum ECDSAKeys {
method fmt (line 90) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 121) | pub fn new(curve: EllipticCurve) -> Result<Self> {
method as_inner (line 130) | pub fn as_inner(&self) -> &dyn KeyPair {
method from_encrypted_pem (line 140) | pub fn from_encrypted_pem(private_key: &[u8], password: &[u8]) -> Resu...
method from_pem (line 149) | pub fn from_pem(pem_data: &[u8]) -> Result<Self> {
method from_der (line 154) | pub fn from_der(private_key: &[u8]) -> Result<Self> {
method to_sigstore_signer (line 163) | pub fn to_sigstore_signer(&self) -> Result<SigStoreSigner> {
type EllipticCurve (line 101) | pub enum EllipticCurve {
FILE: src/crypto/signing_key/ed25519.rs
type Ed25519Keys (line 79) | pub struct Ed25519Keys {
method new (line 88) | pub fn new() -> Result<Self> {
method from_ed25519key (line 99) | pub fn from_ed25519key(key: &Ed25519Keys) -> Result<Self> {
method from_encrypted_pem (line 107) | pub fn from_encrypted_pem(encrypted_pem: &[u8], password: &[u8]) -> Re...
method from_pem (line 137) | pub fn from_pem(pem: &[u8]) -> Result<Self> {
method from_der (line 163) | pub fn from_der(der_bytes: &[u8]) -> Result<Self> {
method from_key_pair_bytes (line 173) | fn from_key_pair_bytes(key_pair_bytes: KeypairBytes) -> Result<Self> {
method to_sigstore_signer (line 189) | pub fn to_sigstore_signer(&self) -> Result<SigStoreSigner> {
method public_key_to_pem (line 198) | fn public_key_to_pem(&self) -> Result<String> {
method public_key_to_der (line 205) | fn public_key_to_der(&self) -> Result<Vec<u8>> {
method private_key_to_encrypted_pem (line 214) | fn private_key_to_encrypted_pem(&self, password: &[u8]) -> Result<zeroiz...
method private_key_to_pem (line 225) | fn private_key_to_pem(&self) -> Result<zeroize::Zeroizing<String>> {
method private_key_to_der (line 234) | fn private_key_to_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>> {
method to_verification_key (line 243) | fn to_verification_key(
type Ed25519Signer (line 254) | pub struct Ed25519Signer {
method from_ed25519_keys (line 259) | pub fn from_ed25519_keys(ed25519_keys: &Ed25519Keys) -> Result<Self> {
method ed25519_keys (line 266) | pub fn ed25519_keys(&self) -> &Ed25519Keys {
method key_pair (line 273) | fn key_pair(&self) -> &dyn KeyPair {
method sign (line 278) | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> {
constant PASSWORD (line 298) | const PASSWORD: &[u8] = b"123";
constant EMPTY_PASSWORD (line 299) | const EMPTY_PASSWORD: &[u8] = b"";
function ed25519_from_unencrypted_pem (line 304) | fn ed25519_from_unencrypted_pem() {
function ed25519_from_encrypted_pem (line 319) | fn ed25519_from_encrypted_pem(#[case] keypath: &str, #[case] password: &...
function ed25519_to_encrypted_pem (line 333) | fn ed25519_to_encrypted_pem(#[case] password: &[u8]) {
function ed25519_error_unencrypted_pem_password (line 346) | fn ed25519_error_unencrypted_pem_password() {
function ed25519_to_and_from_pem (line 361) | fn ed25519_to_and_from_pem() {
function ed25519_to_and_from_encrypted_pem (line 376) | fn ed25519_to_and_from_encrypted_pem(#[case] password: &[u8]) {
function ed25519_to_and_from_der (line 389) | fn ed25519_to_and_from_der() {
function ed25519_generate_public_key (line 402) | fn ed25519_generate_public_key() {
function ecdsa_derive_verification_key (line 423) | fn ecdsa_derive_verification_key() {
function ed25519_sign_and_verify (line 436) | fn ed25519_sign_and_verify() {
FILE: src/crypto/signing_key/kdf.rs
constant SALT_SIZE (line 30) | pub const SALT_SIZE: u32 = 32;
constant NAME_SCRYPT (line 33) | pub const NAME_SCRYPT: &str = "scrypt";
constant SCRYPT_N_LOW (line 36) | pub const SCRYPT_N_LOW: u32 = 32768;
constant SCRYPT_N_HIGH (line 38) | pub const SCRYPT_N_HIGH: u32 = 65536;
constant SCRYPT_R (line 41) | pub const SCRYPT_R: u32 = 8;
constant SCRYPT_P (line 44) | pub const SCRYPT_P: u32 = 1;
constant NAME_SECRET_BOX (line 47) | pub const NAME_SECRET_BOX: &str = "nacl/secretbox";
constant BOX_KEY_SIZE (line 50) | pub const BOX_KEY_SIZE: usize = 32;
constant BOX_NONCE_SIZE (line 53) | pub const BOX_NONCE_SIZE: u32 = 24;
type ScryptParams (line 57) | pub struct ScryptParams {
type ScryptKDF (line 67) | struct ScryptKDF {
method key (line 111) | fn key(&self, password: &[u8]) -> Result<Vec<u8>> {
method check_params (line 126) | fn check_params(&self) -> Result<()> {
function to_base64 (line 75) | fn to_base64<S>(v: &[u8], serializer: S) -> std::result::Result<S::Ok, S...
function from_base64 (line 83) | fn from_base64<'de, D>(deserializer: D) -> std::result::Result<Vec<u8>, ...
method default (line 95) | fn default() -> Self {
type SecretBoxCipher (line 141) | struct SecretBoxCipher {
method encrypt (line 162) | fn encrypt(&mut self, plaintext: &[u8], key: &[u8]) -> Result<Vec<u8>> {
method decrypt (line 182) | fn decrypt(&self, ciphertext: &[u8], key: &[u8]) -> Result<Vec<u8>> {
method default (line 150) | fn default() -> Self {
type Data (line 197) | struct Data {
function generate_random (line 209) | fn generate_random(len: u32) -> Vec<u8> {
function encrypt (line 220) | pub fn encrypt(plaintext: &[u8], password: &[u8]) -> Result<Vec<u8>> {
function decrypt (line 240) | pub fn decrypt(ciphertext: &[u8], password: &[u8]) -> Result<Vec<u8>> {
function serde_kdf (line 273) | fn serde_kdf() {
FILE: src/crypto/signing_key/mod.rs
constant COSIGN_PRIVATE_KEY_PEM_LABEL (line 89) | pub const COSIGN_PRIVATE_KEY_PEM_LABEL: &str = "ENCRYPTED COSIGN PRIVATE...
constant PUBLIC_KEY_PEM_LABEL (line 92) | pub const PUBLIC_KEY_PEM_LABEL: &str = "PUBLIC KEY";
constant SIGSTORE_PRIVATE_KEY_PEM_LABEL (line 95) | pub const SIGSTORE_PRIVATE_KEY_PEM_LABEL: &str = "ENCRYPTED SIGSTORE PRI...
constant PRIVATE_KEY_PEM_LABEL (line 98) | pub const PRIVATE_KEY_PEM_LABEL: &str = "PRIVATE KEY";
constant RSA_PRIVATE_KEY_PEM_LABEL (line 101) | pub const RSA_PRIVATE_KEY_PEM_LABEL: &str = "RSA PRIVATE KEY";
type KeyPair (line 109) | pub trait KeyPair {
method public_key_to_pem (line 111) | fn public_key_to_pem(&self) -> Result<String>;
method public_key_to_der (line 114) | fn public_key_to_der(&self) -> Result<Vec<u8>>;
method private_key_to_encrypted_pem (line 119) | fn private_key_to_encrypted_pem(&self, password: &[u8]) -> Result<Zero...
method private_key_to_pem (line 122) | fn private_key_to_pem(&self) -> Result<Zeroizing<String>>;
method private_key_to_der (line 125) | fn private_key_to_der(&self) -> Result<Zeroizing<Vec<u8>>>;
method to_verification_key (line 129) | fn to_verification_key(
type SigStoreKeyPair (line 136) | pub enum SigStoreKeyPair {
method fmt (line 143) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method from_pem (line 180) | pub fn from_pem(pem_data: &[u8]) -> Result<Self> {
method from_der (line 185) | pub fn from_der(private_key: &[u8]) -> Result<Self> {
method from_encrypted_pem (line 190) | pub fn from_encrypted_pem(pem_data: &[u8], password: &[u8]) -> Result<...
method public_key_to_pem (line 195) | pub fn public_key_to_pem(&self) -> Result<String> {
method public_key_to_der (line 200) | pub fn public_key_to_der(&self) -> Result<Vec<u8>> {
method private_key_to_encrypted_pem (line 207) | pub fn private_key_to_encrypted_pem(&self, password: &[u8]) -> Result<...
method private_key_to_pem (line 212) | pub fn private_key_to_pem(&self) -> Result<Zeroizing<String>> {
method private_key_to_der (line 217) | pub fn private_key_to_der(&self) -> Result<Zeroizing<Vec<u8>>> {
method to_verification_key (line 223) | pub fn to_verification_key(
method to_sigstore_signer (line 233) | pub fn to_sigstore_signer(&self, signing_scheme: &SigningScheme) -> Re...
type Signer (line 302) | pub trait Signer {
method key_pair (line 304) | fn key_pair(&self) -> &dyn KeyPair;
method sign (line 307) | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>>;
type SigStoreSigner (line 312) | pub enum SigStoreSigner {
method as_inner (line 327) | fn as_inner(&self) -> &dyn Signer {
method sign (line 342) | pub fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> {
method to_verification_key (line 347) | pub fn to_verification_key(&self) -> Result<CosignVerificationKey> {
method to_sigstore_keypair (line 365) | pub fn to_sigstore_keypair(&self) -> Result<SigStoreKeyPair> {
constant MESSAGE (line 399) | pub const MESSAGE: &str = r#"{
function sigstore_signing (line 423) | fn sigstore_signing(#[case] signing_scheme: SigningScheme) {
FILE: src/crypto/signing_key/rsa/keypair.rs
type RSAKeys (line 61) | pub struct RSAKeys {
method new (line 70) | pub fn new(bit_size: usize) -> Result<Self> {
method from_rsa_privatekey_key (line 81) | pub fn from_rsa_privatekey_key(key: &RSAKeys) -> Result<Self> {
method from_encrypted_pem (line 89) | pub fn from_encrypted_pem(encrypted_pem: &[u8], password: &[u8]) -> Re...
method from_pem (line 120) | pub fn from_pem(pem: &[u8]) -> Result<Self> {
method from_der (line 150) | pub fn from_der(der_bytes: &[u8]) -> Result<Self> {
method to_sigstore_signer (line 161) | pub fn to_sigstore_signer(
method from (line 213) | fn from(private_key: RsaPrivateKey) -> Self {
method public_key_to_pem (line 223) | fn public_key_to_pem(&self) -> Result<String> {
method public_key_to_der (line 230) | fn public_key_to_der(&self) -> Result<Vec<u8>> {
method private_key_to_encrypted_pem (line 239) | fn private_key_to_encrypted_pem(&self, password: &[u8]) -> Result<zeroiz...
method private_key_to_pem (line 250) | fn private_key_to_pem(&self) -> Result<zeroize::Zeroizing<String>> {
method private_key_to_der (line 257) | fn private_key_to_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>> {
method to_verification_key (line 266) | fn to_verification_key(&self, signing_scheme: &SigningScheme) -> Result<...
constant PASSWORD (line 291) | const PASSWORD: &[u8] = b"123";
constant EMPTY_PASSWORD (line 292) | const EMPTY_PASSWORD: &[u8] = b"";
constant KEY_SIZE (line 293) | const KEY_SIZE: usize = 2048;
function rsa_from_unencrypted_pem (line 298) | fn rsa_from_unencrypted_pem() {
function rsa_from_encrypted_pem (line 313) | fn rsa_from_encrypted_pem(#[case] keypath: &str, #[case] password: &[u8]) {
function rsa_to_encrypted_pem (line 329) | fn rsa_to_encrypted_pem(#[case] password: &[u8]) {
function rsa_error_unencrypted_pem_password (line 342) | fn rsa_error_unencrypted_pem_password() {
function rsa_to_and_from_pem (line 357) | fn rsa_to_and_from_pem() {
function rsa_to_and_from_encrypted_pem (line 372) | fn rsa_to_and_from_encrypted_pem(#[case] password: &[u8]) {
function rsa_to_and_from_der (line 385) | fn rsa_to_and_from_der() {
function rsa_generate_public_key (line 398) | fn rsa_generate_public_key() {
function rsa_derive_verification_key (line 419) | fn rsa_derive_verification_key() {
function rsa_sign_and_verify (line 433) | fn rsa_sign_and_verify() {
FILE: src/crypto/signing_key/rsa/mod.rs
constant DEFAULT_KEY_SIZE (line 67) | pub const DEFAULT_KEY_SIZE: usize = 2048;
type DigestAlgorithm (line 71) | pub enum DigestAlgorithm {
type PaddingScheme (line 82) | pub enum PaddingScheme {
type RSASigner (line 97) | pub enum RSASigner {
method from_rsa_keys (line 121) | pub fn from_rsa_keys(
method rsa_keys (line 160) | pub fn rsa_keys(&self) -> &RSAKeys {
method to_verification_key (line 165) | pub fn to_verification_key(&self) -> Result<CosignVerificationKey> {
method sign (line 191) | fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> {
method key_pair (line 203) | fn key_pair(&self) -> &dyn KeyPair {
function rsa_schemes (line 249) | fn rsa_schemes(
FILE: src/crypto/transparency.rs
function cert_is_preissuer (line 36) | fn cert_is_preissuer(cert: &Certificate) -> bool {
function find_issuer_cert (line 46) | fn find_issuer_cert(chain: &[Certificate]) -> Option<&Certificate> {
type CertificateErrorKind (line 58) | pub enum CertificateErrorKind {
method from (line 79) | fn from(value: x509_cert::ext::pkix::Error) -> Self {
type SCTError (line 88) | pub enum SCTError {
type SignatureType (line 101) | enum SignatureType {
type LogEntryType (line 108) | enum LogEntryType {
type PreCert (line 114) | struct PreCert {
type SignedEntry (line 123) | enum SignedEntry {
type DigitallySigned (line 132) | pub struct DigitallySigned {
method from (line 235) | fn from(value: &CertificateEmbeddedSCT) -> Self {
method from (line 270) | fn from(value: &SigningCertificateDetachedSCT) -> Self {
type CertificateEmbeddedSCT (line 150) | pub struct CertificateEmbeddedSCT<'a> {
function new_with_spki (line 157) | fn new_with_spki(cert: &'a Certificate, spki: &[u8]) -> Result<Self, SCT...
function new (line 189) | pub fn new(leaf: &'a Certificate, chain: &[Certificate]) -> Result<Self,...
function new_with_verified_path (line 202) | pub fn new_with_verified_path(
function verify_sct (line 296) | pub fn verify_sct<S>(sct: S, keyring: &Keyring) -> Result<(), SCTError>
function verify_embedded_sct (line 320) | fn verify_embedded_sct() {
function verify_detached_sct (line 384) | fn verify_detached_sct() {
FILE: src/crypto/verification_key.rs
type CosignVerificationKey (line 49) | pub enum CosignVerificationKey {
type Error (line 69) | type Error = SigstoreError;
method try_from (line 71) | fn try_from(subject_pub_key_info: &SubjectPublicKeyInfoOwned) -> Resul...
method from_der (line 126) | pub fn from_der(der_data: &[u8], signing_scheme: &SigningScheme) -> Re...
method try_from_der (line 208) | pub fn try_from_der(der_data: &[u8]) -> Result<Self> {
method from_pem (line 232) | pub fn from_pem(pem_data: &[u8], signing_scheme: &SigningScheme) -> Re...
method try_from_pem (line 243) | pub fn try_from_pem(pem_data: &[u8]) -> Result<Self> {
method from_sigstore_signer (line 250) | pub fn from_sigstore_signer(signer: &SigStoreSigner) -> Result<Self> {
method from_key_pair (line 256) | pub fn from_key_pair(signer: &dyn KeyPair, signing_scheme: &SigningSch...
method verify_signature (line 262) | pub fn verify_signature(&self, signature: Signature, msg: &[u8]) -> Re...
method verify_prehash (line 334) | pub(crate) fn verify_prehash(&self, signature: Signature, msg: &[u8]) ...
function verify_signature_success (line 406) | fn verify_signature_success() {
function verify_signature_failure_because_wrong_msg (line 418) | fn verify_signature_failure_because_wrong_msg() {
function verify_signature_failure_because_wrong_signature (line 433) | fn verify_signature_failure_because_wrong_signature() {
function verify_signature_failure_because_wrong_verification_key (line 448) | fn verify_signature_failure_because_wrong_verification_key() {
function verify_rsa_signature (line 470) | fn verify_rsa_signature() {
function convert_ecdsa_p256_subject_public_key_to_cosign_verification_key (line 497) | fn convert_ecdsa_p256_subject_public_key_to_cosign_verification_key() ->...
function convert_ecdsa_p384_subject_public_key_to_cosign_verification_key (line 524) | fn convert_ecdsa_p384_subject_public_key_to_cosign_verification_key() ->...
function convert_rsa_subject_public_key_to_cosign_verification_key (line 551) | fn convert_rsa_subject_public_key_to_cosign_verification_key() -> anyhow...
function convert_ed25519_subject_public_key_to_cosign_verification_key (line 578) | fn convert_ed25519_subject_public_key_to_cosign_verification_key() -> an...
function convert_unsupported_curve_subject_public_key_to_cosign_verification_key (line 605) | fn convert_unsupported_curve_subject_public_key_to_cosign_verification_k...
FILE: src/errors.rs
type SigstoreVerifyConstraintsError (line 30) | pub struct SigstoreVerifyConstraintsError<'a> {
type SigstoreApplicationConstraintsError (line 38) | pub struct SigstoreApplicationConstraintsError<'a> {
type Result (line 42) | pub type Result<T> = std::result::Result<T, SigstoreError>;
type SigstoreError (line 45) | pub enum SigstoreError {
FILE: src/fulcio/mod.rs
constant FULCIO_ROOT (line 23) | pub const FULCIO_ROOT: &str = "https://fulcio.sigstore.dev/";
constant SIGNING_CERT_PATH (line 26) | pub const SIGNING_CERT_PATH: &str = "api/v1/signingCert";
constant SIGNING_CERT_V2_PATH (line 27) | pub const SIGNING_CERT_V2_PATH: &str = "api/v2/signingCert";
constant CONTENT_TYPE_HEADER_NAME (line 29) | const CONTENT_TYPE_HEADER_NAME: &str = "content-type";
type Csr (line 37) | struct Csr {
type Error (line 43) | type Error = serde_json::Error;
method try_from (line 45) | fn try_from(csr: Csr) -> std::result::Result<Self, Self::Error> {
type PublicKey (line 52) | struct PublicKey(String, SigningScheme);
method serialize (line 55) | fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::E...
type FulcioCert (line 81) | pub struct FulcioCert(String);
method as_ref (line 84) | fn as_ref(&self) -> &[u8] {
method fmt (line 90) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
type TokenProvider (line 97) | pub enum TokenProvider {
method get_token (line 129) | pub async fn get_token(&self) -> Result<(CoreIdToken, String)> {
type FulcioClient (line 139) | pub struct FulcioClient {
method new (line 151) | pub fn new(root_url: Url, token_provider: TokenProvider) -> Self {
method request_cert (line 163) | pub async fn request_cert(
method request_cert_v2 (line 210) | pub async fn request_cert_v2(
FILE: src/fulcio/models.rs
function serialize_x509_csr (line 31) | fn serialize_x509_csr<S>(
function deserialize_inner_detached_sct (line 45) | fn deserialize_inner_detached_sct<'de, D>(de: D) -> std::result::Result<...
function deserialize_inner_detached_sct_signature (line 53) | fn deserialize_inner_detached_sct_signature<'de, D>(de: D) -> Result<Vec...
type CreateSigningCertificateRequest (line 73) | pub struct CreateSigningCertificateRequest {
type SigningCertificate (line 80) | pub enum SigningCertificate {
type SigningCertificateDetachedSCT (line 87) | pub struct SigningCertificateDetachedSCT {
type SigningCertificateEmbeddedSCT (line 95) | pub struct SigningCertificateEmbeddedSCT {
type CertificateChain (line 100) | pub struct CertificateChain {
type InnerDetachedSCT (line 106) | pub struct InnerDetachedSCT {
type SCTVersion (line 119) | pub enum SCTVersion {
type CertificateResponse (line 123) | pub struct CertificateResponse {
FILE: src/fulcio/oauth.rs
constant DEFAULT_CLIENT_ID (line 7) | pub const DEFAULT_CLIENT_ID: &str = "sigstore";
constant DEFAULT_CLIENT_SECRET (line 10) | pub const DEFAULT_CLIENT_SECRET: &str = "";
constant DEFAULT_ISSUER (line 13) | pub const DEFAULT_ISSUER: &str = "https://oauth2.sigstore.dev/auth";
constant DEFAULT_REDIRECT_PORT (line 16) | pub const DEFAULT_REDIRECT_PORT: u32 = 8080;
type OauthTokenProvider (line 20) | pub struct OauthTokenProvider {
method with_client_id (line 29) | pub fn with_client_id(self, client_id: &str) -> Self {
method with_client_secret (line 39) | pub fn with_client_secret(self, client_secret: &str) -> Self {
method with_issuer (line 49) | pub fn with_issuer(self, issuer: &str) -> Self {
method with_redirect_port (line 59) | pub fn with_redirect_port(self, port: u32) -> Self {
method redirect_url (line 68) | fn redirect_url(&self) -> String {
method get_token (line 77) | pub async fn get_token(&self) -> Result<(CoreIdToken, String)> {
FILE: src/mock_client.rs
type MockOciClient (line 29) | pub struct MockOciClient {
method fetch_manifest_digest (line 41) | async fn fetch_manifest_digest(
method pull (line 63) | async fn pull(
method pull_manifest (line 86) | async fn pull_manifest(
method push (line 107) | async fn push(
FILE: src/oauth/http_client.rs
type AsyncReqwestClient (line 31) | pub(crate) struct AsyncReqwestClient(pub reqwest::Client);
type Error (line 34) | type Error = HttpClientError<reqwest::Error>;
type Future (line 37) | type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, Self::E...
type Future (line 39) | type Future =
method call (line 42) | fn call(&'c self, request: HttpRequest) -> Self::Future {
type SyncReqwestClient (line 73) | pub(crate) struct SyncReqwestClient(pub reqwest::blocking::Client);
type Error (line 77) | type Error = HttpClientError<reqwest::Error>;
method call (line 79) | fn call(&self, request: HttpRequest) -> Result<HttpResponse, Self::Error> {
FILE: src/oauth/openidflow.rs
type OpenIdClient (line 106) | pub(crate) type OpenIdClient = openidconnect::core::CoreClient<
type OpenIDAuthorize (line 116) | pub struct OpenIDAuthorize {
method new (line 139) | pub fn new(client_id: &str, client_secret: &str, issuer: &str, redirec...
method auth_url_internal (line 148) | fn auth_url_internal(
method auth_url (line 176) | pub fn auth_url(&self) -> Result<(Url, OpenIdClient, Nonce, PkceCodeVe...
method auth_url_async (line 195) | pub async fn auth_url_async(&self) -> Result<(Url, OpenIdClient, Nonce...
type RedirectListener (line 216) | pub struct RedirectListener {
method new (line 239) | pub fn new(
method redirect_listener_internal (line 253) | fn redirect_listener_internal(&self) -> Result<AuthorizationCode> {
method redirect_listener (line 305) | pub fn redirect_listener(self) -> Result<(CoreIdTokenClaims, CoreIdTok...
method redirect_listener_async (line 329) | pub async fn redirect_listener_async(self) -> Result<(CoreIdTokenClaim...
method extract_token_and_claims (line 354) | fn extract_token_and_claims(
function assert_auth_url (line 378) | fn assert_auth_url(url: &str) {
function test_auth_url (line 387) | fn test_auth_url() {
function test_auth_url_async (line 400) | async fn test_auth_url_async() {
FILE: src/oauth/token.rs
type Claims (line 24) | pub struct Claims {
type UnverifiedClaims (line 34) | pub type UnverifiedClaims = Claims;
type IdentityToken (line 37) | pub struct IdentityToken {
method unverified_claims (line 47) | pub fn unverified_claims(&self) -> &UnverifiedClaims {
method in_validity_period (line 52) | pub fn in_validity_period(&self) -> bool {
type Error (line 64) | type Error = SigstoreError;
method try_from (line 66) | fn try_from(value: &str) -> Result<Self, Self::Error> {
method from (line 93) | fn from(value: CoreIdToken) -> Self {
method fmt (line 103) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
FILE: src/registry/config.rs
type Auth (line 26) | pub enum Auth {
method from (line 48) | fn from(auth: &oci_client::secrets::RegistryAuth) -> Self {
function from (line 36) | fn from(auth: &Auth) -> Self {
type ClientProtocol (line 61) | pub enum ClientProtocol {
function from (line 72) | fn from(cp: ClientProtocol) -> Self {
type CertificateEncoding (line 85) | pub enum CertificateEncoding {
function from (line 93) | fn from(ce: CertificateEncoding) -> Self {
type Certificate (line 103) | pub struct Certificate {
method cmp (line 112) | fn cmp(&self, other: &Self) -> Ordering {
method partial_cmp (line 118) | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
function from (line 124) | fn from(cert: &Certificate) -> Self {
type Error (line 133) | type Error = errors::SigstoreError;
function try_from (line 134) | fn try_from(value: Certificate) -> errors::Result<CertificateDer<'a>> {
type ClientConfig (line 149) | pub struct ClientConfig {
method default (line 182) | fn default() -> Self {
function from (line 197) | fn from(config: ClientConfig) -> Self {
type PushResponse (line 218) | pub struct PushResponse {
method from (line 235) | fn from(pr: oci_client::client::PushResponse) -> Self {
function from (line 226) | fn from(pr: PushResponse) -> Self {
FILE: src/registry/mod.rs
type ClientCapabilitiesDeps (line 48) | pub(crate) trait ClientCapabilitiesDeps: Send + Sync {}
type ClientCapabilitiesDeps (line 58) | pub(crate) trait ClientCapabilitiesDeps {}
type ClientCapabilities (line 63) | pub(crate) trait ClientCapabilities: ClientCapabilitiesDeps {
method fetch_manifest_digest (line 64) | async fn fetch_manifest_digest(
method pull (line 70) | async fn pull(
method pull_manifest (line 77) | async fn pull_manifest(
method push (line 83) | async fn push(
FILE: src/registry/oci_caching_client.rs
type OciCachingClient (line 31) | pub(crate) struct OciCachingClient {
function fetch_manifest_digest_cached (line 43) | async fn fetch_manifest_digest_cached(
type PullSettings (line 61) | struct PullSettings<'a> {
function new (line 68) | fn new(
function image (line 84) | pub fn image(&self) -> oci_client::Reference {
function auth (line 90) | pub fn auth(&self) -> oci_client::secrets::RegistryAuth {
function hash (line 104) | pub fn hash(&self) -> String {
function pull_cached (line 136) | async fn pull_cached(
type PullManifestSettings (line 156) | struct PullManifestSettings {
method new (line 162) | fn new(
method image (line 176) | pub fn image(&self) -> oci_client::Reference {
method auth (line 182) | pub fn auth(&self) -> oci_client::secrets::RegistryAuth {
method hash (line 196) | pub fn hash(&self) -> String {
function pull_manifest_cached (line 228) | async fn pull_manifest_cached(
method fetch_manifest_digest (line 249) | async fn fetch_manifest_digest(
method pull (line 266) | async fn pull(
method pull_manifest (line 286) | async fn pull_manifest(
method push (line 305) | async fn push(
FILE: src/registry/oci_client.rs
type OciClient (line 26) | pub(crate) struct OciClient {
method fetch_manifest_digest (line 35) | async fn fetch_manifest_digest(
method pull (line 49) | async fn pull(
method pull_manifest (line 64) | async fn pull_manifest(
method push (line 78) | async fn push(
FILE: src/registry/oci_reference.rs
type OciReference (line 22) | pub struct OciReference {
method with_tag (line 40) | pub fn with_tag(registry: String, repository: String, tag: String) -> ...
method with_digest (line 47) | pub fn with_digest(registry: String, repository: String, digest: Strin...
method resolve_registry (line 57) | pub fn resolve_registry(&self) -> &str {
method registry (line 62) | pub fn registry(&self) -> &str {
method repository (line 67) | pub fn repository(&self) -> &str {
method digest (line 72) | pub fn digest(&self) -> Option<&str> {
method tag (line 77) | pub fn tag(&self) -> Option<&str> {
method whole (line 82) | pub fn whole(&self) -> String {
type Err (line 27) | type Err = SigstoreError;
method from_str (line 29) | fn from_str(s: &str) -> Result<Self, Self::Err> {
method fmt (line 88) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
FILE: src/rekor/apis/configuration.rs
constant VERSION (line 11) | const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
type Configuration (line 14) | pub struct Configuration {
method new (line 34) | pub fn new() -> Configuration {
type BasicAuth (line 25) | pub type BasicAuth = (String, Option<String>);
type ApiKey (line 28) | pub struct ApiKey {
method default (line 40) | fn default() -> Self {
FILE: src/rekor/apis/entries_api.rs
type CreateLogEntryError (line 20) | pub enum CreateLogEntryError {
type GetLogEntryByIndexError (line 30) | pub enum GetLogEntryByIndexError {
type GetLogEntryByUuidError (line 39) | pub enum GetLogEntryByUuidError {
type SearchLogQueryError (line 48) | pub enum SearchLogQueryError {
type LogEntries (line 56) | pub struct LogEntries {
function parse_response (line 63) | pub fn parse_response(local_var_content: String) -> String {
function create_log_entry (line 72) | pub async fn create_log_entry(
function get_log_entry_by_index (line 114) | pub async fn get_log_entry_by_index(
function get_log_entry_by_uuid (line 157) | pub async fn get_log_entry_by_uuid(
function search_log_query (line 197) | pub async fn search_log_query(
FILE: src/rekor/apis/index_api.rs
type SearchIndexError (line 18) | pub enum SearchIndexError {
function search_index (line 24) | pub async fn search_index(
FILE: src/rekor/apis/mod.rs
type ResponseContent (line 4) | pub struct ResponseContent<T> {
type Error (line 11) | pub enum Error<T> {
function error_status (line 35) | fn error_status<T>(response: &ResponseContent<T>) -> reqwest::StatusCode {
function urlencode (line 39) | pub fn urlencode<T: AsRef<str>>(s: T) -> String {
FILE: src/rekor/apis/pubkey_api.rs
type GetPublicKeyError (line 18) | pub enum GetPublicKeyError {
function get_public_key (line 24) | pub async fn get_public_key(
FILE: src/rekor/apis/tlog_api.rs
type GetLogInfoError (line 18) | pub enum GetLogInfoError {
type GetLogProofError (line 27) | pub enum GetLogProofError {
function get_log_info (line 41) | pub async fn get_log_info(
function get_log_proof (line 99) | pub async fn get_log_proof(
FILE: src/rekor/mod.rs
type TreeSize (line 91) | type TreeSize = u64;
FILE: src/rekor/models/alpine.rs
type Alpine (line 15) | pub struct Alpine {
method new (line 26) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/alpine_all_of.rs
type AlpineAllOf (line 14) | pub struct AlpineAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> AlpineAllOf {
FILE: src/rekor/models/checkpoint.rs
type SignedCheckpoint (line 18) | pub struct SignedCheckpoint {
method decode (line 73) | pub(crate) fn decode(s: &str) -> Result<Self, ParseCheckpointError> {
method encode (line 95) | pub(crate) fn encode(&self) -> String {
method verify_signature (line 109) | pub fn verify_signature(&self, rekor_key: &CosignVerificationKey) -> R...
method is_valid_for_proof (line 126) | pub(crate) fn is_valid_for_proof(
method deserialize (line 221) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
type Checkpoint (line 25) | pub struct Checkpoint {
method marshal (line 150) | fn marshal(&self) -> String {
method unmarshal (line 164) | fn unmarshal(s: &str) -> Result<Self, ParseCheckpointError> {
type CheckpointSignature (line 41) | pub struct CheckpointSignature {
method encode (line 235) | fn encode(&self) -> String {
method decode (line 245) | fn decode(s: &str) -> Result<Self, ParseCheckpointError> {
type OtherContent (line 51) | pub enum OtherContent {
method fmt (line 57) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
type ParseCheckpointError (line 66) | pub enum ParseCheckpointError {
method serialize (line 212) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
function test_marshal (line 281) | fn test_marshal() {
function test_unmarshal_valid (line 321) | fn test_unmarshal_valid() {
function test_unmarshal_invalid (line 382) | fn test_unmarshal_invalid() {
function test_to_string_valid_with_url_name (line 428) | fn test_to_string_valid_with_url_name() {
function test_to_string_valid_with_id_name (line 440) | fn test_to_string_valid_with_id_name() {
function test_from_str_valid_with_url_name (line 452) | fn test_from_str_valid_with_url_name() {
function test_from_str_valid_with_id_name (line 464) | fn test_from_str_valid_with_id_name() {
function test_from_str_valid_with_whitespace (line 476) | fn test_from_str_valid_with_whitespace() {
function test_from_str_invalid_with_spaces_in_name (line 488) | fn test_from_str_invalid_with_spaces_in_name() {
function test_checkpoint_encode_decode_multiple_signatures (line 495) | fn test_checkpoint_encode_decode_multiple_signatures() {
FILE: src/rekor/models/consistency_proof.rs
type RekorConsistencyProof (line 21) | pub struct RekorConsistencyProof {
type ConsistencyProof (line 40) | pub struct ConsistencyProof {
type Error (line 49) | type Error = crate::errors::SigstoreError;
method try_from (line 51) | fn try_from(raw: RekorConsistencyProof) -> Result<Self, Self::Error> {
method new (line 65) | pub fn new(root_hash: [u8; 32], hashes: Vec<[u8; 32]>) -> ConsistencyP...
method verify (line 72) | pub fn verify(
FILE: src/rekor/models/error.rs
type Error (line 14) | pub struct Error {
method new (line 22) | pub fn new() -> Error {
FILE: src/rekor/models/hashedrekord.rs
type Hashedrekord (line 19) | pub struct Hashedrekord {
method new (line 30) | pub fn new(kind: String, api_version: String, spec: Spec) -> Hashedrek...
type Spec (line 42) | pub struct Spec {
method new (line 49) | pub fn new(signature: Signature, data: Data) -> Spec {
type Signature (line 57) | pub struct Signature {
method new (line 63) | pub fn new(content: String, public_key: PublicKey) -> Signature {
type PublicKey (line 74) | pub struct PublicKey {
method new (line 79) | pub fn new(content: String) -> PublicKey {
method decode (line 83) | pub fn decode(&self) -> Result<String, SigstoreError> {
type Data (line 91) | pub struct Data {
method new (line 96) | pub fn new(hash: Hash) -> Data {
type AlgorithmKind (line 103) | pub enum AlgorithmKind {
type Hash (line 112) | pub struct Hash {
method new (line 118) | pub fn new(algorithm: AlgorithmKind, value: String) -> Hash {
FILE: src/rekor/models/hashedrekord_all_of.rs
type HashedrekordAllOf (line 14) | pub struct HashedrekordAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> Hashedreko...
FILE: src/rekor/models/helm.rs
type Helm (line 16) | pub struct Helm {
method new (line 27) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/helm_all_of.rs
type HelmAllOf (line 14) | pub struct HelmAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> HelmAllOf {
FILE: src/rekor/models/inactive_shard_log_info.rs
type InactiveShardLogInfo (line 15) | pub struct InactiveShardLogInfo {
method new (line 31) | pub fn new(
FILE: src/rekor/models/inclusion_proof.rs
type InclusionProof (line 24) | pub struct InclusionProof {
method new (line 45) | pub fn new(
method verify (line 63) | pub fn verify(
FILE: src/rekor/models/intoto.rs
type Intoto (line 16) | pub struct Intoto {
method new (line 27) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/intoto_all_of.rs
type IntotoAllOf (line 14) | pub struct IntotoAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> IntotoAllOf {
FILE: src/rekor/models/jar.rs
type Jar (line 15) | pub struct Jar {
method new (line 26) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/jar_all_of.rs
type JarAllOf (line 14) | pub struct JarAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> JarAllOf {
FILE: src/rekor/models/log_entry.rs
type LogEntry (line 39) | pub struct LogEntry {
method verify_inclusion (line 144) | pub fn verify_inclusion(&self, rekor_key: &CosignVerificationKey) -> R...
type Err (line 52) | type Err = Error;
method from_str (line 53) | fn from_str(s: &str) -> Result<Self, Self::Err> {
type Body (line 71) | pub enum Body {
method default (line 84) | fn default() -> Self {
function decode_body (line 89) | fn decode_body(s: &str) -> Result<Body, SigstoreError> {
type Attestation (line 96) | pub struct Attestation {
type Verification (line 106) | pub struct Verification {
type RekorInclusionProof (line 167) | pub struct RekorInclusionProof {
type Error (line 181) | type Error = crate::errors::SigstoreError;
method try_from (line 183) | fn try_from(api: &RekorInclusionProof) -> Result<Self, Self::Error> {
constant LOG_ENTRY (line 220) | const LOG_ENTRY: &str = r#"
constant REKOR_STAGING_KEY_PEM (line 254) | const REKOR_STAGING_KEY_PEM: &str = r#"
function test_inclusion_proof_valid (line 262) | fn test_inclusion_proof_valid() {
function test_inclusion_proof_missing_proof (line 275) | fn test_inclusion_proof_missing_proof() {
function test_inclusion_proof_modified_proof (line 289) | fn test_inclusion_proof_modified_proof() {
FILE: src/rekor/models/log_info.rs
type RekorLogInfo (line 22) | pub struct RekorLogInfo {
type LogInfo (line 47) | pub struct LogInfo {
type Error (line 61) | type Error = crate::errors::SigstoreError;
method try_from (line 62) | fn try_from(raw: RekorLogInfo) -> Result<Self, Self::Error> {
method new (line 74) | pub fn new(
method verify_consistency (line 133) | pub fn verify_consistency(
constant LOG_INFO_OLD (line 163) | const LOG_INFO_OLD: &str = r#"
constant LOG_INFO_NEW (line 191) | const LOG_INFO_NEW: &str = r#"
constant LOG_PROOF (line 219) | const LOG_PROOF: &str = r#"
constant REKOR_STAGING_KEY_PEM (line 236) | const REKOR_STAGING_KEY_PEM: &str = r#"
function test_consistency_valid (line 244) | fn test_consistency_valid() {
function test_consistency_invalid (line 274) | fn test_consistency_invalid() {
FILE: src/rekor/models/proposed_entry.rs
type ProposedEntry (line 14) | pub enum ProposedEntry {
FILE: src/rekor/models/rekord.rs
type Rekord (line 15) | pub struct Rekord {
method new (line 26) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/rekord_all_of.rs
type RekordAllOf (line 14) | pub struct RekordAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> RekordAllOf {
FILE: src/rekor/models/rfc3161.rs
type Rfc3161 (line 15) | pub struct Rfc3161 {
method new (line 26) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/rfc3161_all_of.rs
type Rfc3161AllOf (line 14) | pub struct Rfc3161AllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> Rfc3161All...
FILE: src/rekor/models/rpm.rs
type Rpm (line 16) | pub struct Rpm {
method new (line 27) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/rpm_all_of.rs
type RpmAllOf (line 13) | pub struct RpmAllOf {
method new (line 21) | pub fn new(api_version: String, spec: serde_json::Value) -> RpmAllOf {
FILE: src/rekor/models/search_index.rs
type SearchIndex (line 14) | pub struct SearchIndex {
method new (line 24) | pub fn new() -> SearchIndex {
FILE: src/rekor/models/search_index_public_key.rs
type SearchIndexPublicKey (line 14) | pub struct SearchIndexPublicKey {
method new (line 24) | pub fn new(format: Format) -> SearchIndexPublicKey {
type Format (line 37) | pub enum Format {
FILE: src/rekor/models/search_log_query.rs
type SearchLogQuery (line 14) | pub struct SearchLogQuery {
method new (line 24) | pub fn new() -> SearchLogQuery {
FILE: src/rekor/models/tuf.rs
type Tuf (line 16) | pub struct Tuf {
method new (line 27) | pub fn new(kind: String, api_version: String, spec: serde_json::Value)...
FILE: src/rekor/models/tuf_all_of.rs
type TufAllOf (line 14) | pub struct TufAllOf {
method new (line 22) | pub fn new(api_version: String, spec: serde_json::Value) -> TufAllOf {
FILE: src/trust/mod.rs
type TrustRoot (line 25) | pub trait TrustRoot {
method fulcio_certs (line 26) | fn fulcio_certs(&self) -> crate::errors::Result<Vec<CertificateDer<'_>>>;
method rekor_keys (line 27) | fn rekor_keys(&self) -> crate::errors::Result<BTreeMap<String, &[u8]>>;
method ctfe_keys (line 28) | fn ctfe_keys(&self) -> crate::errors::Result<BTreeMap<String, &[u8]>>;
method fulcio_certs (line 41) | fn fulcio_certs(&self) -> crate::errors::Result<Vec<CertificateDer<'a>...
method rekor_keys (line 45) | fn rekor_keys(&self) -> crate::errors::Result<BTreeMap<String, &[u8]>> {
method ctfe_keys (line 53) | fn ctfe_keys(&self) -> crate::errors::Result<BTreeMap<String, &[u8]>> {
type ManualTrustRoot (line 34) | pub struct ManualTrustRoot<'a> {
FILE: src/trust/sigstore/constants.rs
constant SIGSTORE_METADATA_BASE (line 16) | pub(crate) const SIGSTORE_METADATA_BASE: &str = "https://tuf-repo-cdn.si...
constant SIGSTORE_TARGET_BASE (line 17) | pub(crate) const SIGSTORE_TARGET_BASE: &str = "https://tuf-repo-cdn.sigs...
FILE: src/trust/sigstore/mod.rs
type SigstoreTrustRoot (line 50) | pub struct SigstoreTrustRoot {
method from_tough (line 56) | async fn from_tough(
method new (line 69) | pub async fn new(cache_dir: Option<&Path>) -> Result<Self> {
method from_trusted_root_json_unchecked (line 99) | pub fn from_trusted_root_json_unchecked(data: &[u8]) -> Result<Self> {
method from_client_trust_config (line 118) | pub fn from_client_trust_config(pki_file: &PathBuf) -> Result<Self> {
method fetch_target (line 134) | async fn fetch_target<N>(
method tlog_keys (line 197) | fn tlog_keys(tlogs: &[TransparencyLogInstance]) -> impl Iterator<Item ...
method ca_keys (line 224) | fn ca_keys(
type Error (line 237) | type Error = SigstoreError;
method try_from (line 239) | fn try_from(value: ClientTrustConfig) -> Result<Self> {
method fulcio_certs (line 256) | fn fulcio_certs(&self) -> Result<Vec<CertificateDer<'_>>> {
method rekor_keys (line 277) | fn rekor_keys(&self) -> Result<BTreeMap<String, &[u8]>> {
method ctfe_keys (line 287) | fn ctfe_keys(&self) -> Result<BTreeMap<String, &[u8]>> {
function is_timerange_valid (line 303) | fn is_timerange_valid(range: Option<&TimeRange>, allow_expired: bool) ->...
function verify (line 333) | fn verify(root: &SigstoreTrustRoot, cache_dir: Option<&Path>) {
function cache_dir (line 356) | fn cache_dir() -> TempDir {
function trust_root (line 360) | async fn trust_root(cache: Option<&Path>) -> SigstoreTrustRoot {
function trust_root_fetch (line 368) | async fn trust_root_fetch(#[values(None, Some(cache_dir()))] cache: Opti...
function trust_root_outdated (line 377) | async fn trust_root_outdated(cache_dir: TempDir) {
function test_is_timerange_valid (line 392) | fn test_is_timerange_valid() {
function test_load_missing_trust_client_config (line 437) | fn test_load_missing_trust_client_config(
FILE: src/trust/sigstore/transport.rs
type ReqwestTransport (line 36) | pub(crate) struct ReqwestTransport {
method new (line 42) | pub(crate) fn new(client: Client) -> Self {
method fetch (line 52) | async fn fetch(&self, url: Url) -> Result<TransportStream, TransportErro...
type BytesStreamAdapter (line 91) | struct BytesStreamAdapter {
type Item (line 97) | type Item = Result<Bytes, TransportError>;
method poll_next (line 99) | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Opt...
function transport (line 118) | fn transport() -> ReqwestTransport {
function unsupported_scheme (line 123) | async fn unsupported_scheme() {
function file_not_found_on_disk (line 134) | async fn file_not_found_on_disk() {
function file_found_on_disk (line 145) | async fn file_found_on_disk() {
FILE: tests/conformance/conformance.rs
type Cli (line 29) | struct Cli {
type Commands (line 35) | enum Commands {
type Sign (line 43) | struct Sign {
type SignBundle (line 61) | struct SignBundle {
type Verify (line 75) | struct Verify {
type VerifyBundle (line 97) | struct VerifyBundle {
function main (line 114) | fn main() {
function sign_bundle (line 132) | fn sign_bundle(args: SignBundle) -> anyhow::Result<()> {
function verify_bundle (line 153) | fn verify_bundle(args: VerifyBundle) -> anyhow::Result<()> {
Condensed preview — 165 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (872K chars).
[
{
"path": ".cargo/audit.toml",
"chars": 360,
"preview": "[advisories]\nignore = [\n \"RUSTSEC-2023-0071\", # \"Classic\" RSA timing sidechannel attack from non-constant-time implemen"
},
{
"path": ".github/dependabot.yml",
"chars": 901,
"preview": "#\n# Copyright 2022 The Sigstore Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may n"
},
{
"path": ".github/workflows/auto-publish-crates-upon-release.yml",
"chars": 908,
"preview": "name: Publish-Crate-Upon-Release\non:\n release:\n types: [published]\n\npermissions:\n contents: read\n\nconcurrency:\n gr"
},
{
"path": ".github/workflows/conformance.yml",
"chars": 874,
"preview": "on: [workflow_dispatch]\n\nname: Conformance Suite\n\npermissions:\n contents: read\n\nconcurrency:\n group: ${{ github.workfl"
},
{
"path": ".github/workflows/security-audit.yml",
"chars": 908,
"preview": "name: Security audit\non:\n schedule:\n - cron: \"0 0 * * *\"\n push:\n paths:\n - \"**/Cargo.toml\"\n - \"**/Carg"
},
{
"path": ".github/workflows/tests.yml",
"chars": 5732,
"preview": "on: [push, pull_request]\n\nname: Continuous integration\n\npermissions:\n contents: read\n\nconcurrency:\n group: ${{ github."
},
{
"path": ".github/workflows/zizmor.yml",
"chars": 762,
"preview": "name: 'zizmor: GitHub Actions Security Analysis'\n\non:\n push:\n branches: [\"main\"]\n pull_request:\n branches: [\"**\""
},
{
"path": ".gitignore",
"chars": 376,
"preview": "debug/\ntarget/\n\n# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries\n# More information "
},
{
"path": ".taplo.toml",
"chars": 126,
"preview": "exclude = [\".cargo/audit.toml\"]\n\n[[rule]]\n\n[rule.formatting]\nindent_string = \" \"\nreorder_arrays = true\nreorder_keys ="
},
{
"path": "CHANGELOG.md",
"chars": 21441,
"preview": "# v0.10.0\n\n## What's Changed\n\n- chore(deps): Update oci-distribution requirement from 0.10 to 0.11 by @dependabot in htt"
},
{
"path": "CODEOWNERS",
"chars": 173,
"preview": "# The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order):\n#\n# flavio\n# lukehinds\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3214,
"preview": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and"
},
{
"path": "CONTRIBUTORS.md",
"chars": 4674,
"preview": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish\nto make via an [issue](ht"
},
{
"path": "COPYRIGHT.txt",
"chars": 563,
"preview": "\nCopyright 2021 The Sigstore Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use t"
},
{
"path": "Cargo.toml",
"chars": 9039,
"preview": "[package]\nauthors = [\"sigstore-rs developers\"]\ndescription = \"An experimental crate to interact with sigstore\"\nedition ="
},
{
"path": "LICENSE",
"chars": 11356,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 1225,
"preview": ".PHONY: build\nbuild:\n\tcargo build --release\n\n.PHONY: fmt\nfmt:\n\tcargo fmt --all -- --check\n\ttaplo fmt --check\n\n.PHONY: li"
},
{
"path": "README.md",
"chars": 3166,
"preview": "Continuous integration | Docs | License | Crate version | Crate downloads\n ----------------------|------|---------|-----"
},
{
"path": "clippy.toml",
"chars": 57,
"preview": "allow-panic-in-tests = true\nallow-unwrap-in-tests = true\n"
},
{
"path": "examples/README.md",
"chars": 341,
"preview": "# sigstore-rs code examples\n\nThis folder contains executable examples of the sigstore-rs library.\n\nTo run any given exam"
},
{
"path": "examples/bundle/README.md",
"chars": 1289,
"preview": "This example shows how to sign and verify Sigstore signature bundles. The bundle\nformat used here is supported by most S"
},
{
"path": "examples/bundle/main.rs",
"chars": 4935,
"preview": "use clap::{Parser, Subcommand};\nuse std::fs;\nuse std::path::PathBuf;\nuse tracing::debug;\nuse tracing_subscriber::prelude"
},
{
"path": "examples/cosign/sign/README.md",
"chars": 1354,
"preview": "This is a simple example program that shows how perform cosign signing.\n\nThe program allows also to use annotation, in t"
},
{
"path": "examples/cosign/sign/main.rs",
"chars": 6136,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/cosign/trustroot/main.rs",
"chars": 419,
"preview": "use anyhow::Result;\nuse sigstore::trust::{TrustRoot, sigstore::SigstoreTrustRoot};\n\n#[tokio::main]\npub async fn main() -"
},
{
"path": "examples/cosign/verify/README.md",
"chars": 833,
"preview": "This is a simple example program that shows how perform cosign verification.\n\nThe program allows also to use annotation,"
},
{
"path": "examples/cosign/verify/main.rs",
"chars": 11660,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/cosign/verify-blob/.gitignore",
"chars": 35,
"preview": "signature\ncertificate\nartifact.txt\n"
},
{
"path": "examples/cosign/verify-blob/README.md",
"chars": 3601,
"preview": "This example shows how to verify a blob signature that was created by the\n`cosign sign-blob` command.\n\n### Create the ar"
},
{
"path": "examples/cosign/verify-blob/main.rs",
"chars": 2507,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/cosign/verify-bundle/.gitignore",
"chars": 29,
"preview": "artifact.bundle\nartifact.txt\n"
},
{
"path": "examples/cosign/verify-bundle/README.md",
"chars": 426,
"preview": "This example shows how to verify a blob, using a bundle that was created by the\n`cosign sign-blob` command.\n\n### Sign RE"
},
{
"path": "examples/cosign/verify-bundle/main.rs",
"chars": 3020,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/cosign/verify-bundle/run.sh",
"chars": 307,
"preview": "BLOB=\"README.md\"\nBUNDLE=\"artifact.bundle\"\n\necho -e \"\\nSign README.md file using sign-blob\"\ncosign sign-blob --bundle=$BU"
},
{
"path": "examples/fulcio/cert/main.rs",
"chars": 1115,
"preview": "use pkcs8::der::Decode;\nuse sigstore::crypto::SigningScheme;\nuse sigstore::fulcio::oauth::OauthTokenProvider;\nuse sigsto"
},
{
"path": "examples/key_interface/README.md",
"chars": 4461,
"preview": "# Example Key Interface\n\nThis is a simple example program that shows how to use the key interfaces.\nThe key interfaces c"
},
{
"path": "examples/key_interface/key_pair_gen_and_export/main.rs",
"chars": 1832,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/key_interface/key_pair_gen_sign_verify/main.rs",
"chars": 1618,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/key_interface/key_pair_import/ECDSA_P256_ASN1_ENCRYPTED_PRIVATE_PEM.key",
"chars": 649,
"preview": "-----BEGIN ENCRYPTED COSIGN PRIVATE KEY-----\neyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6\nOCwicCI6MX"
},
{
"path": "examples/key_interface/key_pair_import/ECDSA_P256_ASN1_PRIVATE_PEM.key",
"chars": 241,
"preview": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg5qt7YAIL9zSg38Pi\n5DX7rHjEcQAZkDk5MulVsr6x3Qe"
},
{
"path": "examples/key_interface/key_pair_import/ECDSA_P256_ASN1_PUBLIC_PEM.pub",
"chars": 178,
"preview": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE10MJqZ6tgxCxOvANHgfKMY90bso8\nH+Iq3rPfT6GrFbYAgckw24H69hgn"
},
{
"path": "examples/key_interface/key_pair_import/main.rs",
"chars": 3438,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/openidflow/README.md",
"chars": 694,
"preview": "# Open ID Connect Flow for Fulcio Signing Certificates\n\nThis is an example of the fulcio OpenID connect flow.\n\nThe gener"
},
{
"path": "examples/openidflow/openidconnect/main.rs",
"chars": 1858,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/README.md",
"chars": 111,
"preview": "# Rekor Transparency Log Client\n\nThe following examples all interface with the Rekor Transparency Log Client.\n\n"
},
{
"path": "examples/rekor/create_log_entry/main.rs",
"chars": 10009,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/get_log_entry_by_index/main.rs",
"chars": 1737,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/get_log_entry_by_uuid/main.rs",
"chars": 1781,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/get_log_info/main.rs",
"chars": 1286,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/get_log_proof/main.rs",
"chars": 2599,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/get_public_key/main.rs",
"chars": 2188,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/merkle_proofs/consistency.rs",
"chars": 1460,
"preview": "use clap::Parser;\nuse sigstore::crypto::CosignVerificationKey;\nuse sigstore::rekor::apis::configuration::Configuration;\n"
},
{
"path": "examples/rekor/merkle_proofs/inclusion.rs",
"chars": 1083,
"preview": "use clap::Parser;\nuse sigstore::crypto::CosignVerificationKey;\nuse sigstore::rekor::apis::configuration::Configuration;\n"
},
{
"path": "examples/rekor/search_index/main.rs",
"chars": 4344,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "examples/rekor/search_log_query/main.rs",
"chars": 5899,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "rust-toolchain.toml",
"chars": 283,
"preview": "[toolchain]\n# Pin to a specific stable version for consistent clippy/fmt across contributors\n# Update this deliberately "
},
{
"path": "src/bundle/mod.rs",
"chars": 892,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/bundle/models.rs",
"chars": 3129,
"preview": "use std::fmt::Display;\nuse std::str::FromStr;\n\nuse base64::{Engine as _, engine::general_purpose::STANDARD as base64};\n\n"
},
{
"path": "src/bundle/sign.rs",
"chars": 14085,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/bundle/verify/mod.rs",
"chars": 833,
"preview": "//\n// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/bundle/verify/models.rs",
"chars": 9631,
"preview": "//\n// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/bundle/verify/policy.rs",
"chars": 8846,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/bundle/verify/verifier.rs",
"chars": 10734,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/cosign/bundle.rs",
"chars": 11658,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/client.rs",
"chars": 7607,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/client_builder.rs",
"chars": 7839,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/constants.rs",
"chars": 1931,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/constraint/annotation.rs",
"chars": 2469,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/constraint/mod.rs",
"chars": 2693,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/constraint/signature.rs",
"chars": 2631,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/mod.rs",
"chars": 27973,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/payload/mod.rs",
"chars": 926,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/payload/simple_signing.rs",
"chars": 11587,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/signature_layers.rs",
"chars": 39988,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/verification_constraint/annotation_verifier.rs",
"chars": 986,
"preview": "use std::collections::BTreeMap;\n\nuse super::VerificationConstraint;\nuse crate::cosign::signature_layers::SignatureLayer;"
},
{
"path": "src/cosign/verification_constraint/cert_subject_email_verifier.rs",
"chars": 13892,
"preview": "use regex::Regex;\nuse std::fmt::Debug;\n\nuse super::VerificationConstraint;\nuse crate::cosign::signature_layers::{Certifi"
},
{
"path": "src/cosign/verification_constraint/cert_subject_url_verifier.rs",
"chars": 4373,
"preview": "use super::VerificationConstraint;\nuse crate::cosign::signature_layers::{CertificateSubject, SignatureLayer};\nuse crate:"
},
{
"path": "src/cosign/verification_constraint/certificate_verifier.rs",
"chars": 14875,
"preview": "use chrono::{DateTime, Utc};\nuse pkcs8::der::Decode;\nuse pki_types::CertificateDer;\nuse tracing::warn;\nuse x509_cert::Ce"
},
{
"path": "src/cosign/verification_constraint/mod.rs",
"chars": 3373,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/cosign/verification_constraint/public_key_verifier.rs",
"chars": 2110,
"preview": "use super::VerificationConstraint;\nuse crate::cosign::signature_layers::SignatureLayer;\nuse crate::crypto::{CosignVerifi"
},
{
"path": "src/crypto/certificate.rs",
"chars": 17743,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/certificate_pool.rs",
"chars": 4426,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/keyring.rs",
"chars": 5826,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/crypto/merkle/mod.rs",
"chars": 845,
"preview": "pub mod proof_verification;\npub mod rfc6962;\n\nuse crate::errors::SigstoreError;\nuse crate::errors::SigstoreError::Unexpe"
},
{
"path": "src/crypto/merkle/proof_verification.rs",
"chars": 32568,
"preview": "use super::rfc6962::Rfc6269HasherTrait;\nuse MerkleProofError::*;\nuse digest::{Digest, Output};\n\n#[cfg(any(\n feature ="
},
{
"path": "src/crypto/merkle/rfc6962.rs",
"chars": 4111,
"preview": "use super::rfc6962::Rfc6269HashPrefix::{RFC6962LeafHashPrefix, RFC6962NodeHashPrefix};\nuse digest::Output;\nuse sha2::{Di"
},
{
"path": "src/crypto/mod.rs",
"chars": 19929,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/ecdsa/ec.rs",
"chars": 21389,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/ecdsa/mod.rs",
"chars": 7024,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/ed25519.rs",
"chars": 17210,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/kdf.rs",
"chars": 8845,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/mod.rs",
"chars": 18903,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/rsa/keypair.rs",
"chars": 17148,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/signing_key/rsa/mod.rs",
"chars": 8869,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/crypto/transparency.rs",
"chars": 16200,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/crypto/verification_key.rs",
"chars": 29118,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/errors.rs",
"chars": 9218,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/fulcio/mod.rs",
"chars": 8952,
"preview": "pub(crate) mod models;\n\npub mod oauth;\n\nuse crate::crypto::SigningScheme;\nuse crate::crypto::signing_key::SigStoreSigner"
},
{
"path": "src/fulcio/models.rs",
"chars": 3916,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/fulcio/oauth.rs",
"chars": 4118,
"preview": "use crate::errors::Result;\nuse crate::errors::SigstoreError;\nuse crate::oauth::openidflow::{OpenIDAuthorize, RedirectLis"
},
{
"path": "src/lib.rs",
"chars": 9979,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/mock_client.rs",
"chars": 4839,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/oauth/http_client.rs",
"chars": 3509,
"preview": "//\n// Copyright 2026 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/oauth/mod.rs",
"chars": 697,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/oauth/openidflow.rs",
"chars": 14703,
"preview": "//\n// Copyright 2022 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/oauth/token.rs",
"chars": 3212,
"preview": "// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may"
},
{
"path": "src/registry/config.rs",
"chars": 7389,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/registry/mod.rs",
"chars": 3241,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/registry/oci_caching_client.rs",
"chars": 10488,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/registry/oci_client.rs",
"chars": 3190,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/registry/oci_reference.rs",
"chars": 2976,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/rekor/apis/configuration.rs",
"chars": 1335,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/apis/entries_api.rs",
"chars": 9118,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/apis/index_api.rs",
"chars": 2187,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/apis/mod.rs",
"chars": 999,
"preview": "use thiserror::Error;\n\n#[derive(Debug, Clone)]\npub struct ResponseContent<T> {\n pub status: reqwest::StatusCode,\n "
},
{
"path": "src/rekor/apis/pubkey_api.rs",
"chars": 2244,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/apis/tlog_api.rs",
"chars": 6156,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/mod.rs",
"chars": 3224,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/rekor/models/alpine.rs",
"chars": 778,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/alpine_all_of.rs",
"chars": 630,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/checkpoint.rs",
"chars": 20064,
"preview": "use crate::crypto::merkle::{MerkleProofVerifier, Rfc6269Default};\nuse crate::crypto::{CosignVerificationKey, Signature};"
},
{
"path": "src/rekor/models/consistency_proof.rs",
"chars": 3366,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/error.rs",
"chars": 680,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/hashedrekord.rs",
"chars": 3007,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/hashedrekord_all_of.rs",
"chars": 654,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/helm.rs",
"chars": 761,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/helm_all_of.rs",
"chars": 622,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/inactive_shard_log_info.rs",
"chars": 1172,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/inclusion_proof.rs",
"chars": 3261,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/intoto.rs",
"chars": 777,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/intoto_all_of.rs",
"chars": 630,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/jar.rs",
"chars": 771,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/jar_all_of.rs",
"chars": 618,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/log_entry.rs",
"chars": 15294,
"preview": "//\n// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/rekor/models/log_info.rs",
"chars": 15221,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/mod.rs",
"chars": 1781,
"preview": "pub mod alpine;\npub use self::alpine::Alpine;\npub mod alpine_all_of;\npub use self::alpine_all_of::AlpineAllOf;\npub mod c"
},
{
"path": "src/rekor/models/proposed_entry.rs",
"chars": 2051,
"preview": "/*\n* Rekor\n*\n* Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n*\n* The ver"
},
{
"path": "src/rekor/models/rekord.rs",
"chars": 776,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/rekord_all_of.rs",
"chars": 630,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/rfc3161.rs",
"chars": 789,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/rfc3161_all_of.rs",
"chars": 634,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/rpm.rs",
"chars": 758,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/rpm_all_of.rs",
"chars": 617,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/search_index.rs",
"chars": 904,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/search_index_public_key.rs",
"chars": 1235,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/search_log_query.rs",
"chars": 925,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/tuf.rs",
"chars": 760,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/rekor/models/tuf_all_of.rs",
"chars": 618,
"preview": "/*\n * Rekor\n *\n * Rekor is a cryptographically secure, immutable transparency log for signed software releases.\n *\n * Th"
},
{
"path": "src/trust/mod.rs",
"chars": 2114,
"preview": "//\n// Copyright 2024 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/trust/sigstore/constants.rs",
"chars": 1270,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/trust/sigstore/mod.rs",
"chars": 17464,
"preview": "//\n// Copyright 2021 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "src/trust/sigstore/transport.rs",
"chars": 5085,
"preview": "//\n// Copyright 2026 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "tests/conformance/Cargo.toml",
"chars": 479,
"preview": "[package]\nauthors = [\"sigstore-rs developers\"]\ndescription = \"sigstore conformance testing workflow\"\nedition = \"2021\"\nli"
},
{
"path": "tests/conformance/conformance.rs",
"chars": 4374,
"preview": "//\n// Copyright 2023 The Sigstore Authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
},
{
"path": "tests/data/keys/cosign_generated_encrypted_empty_private.key",
"chars": 653,
"preview": "-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----\neyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjo2NTUzNiwiciI6\nOCwicCI6"
},
{
"path": "tests/data/keys/ecdsa_encrypted_private.key",
"chars": 649,
"preview": "-----BEGIN ENCRYPTED COSIGN PRIVATE KEY-----\neyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6\nOCwicCI6MX"
},
{
"path": "tests/data/keys/ecdsa_private.key",
"chars": 241,
"preview": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgAbUSDapDt/yShCq1\nrzJwhGj9fMQd21E5SXmln12o8J+"
},
{
"path": "tests/data/keys/ed25519_encrypted_private.key",
"chars": 562,
"preview": "-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----\r\neyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6\r\nOCwicC"
},
{
"path": "tests/data/keys/ed25519_private.key",
"chars": 168,
"preview": "-----BEGIN PRIVATE KEY-----\nMFECAQEwBQYDK2VwBCIEILZ7IMwQHwlrU+a5l0WnujhvsmQXrWsStjtbAj8n/EiJ\ngSEAXtg9yVbH8JADtC6sn4NBh1C"
},
{
"path": "tests/data/keys/rsa_encrypted_private.key",
"chars": 4768,
"preview": "-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----\r\neyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6\r\nOCwicC"
},
{
"path": "tests/data/keys/rsa_private.key",
"chars": 3243,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAzk4HyifDz3BhYUj4YDk6SjwpZgCh1dkEaL/E1/k8VUFvDH53\niJ/dwbIotd920y86nqA1P8J"
},
{
"path": "trust_root/prod/root.json",
"chars": 5413,
"preview": "{\n \"signatures\": [\n {\n \"keyid\": \"6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3\",\n \"sig\": \"\"\n },"
},
{
"path": "trust_root/prod/trusted_root.json",
"chars": 4537,
"preview": "{\n \"mediaType\": \"application/vnd.dev.sigstore.trustedroot+json;version=0.1\",\n \"tlogs\": [\n {\n \"baseUrl\": \"https"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the sigstore/sigstore-rs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 165 files (814.8 KB), approximately 222.9k tokens, and a symbol index with 919 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.