diff --git a/.github/workflows/build-snapshot.yaml b/.github/workflows/build-snapshot.yaml index 9176e176e..7963cbea4 100644 --- a/.github/workflows/build-snapshot.yaml +++ b/.github/workflows/build-snapshot.yaml @@ -11,20 +11,19 @@ jobs: contents: read runs-on: ubuntu-latest - outputs: - hashes: ${{ steps.hash.outputs.hashes }} - tag_name: ${{ steps.tag.outputs.tag_name }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version-file: './go.mod' check-latest: true - - uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - - uses: anchore/sbom-action/download-syft@df80a981bc6edbc4e220a492d3cbe9f5547a6e75 # v0.17.9 - - uses: imjasonh/setup-ko@d982fec422852203cfb2053a8ec6ad302280d04d # v0.8 + - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 + - uses: anchore/sbom-action/download-syft@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0 + - uses: imjasonh/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: Set LDFLAGS id: ldflags @@ -35,7 +34,7 @@ jobs: - name: Run GoReleaser id: run-goreleaser - uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0 + uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.2.1 # zizmor: ignore[cache-poisoning] with: version: latest args: release --clean --skip=sign --snapshot diff --git a/.github/workflows/codeql_analysis.yaml b/.github/workflows/codeql_analysis.yaml index c2a6b7db1..dd3892715 100644 --- a/.github/workflows/codeql_analysis.yaml +++ b/.github/workflows/codeql_analysis.yaml @@ -41,20 +41,25 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version-file: './go.mod' check-latest: true # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 + uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: languages: ${{ matrix.language }} + build-mode: manual + dependency-caching: true - - name: Autobuild - uses: github/codeql-action/autobuild@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 + - name: Build Code + run: | + make all test - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 + uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 diff --git a/.github/workflows/dependecy_review.yaml b/.github/workflows/dependency_review.yaml similarity index 70% rename from .github/workflows/dependecy_review.yaml rename to .github/workflows/dependency_review.yaml index 5b4e737d9..bd80430c0 100644 --- a/.github/workflows/dependecy_review.yaml +++ b/.github/workflows/dependency_review.yaml @@ -20,9 +20,5 @@ permissions: jobs: dependency-review: - runs-on: ubuntu-latest - steps: - - name: 'Checkout Repository' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: 'Dependency Review' - uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 + name: License and Vulnerability Scan + uses: sigstore/community/.github/workflows/reusable-dependency-review.yml@9b1b5aca605f92ec5b1bf3681b1e61b3dbc420cc diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 43f9aa9bf..d4bae6c20 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,7 +7,7 @@ on: concurrency: cut-release -permissions: read-all +permissions: {} jobs: release: @@ -21,15 +21,18 @@ jobs: tag_name: ${{ steps.tag.outputs.tag_name }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version-file: './go.mod' check-latest: true + cache: false # avoid cache-poisoning attacks - - uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - - uses: anchore/sbom-action/download-syft@df80a981bc6edbc4e220a492d3cbe9f5547a6e75 # v0.17.9 - - uses: imjasonh/setup-ko@d982fec422852203cfb2053a8ec6ad302280d04d # v0.8 + - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 + - uses: anchore/sbom-action/download-syft@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0 + - uses: imjasonh/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: Set LDFLAGS id: ldflags @@ -40,7 +43,7 @@ jobs: - name: Run GoReleaser id: run-goreleaser - uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0 + uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0 with: version: latest args: release --clean @@ -70,7 +73,7 @@ jobs: actions: read # To read the workflow path. id-token: write # To sign the provenance. contents: write # To add assets to a release. - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 with: base64-subjects: "${{ needs.release.outputs.hashes }}" upload-assets: true diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index b4407b7f3..fe8b5b3c0 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -42,7 +42,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: results_file: results.sarif results_format: sarif @@ -58,7 +58,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: SARIF file path: results.sarif @@ -66,6 +66,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 + uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: sarif_file: results.sarif diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 5fa82da6d..2a01f0cc2 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -19,10 +19,9 @@ on: push: branches: - 'main' - - 'updates' pull_request: -permissions: read-all +permissions: {} jobs: unit-tests: @@ -36,8 +35,10 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds - - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: # In order: # * Module download cache @@ -50,7 +51,7 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version-file: './go.mod' check-latest: true @@ -59,7 +60,7 @@ jobs: - name: Run Go tests run: go test -covermode atomic -coverprofile coverage.txt $(go list ./... | grep -v third_party/) - name: Upload Coverage Report - uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2 + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: env_vars: OS - name: Run Go tests w/ `-race` @@ -69,9 +70,13 @@ jobs: license-check: name: license boilerplate check runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + with: + persist-credentials: false + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version-file: './go.mod' check-latest: true @@ -85,15 +90,37 @@ jobs: golangci: name: lint runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + with: + persist-credentials: false + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version-file: './go.mod' check-latest: true - name: golangci-lint - uses: golangci/golangci-lint-action@ec5d18412c0aeab7936cb16880d708ba2a64e1ae # v6.2.0 + uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: - version: v1.61 + version: v2.1 args: --timeout=10m --verbose + + gen-check: + name: Check generated code + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: './go.mod' + check-latest: true + - name: Verify generated code is unchanged + run: | + make gen + git diff --exit-code diff --git a/.golangci.yml b/.golangci.yml index 81f3d0f79..927f9016b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -13,30 +13,46 @@ # See the License for the specific language governing permissions and # limitations under the License. +version: "2" +run: + issues-exit-code: 1 linters: enable: - - errcheck - - gofmt - - goimports - - gosec - gocritic + - gosec - misspell - revive - - unused -output: - uniq-by-line: false + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - errcheck + - gosec + path: _test\.go + - linters: + - staticcheck + path: pkg/signer/tink.go + text: SA1019 + paths: + - third_party$ + - builtin$ + - examples$ issues: - exclude-rules: - - path: _test\.go - linters: - - errcheck - - gosec - - path: pkg/signer/tink.go - linters: - - staticcheck - text: SA1019 max-issues-per-linter: 0 max-same-issues: 0 -run: - issues-exit-code: 1 - timeout: 10m + uniq-by-line: false +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/.goreleaser.yml b/.goreleaser.yml index c21b6a750..15b49e39a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,5 +1,7 @@ project_name: timestamp-authority +version: 2 + env: - GO111MODULE=on - CGO_ENABLED=0 @@ -76,7 +78,7 @@ signs: artifacts: checksum archives: - - format: binary + - formats: [ "binary" ] name_template: "{{ .Binary }}" allow_different_binary_count: true @@ -84,7 +86,7 @@ checksum: name_template: "{{ .ProjectName }}_checksums.txt" snapshot: - name_template: SNAPSHOT-{{ .ShortCommit }} + version_template: SNAPSHOT-{{ .ShortCommit }} release: prerelease: auto diff --git a/.tekton/fetch-tsa-certs-pull-request.yaml b/.tekton/fetch-tsa-certs-pull-request.yaml index fad605944..00d2c2464 100644 --- a/.tekton/fetch-tsa-certs-pull-request.yaml +++ b/.tekton/fetch-tsa-certs-pull-request.yaml @@ -45,7 +45,7 @@ spec: CGO_ENABLED=0 go build -trimpath -o bin/timestamp-server ./cmd/timestamp-server go test ./... - name: go_base_image - value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder@sha256:356986205e66dcc03ef9a9fef5a7a13d6d59c29efacf1d971f9224c678932cf0 + value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder:rhel_9_1.23@sha256:44fd8f88f3b6463cda15571260f9ca3a0b78d3c8c8827a338e04ab3a23581a88 pipelineRef: params: - name: url diff --git a/.tekton/fetch-tsa-certs-push.yaml b/.tekton/fetch-tsa-certs-push.yaml index e5e585afa..a229c8c6b 100644 --- a/.tekton/fetch-tsa-certs-push.yaml +++ b/.tekton/fetch-tsa-certs-push.yaml @@ -42,7 +42,7 @@ spec: CGO_ENABLED=0 go build -trimpath -o bin/timestamp-server ./cmd/timestamp-server go test ./... - name: go_base_image - value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder@sha256:356986205e66dcc03ef9a9fef5a7a13d6d59c29efacf1d971f9224c678932cf0 + value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder:rhel_9_1.23@sha256:44fd8f88f3b6463cda15571260f9ca3a0b78d3c8c8827a338e04ab3a23581a88 pipelineRef: params: - name: url diff --git a/.tekton/timestamp-authority-pull-request.yaml b/.tekton/timestamp-authority-pull-request.yaml index d8d6b3809..d8549a620 100644 --- a/.tekton/timestamp-authority-pull-request.yaml +++ b/.tekton/timestamp-authority-pull-request.yaml @@ -45,7 +45,7 @@ spec: CGO_ENABLED=0 go build -trimpath -o bin/timestamp-server ./cmd/timestamp-server go test ./... - name: go_base_image - value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder@sha256:356986205e66dcc03ef9a9fef5a7a13d6d59c29efacf1d971f9224c678932cf0 + value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder:rhel_9_1.23@sha256:44fd8f88f3b6463cda15571260f9ca3a0b78d3c8c8827a338e04ab3a23581a88 pipelineRef: params: - name: url diff --git a/.tekton/timestamp-authority-push.yaml b/.tekton/timestamp-authority-push.yaml index 133360b21..da1992797 100644 --- a/.tekton/timestamp-authority-push.yaml +++ b/.tekton/timestamp-authority-push.yaml @@ -42,7 +42,7 @@ spec: CGO_ENABLED=0 go build -trimpath -o bin/timestamp-server ./cmd/timestamp-server go test ./... - name: go_base_image - value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder@sha256:356986205e66dcc03ef9a9fef5a7a13d6d59c29efacf1d971f9224c678932cf0 + value: brew.registry.redhat.io/rh-osbs/openshift-golang-builder:rhel_9_1.23@sha256:44fd8f88f3b6463cda15571260f9ca3a0b78d3c8c8827a338e04ab3a23581a88 pipelineRef: params: - name: url diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f618a600..d0e118fe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,74 @@ +# v1.2.8 + +## Features + +* Allow full issuing chain in response (#1082) +* Relax EKU chaining rules verification for intermediate certs (#1078) + +# v1.2.7 + +## Features + +* fetch-tsa-certs: Add "--org-name" (#1056) + +## Bug Fixes + +* Fix: Disallow timestamp requests where digest length is inconsistent with hash algorithm (#1066) +* Fix --http-ping-only flag to not affect https listener (#1051) + +# v1.2.6 + +## Features + +* allow operators to customize the HTTP header used to customize request correlation IDs (#1026) + +## Bug Fixes + +* Do not assume leaf certificate is first in chain (#1040) + +# v1.2.5 + +### Enhancements + +* Exposes validity period of signing certificate as prometheus metric for monitoring +* fetch-tsa-certs now supports fetching a self-signed certificate chain + +## Changes + +### Bug fixes + +* Minor tweaks to CI configuration for hardening + +### Misc + +* Add fuzzing coverage with oss-fuzz +* Dependabot updates + +# v1.2.4 + +## Changes + +### Bug fixes + +* Fix timestamp response to always be returned in GMT + +### Misc + +* Relax go directive to permit 1.22.x +* Dependabot updates + +# v1.2.3 + +## Changes + +### Bug fixes + +* Don't mark hash argument as required in timestamp-cli + +### Misc + +* Dependabot updates + # v1.2.2 ## Changes diff --git a/CODEOWNERS b/CODEOWNERS index 597c43acc..1fb386da7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,13 +1,6 @@ -* @sigstore/timestamp-codeowners +* @sigstore/timestamp-codeowners -/.github/ @cpanato -/release/ @cpanato - -asraa -haydentherapper - -# The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order): - -# asraa -# bobcallaway -# haydentherapper +/.github/ @sigstore/dep-maintainers +/release/ @sigstore/dep-maintainers +go.mod @sigstore/dep-maintainers +go.sum @sigstore/dep-maintainers diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 440768d57..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# 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 . 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/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0330ffff4..f70eabceb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:1.24.2@sha256:1ecc479bc712a6bdb56df3e346e33edcc141f469f82840bab9f4bc2bc41bf91d AS builder +FROM golang:1.24.3@sha256:81bf5927dc91aefb42e2bc3a5abdbe9bb3bae8ba8b107e2a4cf43ce3402534c6 AS builder ENV APP_ROOT=/opt/app-root ENV GOPATH=$APP_ROOT @@ -36,7 +36,7 @@ RUN go install github.com/go-delve/delve/cmd/dlv@v1.9.0 COPY --from=builder /opt/app-root/src/timestamp-server_debug /usr/local/bin/timestamp-server # Multi-Stage production build -FROM golang:1.24.2@sha256:1ecc479bc712a6bdb56df3e346e33edcc141f469f82840bab9f4bc2bc41bf91d as deploy +FROM golang:1.24.3@sha256:81bf5927dc91aefb42e2bc3a5abdbe9bb3bae8ba8b107e2a4cf43ce3402534c6 as deploy # Retrieve the binary from the previous stage COPY --from=builder /opt/app-root/src/timestamp-server /usr/local/bin/timestamp-server diff --git a/Makefile b/Makefile index c0c942e66..166571e7d 100644 --- a/Makefile +++ b/Makefile @@ -136,4 +136,4 @@ help: ## Display help printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \ }' $(MAKEFILE_LIST) | sort -include release/release.mk +include release/release.mk \ No newline at end of file diff --git a/README.md b/README.md index bfcf4266d..29b1971ed 100644 --- a/README.md +++ b/README.md @@ -118,26 +118,59 @@ To deploy to production, the timestamp authority currently supports signing with a certificate chain (leaf, any intermediates, and root), where the certificate chain's purpose (extended key usage) is for timestamping. We do not recommend the file signer for production since the signing key will only be password protected. +### Certificate Maker + +Certificate Maker is a tool for creating RFC 3161 compliant certificate chains for Timestamp Authority. It supports: + +* Two-level chains: + * root → leaf + * root → intermediate +* Three-level chains: + * root → intermediate → leaf +* Multiple KMS providers (AWS, Google Cloud, Azure, HashiCorp Vault) + +For detailed usage instructions and examples, see the [Certificate Maker documentation](docs/certificate-maker.md). + ### Cloud KMS -Create an asymmetric cloud KMS signing key in either GCP, AWS, Azure, or Vault, that will be used to sign timestamps. Generate a certificate chain, which must include a leaf certificate whose public key pairs to the private key in cloud KMS, may include any number of intermediate certificates, and must include a root certificate. We recommend reviewing the [code](https://github.com/sigstore/timestamp-authority/blob/main/cmd/fetch-tsa-certs/fetch_tsa_certs.go) -used to generate the certificate chain if you do not want to use GCP. If you are using GCP: +used to generate the certificate chain if you do not want to use GCP. + +#### Example: timestamp signing key on GCP, intermediate key on GCP, root CA on GCP + * Create a root CA with [GCP CA Service](https://cloud.google.com/certificate-authority-service). Configure lifetime, and other defaults can remain. You will need to first create a CA pool, and then create one CA in that pool. -* Create an asymmetric signing key on KMS that will be used as an intermediate CA to sign the TSA certificate. -* Run the following: +* Create an asymmetric certificate signing key on KMS that will be used as an intermediate CA to sign the TSA certificate. +* Create an asymmetric timestamp signing key on KMS. +* Run the following to create a certificate chain of root, intermediate and leaf certificates + ```shell + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --leaf-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --gcp-ca-parent="projects//locations//caPools/" \ + --org-name="example.com" + --output="chain.crt.pem" + ``` + +#### Example: signing key on GCP, self-signed root on GCP + +* Create an asymmetric certificate signing key on KMS that will be used in the self-signed certificate to sign the TSA certificate. +* Create an asymmetric timestamp signing key on KMS. +* Run the following to create a chain of self-signed certificate and leaf signing certificate: + ```shell + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --leaf-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --parent-validity= + --org-name="example.com" + --output="chain.crt.pem" + ``` + +#### Other KMSs -```shell -go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ - --intermediate-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ - --leaf-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ - --gcp-ca-parent="projects//locations//caPools/" \ - --output="chain.crt.pem" -``` If you are not using GCP, there are many possible options but the steps for setting up the certificates could be similar to the following: * create a KMS private key (for example, in the AWS KMS) * use this private key to create a CSR @@ -160,32 +193,47 @@ with a cloud KMS key, and decrypted on startup. Install [tinkey](https://github.com/google/tink/blob/master/docs/TINKEY.md) first. -Create a symmetric cloud KMS key in either GCP, AWS, or Vault, that will be used to encrypt a -signing key that is generated locally. +#### Example: Tinkey as timestamp signing key, intermediate key on GCP, root CA on GCP -Run the following to create the local encrypted signing key, changing key URI and the key template if desired: - -```shell -tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key-uri gcp-kms://path-to-key -``` - -Generate a certificate chain, which must include a leaf certificate whose public key pairs to the private key -in the Tink keyset, may include any number of intermediate certificates, and must include a root certificate. -We recommend reviewing the [code](https://github.com/sigstore/timestamp-authority/blob/main/cmd/fetch-tsa-certs/fetch_tsa_certs.go) -used to generate the certificate chain if you do not want to use GCP. If you are using GCP: +* Create a symmetric key encryption key in GCP +* Run the following to create the local encrypted signing key, changing key URI and the key template if desired: + ```shell + tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key-uri gcp-kms://projects//locations//keyRings//cryptoKeys/ + ``` * Create a root CA with [GCP CA Service](https://cloud.google.com/certificate-authority-service). Configure lifetime, and other defaults can remain. You will need to first create a CA pool, and then create one CA in that pool. * Create an asymmetric signing key on KMS that will be used as an intermediate CA to sign the TSA certificate. * Run the following: - -```shell -go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ - --intermediate-kms-resource="gcpkms://asymmetric-kms-key"\ - --tink-kms-resource="gcp-kms://tink-encryption-key"\ - --gcp-ca-parent="projects//locations//caPools/"\ - --tink-keyset-path="enc-keyset.cfg"\ - --output="chain.crt.pem" -``` + ```shell + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --tink-kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/"\ + --tink-keyset-path="enc-keyset.cfg"\ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1"\ + --gcp-ca-parent="projects//locations//caPools/"\ + --org-name="example.com" + --output="chain.crt.pem" + ``` + +#### Example: Tinkey as timestamp signing key, self-signed root on GCP + +* Create a symmetric key encryption key in GCP +* Run the following to create the local encrypted signing key, changing key URI and the key template if desired: + ```shell + tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key-uri gcp-kms://projects//locations//keyRings//cryptoKeys/ + ``` +* Create an asymmetric signing key on KMS that will be used in the self-signed certificate to sign the TSA certificate. +* Run the following: + ```shell + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --tink-kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/"\ + --tink-keyset-path="enc-keyset.cfg"\ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1"\ + --parent-validity= + --org-name="example.com" + --output="chain.crt.pem" + ``` + +#### Running Timestamp Authority with a tinkey To run the TSA, set `--timestamp-signer=tink`, `--tink-key-resource=`, and `--tink-keyset-path=enc-keyset.cfg`. The key resource should be prefixed with either `gcp-kms://`, `aws-kms://`, or `hcvault://`. diff --git a/cmd/fetch-tsa-certs/fetch_tsa_certs.go b/cmd/fetch-tsa-certs/fetch_tsa_certs.go index fe18517c8..a6fd24bbf 100644 --- a/cmd/fetch-tsa-certs/fetch_tsa_certs.go +++ b/cmd/fetch-tsa-certs/fetch_tsa_certs.go @@ -32,10 +32,11 @@ import ( privateca "cloud.google.com/go/security/privateca/apiv1" "cloud.google.com/go/security/privateca/apiv1/privatecapb" - "github.com/google/tink/go/keyset" "github.com/sigstore/sigstore/pkg/cryptoutils" + tinkUtils "github.com/sigstore/sigstore/pkg/signature/tink" "github.com/sigstore/timestamp-authority/pkg/signer" tsx509 "github.com/sigstore/timestamp-authority/pkg/x509" + "github.com/tink-crypto/tink-go/v2/keyset" "google.golang.org/protobuf/types/known/durationpb" // Register the provider-specific plugins @@ -47,19 +48,31 @@ import ( ) /* -To run: -go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ - --intermediate-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ - --leaf-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ - --gcp-ca-parent="projects//locations//caPools/" \ - --output="chain.crt.pem" - -go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ - --intermediate-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ - --tink-kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/" \ - --tink-keyset-path="enc-keyset.cfg" \ - --gcp-ca-parent="projects//locations//caPools/" \ - --output="chain.crt.pem" +Create certificate chain with a KMS signing key, a KMS intermediate and a CA root: + + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --leaf-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --gcp-ca-parent="projects//locations//caPools/" \ + --output="chain.crt.pem" + +Create certificate chain with a Tink signing key encrypted with KMS KEK, a KMS intermediate and a CA root: + + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --tink-kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/" \ + --tink-keyset-path="enc-keyset.cfg" \ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --gcp-ca-parent="projects//locations//caPools/" \ + --output="chain.crt.pem" + +Create certificate chain with a Tink signing key encrypted with KMS KEK and a self-signed parent certificate: + + go run cmd/fetch-tsa-certs/fetch_tsa_certs.go \ + --tink-kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/" \ + --tink-keyset-path="enc-keyset.cfg" \ + --parent-validity=365 \ + --parent-kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ + --output="chain.crt.pem" You must have the permissions to read, sign with, and decrypt with the KMS keys, and create a certificate in the CA pool. @@ -68,29 +81,35 @@ tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key */ var ( - // likely the root CA - gcpCaParent = flag.String("gcp-ca-parent", "", "Resource path to GCP CA Service CA") - // key only used for fetching intermediate certificate from root and signing leaf certificate - intermediateKMSKey = flag.String("intermediate-kms-resource", "", "Resource path to the asymmetric signing KMS key for the intermediate CA, starting with gcpkms://, awskms://, azurekms:// or hashivault://") + // Optional root CA + gcpCaRoot = flag.String("gcp-ca-root", "", "Resource path to GCP CA Service CA. If set, the parent certificate will be an intermediate one. If unset, the parent certificate is a self-signed one.") + + // The kms key to use for "parent" certificate (intermediate if CA is used, self-signed certificate otherwise) + parentKMSKey = flag.String("parent-kms-resource", "", "Resource path to the asymmetric signing KMS key for the parent certificate, starting with gcpkms://, awskms://, azurekms:// or hashivault://") + parentValidity = flag.Int("parent-validity", 20*365, "Days the parent certificate will be valid for. Default 20*365. Value will be truncated by CA if one is used.") + // leafKMSKey or Tink flags required leafKMSKey = flag.String("leaf-kms-resource", "", "Resource path to the asymmetric signing KMS key for the leaf, starting with gcpkms://, awskms://, azurekms:// or hashivault://") tinkKeysetPath = flag.String("tink-keyset-path", "", "Path to Tink keyset") tinkKmsKey = flag.String("tink-kms-resource", "", "Resource path to symmetric encryption KMS key to decrypt Tink keyset, starting with gcp-kms:// or aws-kms://") - outputPath = flag.String("output", "", "Path to the output file") + + orgName = flag.String("org-name", "", "Issuer organization name to use in created certificates") + + outputPath = flag.String("output", "", "Path to write the certificate chain to") ) -func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leafKMSKey, tinkKeysetPath, tinkKmsKey string, +func fetchCertificateChain(ctx context.Context, root, parentKMSKey, leafKMSKey, tinkKeysetPath, tinkKmsKey string, client *privateca.CertificateAuthorityClient) ([]*x509.Certificate, error) { - intermediateKMSSigner, err := kms.Get(ctx, intermediateKMSKey, crypto.SHA256) + parentKMSSigner, err := kms.Get(ctx, parentKMSKey, crypto.SHA256) if err != nil { return nil, err } - intermediateSigner, _, err := intermediateKMSSigner.CryptoSigner(ctx, func(_ error) {}) + parentSigner, _, err := parentKMSSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } - - pemPubKey, err := cryptoutils.MarshalPublicKeyToPEM(intermediateSigner.Public()) + parentPubKey := parentSigner.Public() + parentPEMPubKey, err := cryptoutils.MarshalPublicKeyToPEM(parentPubKey) if err != nil { return nil, err } @@ -106,68 +125,109 @@ func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leaf Value: timestampExt, }} - isCa := true - // default value of 0 for int32 - var maxIssuerPathLength int32 - - csr := &privatecapb.CreateCertificateRequest{ - Parent: parent, - Certificate: &privatecapb.Certificate{ - // Default to a very large lifetime - CA Service will truncate the - // lifetime to be no longer than the root's lifetime. - // 20 years (24 hours * 365 days * 20) - Lifetime: durationpb.New(time.Hour * 24 * 365 * 20), - CertificateConfig: &privatecapb.Certificate_Config{ - Config: &privatecapb.CertificateConfig{ - PublicKey: &privatecapb.PublicKey{ - Format: privatecapb.PublicKey_PEM, - Key: pemPubKey, - }, - X509Config: &privatecapb.X509Parameters{ - KeyUsage: &privatecapb.KeyUsage{ - BaseKeyUsage: &privatecapb.KeyUsage_KeyUsageOptions{ - CertSign: true, - CrlSign: true, - }, + var certChain []*x509.Certificate + + if root == "" { + // Create a self signed signing certificate for parentPubKey + parentSn, err := cryptoutils.GenerateSerialNumber() + if err != nil { + return nil, fmt.Errorf("generating serial number: %w", err) + } + + parentSkid, err := cryptoutils.SKID(parentPubKey) + if err != nil { + return nil, fmt.Errorf("generating SKID hash: %w", err) + } + now := time.Now() + cert := &x509.Certificate{ + SerialNumber: parentSn, + Subject: pkix.Name{ + CommonName: "sigstore-tsa-selfsigned", + Organization: []string{*orgName}, + }, + SubjectKeyId: parentSkid, + NotBefore: now, + NotAfter: now.AddDate(0, 0, *parentValidity), + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, + BasicConstraintsValid: true, + MaxPathLen: 0, + MaxPathLenZero: true, + IsCA: true, + } + parentCertDER, err := x509.CreateCertificate(rand.Reader, cert, cert, parentPubKey, parentSigner) + if err != nil { + return nil, fmt.Errorf("creating self-signed parent certificate: %w", err) + } + parentCert, err := x509.ParseCertificate(parentCertDER) + if err != nil { + return nil, fmt.Errorf("parsing leaf certificate: %w", err) + } + + certChain = append(certChain, parentCert) + + } else { + // Use CA to get an intermediate signing certificate for parentPubKey + isCa := true + // default value of 0 for int32 + var maxIssuerPathLength int32 + csr := &privatecapb.CreateCertificateRequest{ + Parent: root, + Certificate: &privatecapb.Certificate{ + // CA Service will truncate the lifetime to be no longer than the root's lifetime. + Lifetime: durationpb.New(time.Hour * 24 * time.Duration(*parentValidity)), + CertificateConfig: &privatecapb.Certificate_Config{ + Config: &privatecapb.CertificateConfig{ + PublicKey: &privatecapb.PublicKey{ + Format: privatecapb.PublicKey_PEM, + Key: parentPEMPubKey, }, - CaOptions: &privatecapb.X509Parameters_CaOptions{ - IsCa: &isCa, - MaxIssuerPathLength: &maxIssuerPathLength, + X509Config: &privatecapb.X509Parameters{ + KeyUsage: &privatecapb.KeyUsage{ + BaseKeyUsage: &privatecapb.KeyUsage_KeyUsageOptions{ + CertSign: true, + CrlSign: true, + }, + }, + CaOptions: &privatecapb.X509Parameters_CaOptions{ + IsCa: &isCa, + MaxIssuerPathLength: &maxIssuerPathLength, + }, + AdditionalExtensions: additionalExtensions, }, - AdditionalExtensions: additionalExtensions, - }, - SubjectConfig: &privatecapb.CertificateConfig_SubjectConfig{ - Subject: &privatecapb.Subject{ - CommonName: "sigstore-tsa-intermediate", - Organization: "sigstore.dev", + SubjectConfig: &privatecapb.CertificateConfig_SubjectConfig{ + Subject: &privatecapb.Subject{ + CommonName: "sigstore-tsa-intermediate", + Organization: *orgName, + }, }, }, }, }, - }, - } - - resp, err := client.CreateCertificate(ctx, csr) - if err != nil { - return nil, err - } - - var pemCerts []string - pemCerts = append(pemCerts, resp.PemCertificate) - pemCerts = append(pemCerts, resp.PemCertificateChain...) + } - var parsedCerts []*x509.Certificate - for _, c := range pemCerts { - certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(c)) + resp, err := client.CreateCertificate(ctx, csr) if err != nil { return nil, err } - if len(certs) != 1 { - return nil, errors.New("unexpected number of certificates returned") + + var pemCerts []string + pemCerts = append(pemCerts, resp.PemCertificate) + pemCerts = append(pemCerts, resp.PemCertificateChain...) + + for _, c := range pemCerts { + certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(c)) + if err != nil { + return nil, err + } + if len(certs) != 1 { + return nil, errors.New("unexpected number of certificates returned") + } + certChain = append(certChain, certs[0]) } - parsedCerts = append(parsedCerts, certs[0]) } - intermediate := parsedCerts[0] + + // parent may be intermediate or self signed root + parent := certChain[0] // generate leaf certificate var leafKMSSigner crypto.Signer @@ -195,7 +255,7 @@ func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leaf if err != nil { return nil, err } - leafKMSSigner, err = signer.KeyHandleToSigner(kh) + leafKMSSigner, err = tinkUtils.KeyHandleToSigner(kh) if err != nil { return nil, err } @@ -217,11 +277,11 @@ func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leaf SerialNumber: sn, Subject: pkix.Name{ CommonName: "sigstore-tsa", - Organization: []string{"sigstore.dev"}, + Organization: []string{*orgName}, }, SubjectKeyId: skid, - NotBefore: intermediate.NotBefore, - NotAfter: intermediate.NotAfter, + NotBefore: parent.NotBefore, + NotAfter: parent.NotAfter, IsCA: false, KeyUsage: x509.KeyUsageDigitalSignature, // set EKU to x509.ExtKeyUsageTimeStamping but with a critical bit @@ -233,7 +293,7 @@ func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leaf }, }, } - certDER, err := x509.CreateCertificate(rand.Reader, cert, intermediate, leafPubKey, intermediateSigner) + certDER, err := x509.CreateCertificate(rand.Reader, cert, parent, leafPubKey, parentSigner) if err != nil { return nil, fmt.Errorf("creating tsa certificate: %w", err) } @@ -241,19 +301,16 @@ func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leaf if err != nil { return nil, fmt.Errorf("parsing leaf certificate: %w", err) } - parsedCerts = append([]*x509.Certificate{leafCert}, parsedCerts...) + certChain = append([]*x509.Certificate{leafCert}, certChain...) - return parsedCerts, nil + return certChain, nil } func main() { flag.Parse() - if *gcpCaParent == "" { - log.Fatal("gcp-ca-parent must be set") - } - if *intermediateKMSKey == "" { - log.Fatal("intermediate-kms-resource must be set") + if *parentKMSKey == "" { + log.Fatal("parent-kms-resource must be set") } if *leafKMSKey == "" && *tinkKeysetPath == "" { log.Fatal("either leaf-kms-resource or tink-keyset-path must be set") @@ -269,7 +326,7 @@ func main() { if err != nil { log.Fatal(err) } - parsedCerts, err := fetchCertificateChain(context.Background(), *gcpCaParent, *intermediateKMSKey, *leafKMSKey, *tinkKeysetPath, *tinkKmsKey, client) + parsedCerts, err := fetchCertificateChain(context.Background(), *gcpCaRoot, *parentKMSKey, *leafKMSKey, *tinkKeysetPath, *tinkKmsKey, client) if err != nil { log.Fatal(err) } diff --git a/cmd/timestamp-cli/app/inspect.go b/cmd/timestamp-cli/app/inspect.go index b2440348e..b78a77581 100644 --- a/cmd/timestamp-cli/app/inspect.go +++ b/cmd/timestamp-cli/app/inspect.go @@ -54,7 +54,7 @@ var inspectCmd = &cobra.Command{ tsr := viper.GetString("timestamp") tsrBytes, err := os.ReadFile(filepath.Clean(tsr)) if err != nil { - return nil, fmt.Errorf("Error reading request from TSR file: %w", err) + return nil, fmt.Errorf("error reading request from TSR file: %w", err) } ts, err := timestamp.ParseResponse(tsrBytes) diff --git a/cmd/timestamp-cli/app/timestamp_test.go b/cmd/timestamp-cli/app/timestamp_test.go index 790bb0132..6be91635d 100644 --- a/cmd/timestamp-cli/app/timestamp_test.go +++ b/cmd/timestamp-cli/app/timestamp_test.go @@ -20,8 +20,13 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "go.uber.org/goleak" ) +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} + func TestTimestampFlags(t *testing.T) { type test struct { caseDesc string diff --git a/cmd/timestamp-cli/app/verify.go b/cmd/timestamp-cli/app/verify.go index 68036ce53..415e13eec 100644 --- a/cmd/timestamp-cli/app/verify.go +++ b/cmd/timestamp-cli/app/verify.go @@ -158,6 +158,7 @@ func getRootAndIntermediateCerts() ([]*x509.Certificate, []*x509.Certificate, er // 2. Called with only the --certificate-chain flag // this early exit if statement is only entered if neither of those combinations is valid + //nolint:staticcheck // code readability if !((rootPEM != "" && certChainPEM == "") || (intermediatePEM == "" && rootPEM == "" && certChainPEM != "")) { return nil, nil, fmt.Errorf("the verify command must be called with either only the --certificate-chain flag or with the --root-certificates and --intermediate-certificates flags") } diff --git a/cmd/timestamp-server/app/root.go b/cmd/timestamp-server/app/root.go index aead968b4..303fd912d 100644 --- a/cmd/timestamp-server/app/root.go +++ b/cmd/timestamp-server/app/root.go @@ -19,6 +19,7 @@ import ( "fmt" "os" + "github.com/go-chi/chi/middleware" homedir "github.com/mitchellh/go-homedir" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/spf13/cobra" @@ -60,6 +61,7 @@ func init() { rootCmd.PersistentFlags().BoolVar(&httpPingOnly, "http-ping-only", false, "serve only /ping in the http server") rootCmd.PersistentFlags().String("timestamp-signer", "memory", "Timestamping authority signer. Valid options include: [kms, tink, memory, file]. Memory and file-based signers should only be used for testing") rootCmd.PersistentFlags().String("timestamp-signer-hash", "sha256", "Hash algorithm used by the signer. Must match the hash algorithm specified for a KMS or Tink key. Valid options include: [sha256, sha384, sha512]. Ignored for Memory signer.") + rootCmd.PersistentFlags().Bool("include-chain-in-response", false, "Whether to include the issuing chain in the timestamp response when certReq is set in the timestamp request. When false, only the leaf certificate is included in the response.") // KMS flags rootCmd.PersistentFlags().String("kms-key-resource", "", "KMS key for signing timestamp responses. Valid options include: [gcpkms://resource, azurekms://resource, hashivault://resource, awskms://resource]") // Tink flags @@ -75,6 +77,8 @@ func init() { rootCmd.PersistentFlags().String("ntp-monitoring", "", "Path to a file configuring ntp monitoring. Uses pkg/ntpmonitor/ntpsync.yaml as the default configuration if none is provided") rootCmd.PersistentFlags().Bool("disable-ntp-monitoring", false, "Disables NTP monitoring. Defaults to false") + rootCmd.PersistentFlags().String("http-request-id-header-name", middleware.RequestIDHeader, "name of HTTP Request Header to use as request correlation ID") + if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { log.Logger.Fatal(err) } diff --git a/cmd/timestamp-server/app/serve.go b/cmd/timestamp-server/app/serve.go index e7b4bfbfb..7c91591b9 100644 --- a/cmd/timestamp-server/app/serve.go +++ b/cmd/timestamp-server/app/serve.go @@ -19,6 +19,7 @@ import ( "flag" "net/http" + "github.com/go-chi/chi/middleware" "github.com/spf13/cobra" "github.com/spf13/viper" "sigs.k8s.io/release-utils/version" @@ -97,6 +98,9 @@ var serveCmd = &cobra.Command{ }() } + // overrides the correlation ID printed in logs, if config is set + middleware.RequestIDHeader = viper.GetString("http-request-id-header-name") + host := viper.GetString("host") port := int(viper.GetUint("port")) scheme := viper.GetStringSlice("scheme") diff --git a/docker-compose.yml b/docker-compose.yml index 5dc599950..7e0272031 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -version: '3.8' services: timestamp-server: build: @@ -22,17 +21,17 @@ services: "timestamp-server", "serve", "--host=0.0.0.0", - "--port=3000", + "--port=3004", "--timestamp-signer=memory", # Uncomment this for production logging # "--log-type=prod", ] restart: always # keep the server running ports: - - "3000:3000" - - "2112:2112" + - "3004:3004" + - "2115:2112" healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/ping"] + test: ["CMD", "curl", "-f", "http://localhost:3004/ping"] interval: 10s timeout: 3s retries: 3 diff --git a/docs/certificate-maker.md b/docs/certificate-maker.md new file mode 100644 index 000000000..afab0faf2 --- /dev/null +++ b/docs/certificate-maker.md @@ -0,0 +1,13 @@ +# Certificate Maker + +_Note: Certificate Maker can be [found in the Fulcio repository](https://github.com/sigstore/fulcio/tree/main/cmd/certificate_maker). Please refer to its [respective documentation](https://github.com/sigstore/fulcio/blob/main/docs/certificate-maker.md) to learn more._ + +The TSA-specific certificate templates located in the `pkg/certmaker/templates` can be used with Certificate Maker. + +## Templates + +These [TSA-specific certificate templates](pkg/certmaker/templates) are specifically configured for Timestamp Authority certificates with appropriate extensions and constraints: + +- `root-template.json`: Template for root CA certificates +- `intermediate-template.json`: Template for intermediate CA certificates +- `leaf-template.json`: Template for leaf (TSA) certificates diff --git a/go.mod b/go.mod index 64b980308..4303c3f39 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/sigstore/timestamp-authority -go 1.23.0 +go 1.23.6 -toolchain go1.23.4 +toolchain go1.24.1 require ( - cloud.google.com/go/security v1.18.4 + cloud.google.com/go/security v1.18.5 github.com/beevik/ntp v1.4.3 github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 @@ -16,47 +16,50 @@ require ( github.com/go-openapi/spec v0.21.0 github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.1 - github.com/go-playground/validator/v10 v10.25.0 - github.com/golang/protobuf v1.5.4 + github.com/go-playground/validator/v10 v10.26.0 github.com/google/go-cmp v0.7.0 - github.com/google/tink/go v1.7.0 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.20.5 + github.com/prometheus/client_golang v1.22.0 github.com/rs/cors v1.11.1 - github.com/sigstore/sigstore v1.9.1 - github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1 - github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.1 - github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.1 - github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.1 + github.com/sigstore/sigstore v1.9.4 + github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.4 + github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.4 + github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.4 + github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.4 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 - github.com/spf13/viper v1.19.0 + github.com/spf13/viper v1.20.1 + github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 + github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 + github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 + github.com/tink-crypto/tink-go/v2 v2.4.0 github.com/urfave/negroni v1.0.0 - go.step.sm/crypto v0.57.0 + go.step.sm/crypto v0.66.0 + go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 - golang.org/x/net v0.37.0 + golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 - gopkg.in/yaml.v3 v3.0.1 - sigs.k8s.io/release-utils v0.8.4 + sigs.k8s.io/release-utils v0.11.1 + sigs.k8s.io/yaml v1.4.0 ) require ( cloud.google.com/go v0.120.0 // indirect - cloud.google.com/go/auth v0.15.0 // indirect + cloud.google.com/go/auth v0.16.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/iam v1.5.0 // indirect - cloud.google.com/go/kms v1.21.1 // indirect - cloud.google.com/go/longrunning v0.6.6 // indirect + cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/iam v1.5.2 // indirect + cloud.google.com/go/kms v1.22.0 // indirect + cloud.google.com/go/longrunning v0.6.7 // indirect filippo.io/edwards25519 v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.55.6 // indirect github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect @@ -79,7 +82,7 @@ require ( github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -90,12 +93,13 @@ require ( github.com/go-openapi/validate v0.24.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/google/go-containerregistry v0.20.3 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.1 // indirect + github.com/googleapis/gax-go/v2 v2.14.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -110,51 +114,47 @@ require ( github.com/jellydator/ttlcache/v3 v3.3.0 // indirect github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.11 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect - github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect - github.com/sigstore/protobuf-specs v0.4.0 // indirect + github.com/sigstore/protobuf-specs v0.4.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/trace v1.35.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect golang.org/x/time v0.11.0 // indirect - google.golang.org/api v0.227.0 // indirect - google.golang.org/genproto v0.0.0-20250409194420-de1ac958c67a // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250404141209-ee84b53bf3d0 // indirect - google.golang.org/grpc v1.71.0 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect + google.golang.org/api v0.234.0 // indirect + google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect + google.golang.org/grpc v1.72.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d36c4f738..667465cf4 100644 --- a/go.sum +++ b/go.sum @@ -1,37 +1,37 @@ cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA= cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q= -cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps= -cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= +cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/iam v1.5.0 h1:QlLcVMhbLGOjRcGe6VTGGTyQib8dRLK2B/kYNV0+2xs= -cloud.google.com/go/iam v1.5.0/go.mod h1:U+DOtKQltF/LxPEtcDLoobcsZMilSRwR7mgNL7knOpo= -cloud.google.com/go/kms v1.21.1 h1:r1Auo+jlfJSf8B7mUnVw5K0fI7jWyoUy65bV53VjKyk= -cloud.google.com/go/kms v1.21.1/go.mod h1:s0wCyByc9LjTdCjG88toVs70U9W+cc6RKFc8zAqX7nE= -cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw= -cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= -cloud.google.com/go/security v1.18.4 h1:vY/Z2D+bE9PqdZNiPpW+RLSzDNDVWkNDFKdCnqOeCis= -cloud.google.com/go/security v1.18.4/go.mod h1:+oNVB34sloqG2K3IpoT2KUDgNAbAJ9A2uENjAUvgzRQ= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= +cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk= +cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8= +cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= +cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= +cloud.google.com/go/security v1.18.5 h1:6hqzvuwC8za9jyCTxygmEHnp4vZ8hfhwKVArxSCAVCo= +cloud.google.com/go/security v1.18.5/go.mod h1:D1wuUkDwGqTKD0Nv7d4Fn2Dc53POJSmO4tlg1K1iS7s= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 h1:j8BorDEigD8UFOSZQiSqAMOOleyQOOQPnUAwV+Ls1gA= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 h1:Wgf5rZba3YZqeTNJPtvqZoBu1sBN/L4sry+u2U3Y75w= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1/go.mod h1:xxCBG/f/4Vbmh2XQJBsOmNdxWUY5j/s27jujKPbQf14= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -78,9 +78,8 @@ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= @@ -97,8 +96,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= @@ -136,28 +135,29 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= -github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI= github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= -github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= -github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= -github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= +github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -195,10 +195,10 @@ github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -209,8 +209,6 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ= github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -234,26 +232,25 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= -github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= +github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= @@ -262,52 +259,49 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc= github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw= -github.com/sigstore/protobuf-specs v0.4.0 h1:yoZbdh0kZYKOSiVbYyA8J3f2wLh5aUk2SQB7LgAfIdU= -github.com/sigstore/protobuf-specs v0.4.0/go.mod h1:FKW5NYhnnFQ/Vb9RKtQk91iYd0MKJ9AxyqInEwU6+OI= -github.com/sigstore/sigstore v1.9.1 h1:bNMsfFATsMPaagcf+uppLk4C9rQZ2dh5ysmCxQBYWaw= -github.com/sigstore/sigstore v1.9.1/go.mod h1:zUoATYzR1J3rLNp3jmp4fzIJtWdhC3ZM6MnpcBtnsE4= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1 h1:/YcNq687WnXpIRXl04nLfJX741G4iW+w+7Nem2Zy0f4= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.1/go.mod h1:ApL9RpKsi7gkSYN0bMNdm/3jZ9EefxMmfYHfUmq2ZYM= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.1 h1:FnusXyTIInnwfIOzzl5PFilRm1I97dxMSOcCkZBu9Kc= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.1/go.mod h1:d5m5LOa/69a+t2YC9pDPwS1n2i/PhqB4cUKbpVDlKKE= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.1 h1:LFiYK1DEWQ6Hf/nroFzBMM+s5rVSjVL45Alpb5Ctl5A= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.1/go.mod h1:GFyFmDsE2wDuIHZD+4+JErGpA0S4zJsKNz5l2JVJd8s= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.1 h1:sIW6xe4yU5eIMH8fve2C78d+r29KmHnIb+7po+80bsY= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.1/go.mod h1:3pNf99GnK9eu3XUa5ebHzgEQSVYf9hqAoPFwbwD6O6M= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= +github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby1BxGU7Zc= +github.com/sigstore/protobuf-specs v0.4.1/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= +github.com/sigstore/sigstore v1.9.4 h1:64+OGed80+A4mRlNzRd055vFcgBeDghjZw24rPLZgDU= +github.com/sigstore/sigstore v1.9.4/go.mod h1:Q7tGTC3gbtK7c3jcxEmGc2MmK4rRpIRzi3bxRFWKvEY= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.4 h1:kQqUJ1VuWdJltMkinFXAHTlJrzMRPoNgL+dy6WyJ/dA= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.4/go.mod h1:9miLz7c69vj/7VH7UpCKHDia41HCTIDJWJWf4Ex5yUk= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.4 h1:MHRm7YQuF4zFyoXRLgUdLaNxqVO6JlLGnkDUI9fm9ow= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.4/go.mod h1:899VNYSSnQ0QtcuhkW0gznzxn0cqhowTL3nzc/xnym8= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.4 h1:C2nSyTmTxpuamUmLCWWZwz+0Y1IQIig9XwAJ4UAn/SI= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.4/go.mod h1:vjDahU0sEw/WMkKkygZNH72EMg86iaFNLAaJFXhItXU= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.4 h1:t9yfb6yteIDv8CNRT6OHdqgTV6TSj+CdOtZP9dVhpsQ= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.4/go.mod h1:m7sQxVJmDa+rsmS1m6biQxaLX83pzNS7ThUEyjOqkCU= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= +github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= +github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= +github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= +github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 h1:6nAX1aRGnkg2SEUMwO5toB2tQkP0Jd6cbmZ/K5Le1V0= +github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0/go.mod h1:HOC5NWW1wBI2Vke1FGcRBvDATkEYE7AUDiYbXqi2sBw= +github.com/tink-crypto/tink-go/v2 v2.4.0 h1:8VPZeZI4EeZ8P/vB6SIkhlStrJfivTJn+cQ4dtyHNh0= +github.com/tink-crypto/tink-go/v2 v2.4.0/go.mod h1:l//evrF2Y3MjdbpNDNGnKgCpo5zSmvUvnQ4MU+yE2sw= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= @@ -316,70 +310,68 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.step.sm/crypto v0.57.0 h1:YjoRQDaJYAxHLVwjst0Bl0xcnoKzVwuHCJtEo2VSHYU= -go.step.sm/crypto v0.57.0/go.mod h1:+Lwp5gOVPaTa3H/Ul/TzGbxQPXZZcKIUGMS0lG6n9Go= +go.step.sm/crypto v0.66.0 h1:9TW6BEguOtcS9NIjja9bDQ+j8OjhenU/F6lJfHjbXNU= +go.step.sm/crypto v0.66.0/go.mod h1:anqGyvO/Px05D1mznHq4/a9wwP1I1DmMZvk+TWX5Dzo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= -google.golang.org/api v0.227.0 h1:QvIHF9IuyG6d6ReE+BNd11kIB8hZvjN8Z5xY5t21zYc= -google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ= -google.golang.org/genproto v0.0.0-20250409194420-de1ac958c67a h1:AoyioNVZR+nS6zbvnvW5rjQdeQu7/BWwIT7YI8Gq5wU= -google.golang.org/genproto v0.0.0-20250409194420-de1ac958c67a/go.mod h1:qD4k1RhYfNmRjqaHJxKLG/HRtqbXVclhjop2mPlxGwA= -google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a h1:OQ7sHVzkx6L57dQpzUS4ckfWJ51KDH74XHTDe23xWAs= -google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a/go.mod h1:2R6XrVC8Oc08GlNh8ujEpc7HkLiEZ16QeY7FxIs20ac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250404141209-ee84b53bf3d0 h1:0K7wTWyzxZ7J+L47+LbFogJW1nn/gnnMCN0vGXNYtTI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250404141209-ee84b53bf3d0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/api v0.234.0 h1:d3sAmYq3E9gdr2mpmiWGbm9pHsA/KJmyiLkwKfHBqU4= +google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= +google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0= +google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -sigs.k8s.io/release-utils v0.8.4 h1:4QVr3UgbyY/d9p74LBhg0njSVQofUsAZqYOzVZBhdBw= -sigs.k8s.io/release-utils v0.8.4/go.mod h1:m1bHfscTemQp+z+pLCZnkXih9n0+WukIUU70n6nFnU0= +sigs.k8s.io/release-utils v0.11.1 h1:hzvXGpHgHJfLOJB6TRuu14bzWc3XEglHmXHJqwClSZE= +sigs.k8s.io/release-utils v0.11.1/go.mod h1:ybR2V/uQAOGxYfzYtBenSYeXWkBGNP2qnEiX77ACtpc= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/tools/go.mod b/hack/tools/go.mod index 5eaf5aa60..aad1bec7a 100644 --- a/hack/tools/go.mod +++ b/hack/tools/go.mod @@ -1,8 +1,8 @@ module github.com/sigstore/timestamp-authority/hack/tools -go 1.23.0 +go 1.23.6 -toolchain go1.23.4 +toolchain go1.24.1 require github.com/go-swagger/go-swagger v0.31.0 @@ -53,13 +53,13 @@ require ( github.com/toqueteos/webbrowser v1.2.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/mod v0.24.0 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.32.0 // indirect + golang.org/x/crypto v0.35.0 // indirect + golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/tools v0.29.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/hack/tools/go.sum b/hack/tools/go.sum index bef0998d6..f62d55259 100644 --- a/hack/tools/go.sum +++ b/hack/tools/go.sum @@ -130,21 +130,21 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -152,8 +152,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -161,13 +161,13 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/pkg/api/api.go b/pkg/api/api.go index 817463cec..6d5d92978 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -38,6 +38,7 @@ type API struct { tsaSignerHash crypto.Hash // hash algorithm used to hash pre-signed timestamps certChain []*x509.Certificate // timestamping cert chain certChainPem string // PEM encoded timestamping cert chain + includeChain bool // Whether to include the full issuing chain or just the leaf certificate } func NewAPI() (*API, error) { @@ -91,6 +92,7 @@ func NewAPI() (*API, error) { tsaSignerHash: tsaSignerHash, certChain: certChain, certChainPem: string(certChainPEM), + includeChain: viper.GetBool("include-chain-in-response"), }, nil } diff --git a/pkg/api/error.go b/pkg/api/error.go index 5786a96dd..f9ec27403 100644 --- a/pkg/api/error.go +++ b/pkg/api/error.go @@ -28,8 +28,9 @@ import ( ) const ( - failedToGenerateTimestampResponse = "Error generating timestamp response" - WeakHashAlgorithmTimestampRequest = "Weak hash algorithm in timestamp request" + failedToGenerateTimestampResponse = "Error generating timestamp response" + WeakHashAlgorithmTimestampRequest = "Weak hash algorithm in timestamp request" + InconsistentDigestLengthTimestampRequest = "Message digest has incorrect length for specified algorithm" ) func errorMsg(message string, code int) *models.Error { diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go index 741ccd169..a82571935 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -16,6 +16,7 @@ package api import ( + "math" "time" "github.com/prometheus/client_golang/prometheus" @@ -63,6 +64,28 @@ var ( Help: "Total number of NTP related errors", }, []string{"reason"}) + _ = promauto.NewGaugeFunc( + prometheus.GaugeOpts{ + Name: "timestamp_authority_certificate_valid_days_remaining", + Help: "Number of days remaining in validity period of signing certificate", + }, + func() float64 { + // if api hasn't been initialized yet, then we can't know the validity period; + // so we return MaxFloat64 to not cause an alarm if someone fetches the metric + // before the initialization has completed + if api == nil { + return math.MaxFloat64 + } + // compute minimum validity inclusive of leaf, any intermediates (if present), and root + minValidity := api.certChain[0].NotAfter + for _, cert := range api.certChain[1:] { + if cert.NotAfter.Before(minValidity) { + minValidity = cert.NotAfter + } + } + return time.Until(minValidity).Hours() / 24 + }) + _ = promauto.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: "timestamp_authority", diff --git a/pkg/api/timestamp.go b/pkg/api/timestamp.go index 2dc911f4f..2e8192d0a 100644 --- a/pkg/api/timestamp.go +++ b/pkg/api/timestamp.go @@ -99,7 +99,7 @@ func ParseJSONRequest(reqBytes []byte) (*timestamp.Request, string, error) { TSAPolicyOID: oidInts, } - return &tsReq, "", nil + return verifyTimestampRequest(&tsReq) } func parseDERRequest(reqBytes []byte) (*timestamp.Request, string, error) { @@ -108,12 +108,7 @@ func parseDERRequest(reqBytes []byte) (*timestamp.Request, string, error) { return nil, failedToGenerateTimestampResponse, err } - // verify that the request's hash algorithm is supported - if err := verification.VerifyRequest(parsed); err != nil { - return nil, WeakHashAlgorithmTimestampRequest, err - } - - return parsed, "", nil + return verifyTimestampRequest(parsed) } func getContentType(r *http.Request) (string, error) { @@ -176,6 +171,9 @@ func TimestampResponseHandler(params ts.GetTimestampResponseParams) middleware.R AddTSACertificate: req.Certificates, ExtraExtensions: req.Extensions, } + if api.includeChain { + tsStruct.Certificates = api.certChain[1:] // Issuing CA certificate down to root + } resp, err := tsStruct.CreateResponseWithOpts(api.certChain[0], api.tsaSigner, api.tsaSignerHash) if err != nil { @@ -188,3 +186,23 @@ func TimestampResponseHandler(params ts.GetTimestampResponseParams) middleware.R func GetTimestampCertChainHandler(_ ts.GetTimestampCertChainParams) middleware.Responder { return ts.NewGetTimestampCertChainOK().WithPayload(api.certChainPem) } + +func verifyTimestampRequest(tsReq *timestamp.Request) (*timestamp.Request, string, error) { + if err := verification.VerifyRequest(tsReq); err != nil { + // verify that the request's hash algorithm is not weak + if errors.Is(err, verification.ErrWeakHashAlg) { + return nil, WeakHashAlgorithmTimestampRequest, err + } + // verify that the request's hash algorithm is supported + if errors.Is(err, verification.ErrUnsupportedHashAlg) { + return nil, failedToGenerateTimestampResponse, err + } + // verify that the request's digest length is consistent with the request's hash algorithm + if errors.Is(err, verification.ErrInconsistentDigestLength) { + return nil, InconsistentDigestLengthTimestampRequest, err + } + return nil, failedToGenerateTimestampResponse, err + } + + return tsReq, "", nil +} diff --git a/pkg/api/timestamp_test.go b/pkg/api/timestamp_test.go new file mode 100644 index 000000000..17cf6ee8c --- /dev/null +++ b/pkg/api/timestamp_test.go @@ -0,0 +1,29 @@ +// Copyright 2025 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package api + +import "testing" + +func FuzzParseJSONRequest(f *testing.F) { + f.Fuzz(func(_ *testing.T, reqBytes []byte) { + _, _, _ = ParseJSONRequest(reqBytes) + }) +} + +func FuzzParseDERRequest(f *testing.F) { + f.Fuzz(func(_ *testing.T, reqBytes []byte) { + _, _, _ = parseDERRequest(reqBytes) + }) +} diff --git a/pkg/certmaker/templates/intermediate-template.json b/pkg/certmaker/templates/intermediate-template.json new file mode 100644 index 000000000..a8519de46 --- /dev/null +++ b/pkg/certmaker/templates/intermediate-template.json @@ -0,0 +1,22 @@ +{ + "subject": { + "country": [ + "" + ], + "organization": [ + "" + ], + "organizationalUnit": [ + "" + ], + "commonName": "{{ .Subject.CommonName }}" + }, + "keyUsage": [ + "certSign", + "crlSign" + ], + "basicConstraints": { + "isCA": true, + "maxPathLen": 0 + } +} \ No newline at end of file diff --git a/pkg/certmaker/templates/leaf-template.json b/pkg/certmaker/templates/leaf-template.json new file mode 100644 index 000000000..c1d0b6aab --- /dev/null +++ b/pkg/certmaker/templates/leaf-template.json @@ -0,0 +1,27 @@ +{ + "subject": { + "country": [ + "" + ], + "organization": [ + "" + ], + "organizationalUnit": [ + "" + ], + "commonName": "{{ .Subject.CommonName }}" + }, + "keyUsage": [ + "digitalSignature" + ], + "extensions": [ + { + "id": "2.5.29.37", + "critical": true, + "value": {{ asn1Seq (asn1Enc "oid:1.3.6.1.5.5.7.3.8") | toJson }} + } + ], + "basicConstraints": { + "isCA": false + } +} \ No newline at end of file diff --git a/pkg/certmaker/templates/root-template.json b/pkg/certmaker/templates/root-template.json new file mode 100644 index 000000000..218ef32a3 --- /dev/null +++ b/pkg/certmaker/templates/root-template.json @@ -0,0 +1,22 @@ +{ + "subject": { + "country": [ + "" + ], + "organization": [ + "" + ], + "organizationalUnit": [ + "" + ], + "commonName": "{{ .Subject.CommonName }}" + }, + "basicConstraints": { + "isCA": true, + "maxPathLen": 1 + }, + "keyUsage": [ + "certSign", + "crlSign" + ] +} \ No newline at end of file diff --git a/pkg/client/timestamp_client_test.go b/pkg/client/timestamp_client_test.go index e572cceea..d149b9abd 100644 --- a/pkg/client/timestamp_client_test.go +++ b/pkg/client/timestamp_client_test.go @@ -37,9 +37,10 @@ func TestGetTimestampClientWithOptions(t *testing.T) { } var expectedAccept string - if r.URL.Path == "/api/v1/timestamp/certchain" { + switch r.URL.Path { + case "/api/v1/timestamp/certchain": expectedAccept = "application/pem-certificate-chain" - } else if r.URL.Path == "/api/v1/timestamp" { + case "/api/v1/timestamp": expectedAccept = "application/timestamp-reply" } diff --git a/pkg/generated/restapi/configure_timestamp_server.go b/pkg/generated/restapi/configure_timestamp_server.go index c602b8126..8618dcf7e 100644 --- a/pkg/generated/restapi/configure_timestamp_server.go +++ b/pkg/generated/restapi/configure_timestamp_server.go @@ -110,7 +110,7 @@ const pingPath = "/ping" func httpPingOnly() func(http.Handler) http.Handler { f := func(h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { - if r.URL.Scheme != "https" && !strings.EqualFold(r.URL.Path, pingPath) { + if r.TLS == nil && !strings.EqualFold(r.URL.Path, pingPath) { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusNotFound) w.Write([]byte("http server supports only the " + pingPath + " entrypoint")) //nolint:errcheck diff --git a/pkg/ntpmonitor/config.go b/pkg/ntpmonitor/config.go index 9794b21d2..c5742ad10 100644 --- a/pkg/ntpmonitor/config.go +++ b/pkg/ntpmonitor/config.go @@ -21,7 +21,7 @@ import ( "fmt" "os" - "gopkg.in/yaml.v3" + "sigs.k8s.io/yaml" ) //go:embed ntpsync.yaml @@ -29,13 +29,13 @@ var defaultConfigData []byte // Config holds the configuration for a NTPMonitor type Config struct { - RequestAttempts int `yaml:"request_attempts"` - RequestTimeout int `yaml:"request_timeout"` - NumServers int `yaml:"num_servers"` - MaxTimeDelta int `yaml:"max_time_delta"` - ServerThreshold int `yaml:"server_threshold"` - Period int `yaml:"period"` - Servers []string `yaml:"servers"` + RequestAttempts int `json:"request_attempts"` + RequestTimeout int `json:"request_timeout"` + NumServers int `json:"num_servers"` + MaxTimeDelta int `json:"max_time_delta"` + ServerThreshold int `json:"server_threshold"` + Period int `json:"period"` + Servers []string `json:"servers"` } // LoadConfig reads a yaml file from a provided path, instantiating a new diff --git a/pkg/ntpmonitor/config_test.go b/pkg/ntpmonitor/config_test.go index c30abb1a3..95fc6badb 100644 --- a/pkg/ntpmonitor/config_test.go +++ b/pkg/ntpmonitor/config_test.go @@ -20,7 +20,7 @@ import ( "path" "testing" - "gopkg.in/yaml.v3" + "sigs.k8s.io/yaml" ) var yamlData = ` diff --git a/pkg/signer/signer.go b/pkg/signer/signer.go index ee79d53d4..52af01245 100644 --- a/pkg/signer/signer.go +++ b/pkg/signer/signer.go @@ -56,7 +56,7 @@ func NewCryptoSigner(ctx context.Context, hash crypto.Hash, signer, kmsKey, tink if err != nil { return nil, err } - return NewTinkSigner(ctx, tinkKeysetPath, primaryKey) + return NewTinkSigner(tinkKeysetPath, primaryKey) default: return nil, fmt.Errorf("unsupported signer type: %s", signer) } diff --git a/pkg/signer/tink.go b/pkg/signer/tink.go index affb65562..a8f65fcca 100644 --- a/pkg/signer/tink.go +++ b/pkg/signer/tink.go @@ -17,41 +17,22 @@ package signer import ( "context" "crypto" - "crypto/ecdsa" - "crypto/ed25519" "errors" - "fmt" - "math/big" "os" "path/filepath" "strings" - "github.com/google/tink/go/core/registry" - "github.com/google/tink/go/integration/awskms" - "github.com/google/tink/go/integration/gcpkms" - "github.com/google/tink/go/integration/hcvault" - signatureSubtle "github.com/google/tink/go/signature/subtle" - "github.com/google/tink/go/subtle" - "github.com/google/tink/go/tink" - - "github.com/golang/protobuf/proto" //lint:ignore SA1019 needed for unmarshalling - "github.com/google/tink/go/insecurecleartextkeyset" - "github.com/google/tink/go/keyset" - commonpb "github.com/google/tink/go/proto/common_go_proto" - ecdsapb "github.com/google/tink/go/proto/ecdsa_go_proto" - ed25519pb "github.com/google/tink/go/proto/ed25519_go_proto" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" -) - -var ( - ecdsaSignerKeyVersion = 0 - ecdsaSignerTypeURL = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey" - ed25519SignerKeyVersion = 0 - ed25519SignerTypeURL = "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey" + tinkUtils "github.com/sigstore/sigstore/pkg/signature/tink" + "github.com/tink-crypto/tink-go-awskms/v2/integration/awskms" + "github.com/tink-crypto/tink-go-gcpkms/v2/integration/gcpkms" + "github.com/tink-crypto/tink-go-hcvault/v2/integration/hcvault" + "github.com/tink-crypto/tink-go/v2/core/registry" + "github.com/tink-crypto/tink-go/v2/keyset" + "github.com/tink-crypto/tink-go/v2/tink" ) // NewTinkSigner creates a signer by decrypting a local Tink keyset with a remote KMS encryption key -func NewTinkSigner(_ context.Context, tinkKeysetPath string, primaryKey tink.AEAD) (crypto.Signer, error) { +func NewTinkSigner(tinkKeysetPath string, primaryKey tink.AEAD) (crypto.Signer, error) { f, err := os.Open(filepath.Clean(tinkKeysetPath)) if err != nil { return nil, err @@ -62,7 +43,7 @@ func NewTinkSigner(_ context.Context, tinkKeysetPath string, primaryKey tink.AEA if err != nil { return nil, err } - signer, err := KeyHandleToSigner(kh) + signer, err := tinkUtils.KeyHandleToSigner(kh) if err != nil { return nil, err } @@ -81,7 +62,7 @@ func GetPrimaryKey(ctx context.Context, kmsKey, hcVaultToken string) (tink.AEAD, registry.RegisterKMSClient(gcpClient) return gcpClient.GetAEAD(kmsKey) case strings.HasPrefix(kmsKey, "aws-kms://"): - awsClient, err := awskms.NewClient(kmsKey) + awsClient, err := awskms.NewClientWithOptions(kmsKey) if err != nil { return nil, err } @@ -98,91 +79,3 @@ func GetPrimaryKey(ctx context.Context, kmsKey, hcVaultToken string) (tink.AEAD, return nil, errors.New("unsupported Tink KMS key type") } } - -// KeyHandleToSigner converts a key handle to the crypto.Signer interface. -// Heavily pulls from Tink's signature and subtle packages. -func KeyHandleToSigner(kh *keyset.Handle) (crypto.Signer, error) { - // extract the key material from the key handle - ks := insecurecleartextkeyset.KeysetMaterial(kh) - - k := getPrimaryKey(ks) - if k == nil { - return nil, errors.New("no enabled key found in keyset") - } - - switch k.GetTypeUrl() { - case ecdsaSignerTypeURL: - // https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ecdsa_signer_key_manager.go#L48 - privKey := new(ecdsapb.EcdsaPrivateKey) - if err := proto.Unmarshal(k.GetValue(), privKey); err != nil { - return nil, fmt.Errorf("error unmarshalling ecdsa private key: %w", err) - } - if err := validateEcdsaPrivKey(privKey); err != nil { - return nil, fmt.Errorf("error validating ecdsa private key: %w", err) - } - // https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/subtle/ecdsa_signer.go#L39 - _, curve, _ := getECDSAParamNames(privKey.PublicKey.Params) - p := new(ecdsa.PrivateKey) - c := subtle.GetCurve(curve) - p.PublicKey.Curve = c - p.D = new(big.Int).SetBytes(privKey.GetKeyValue()) - p.PublicKey.X, p.PublicKey.Y = c.ScalarBaseMult(privKey.GetKeyValue()) - return p, nil - case ed25519SignerTypeURL: - // https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ed25519_signer_key_manager.go#L47 - privKey := new(ed25519pb.Ed25519PrivateKey) - if err := proto.Unmarshal(k.GetValue(), privKey); err != nil { - return nil, fmt.Errorf("error unmarshalling ed25519 private key: %w", err) - } - if err := validateEd25519PrivKey(privKey); err != nil { - return nil, fmt.Errorf("error validating ed25519 private key: %w", err) - } - // https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/subtle/ed25519_signer.go#L29 - p := ed25519.NewKeyFromSeed(privKey.GetKeyValue()) - return p, nil - default: - return nil, fmt.Errorf("unsupported key type: %s", k.GetTypeUrl()) - } -} - -// getPrimaryKey returns the first enabled key from a keyset. -func getPrimaryKey(ks *tinkpb.Keyset) *tinkpb.KeyData { - for _, k := range ks.GetKey() { - if k.GetKeyId() == ks.GetPrimaryKeyId() && k.GetStatus() == tinkpb.KeyStatusType_ENABLED { - return k.GetKeyData() - } - } - return nil -} - -// validateEcdsaPrivKey validates the given ECDSAPrivateKey. -// https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ecdsa_signer_key_manager.go#L139 -func validateEcdsaPrivKey(key *ecdsapb.EcdsaPrivateKey) error { - if err := keyset.ValidateKeyVersion(key.Version, uint32(ecdsaSignerKeyVersion)); err != nil { //nolint:gosec - return fmt.Errorf("ecdsa_signer_key_manager: invalid key: %w", err) - } - hash, curve, encoding := getECDSAParamNames(key.PublicKey.Params) - return signatureSubtle.ValidateECDSAParams(hash, curve, encoding) -} - -// getECDSAParamNames returns the string representations of each parameter in -// the given ECDSAParams. -// https://github.com/google/tink/blob/4cc630dfc711555f6bbbad64f8c573b39b7af500/go/signature/proto.go#L26 -func getECDSAParamNames(params *ecdsapb.EcdsaParams) (string, string, string) { - hashName := commonpb.HashType_name[int32(params.HashType)] - curveName := commonpb.EllipticCurveType_name[int32(params.Curve)] - encodingName := ecdsapb.EcdsaSignatureEncoding_name[int32(params.Encoding)] - return hashName, curveName, encodingName -} - -// validateEd25519PrivKey validates the given ED25519PrivateKey. -// https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ed25519_signer_key_manager.go#L132 -func validateEd25519PrivKey(key *ed25519pb.Ed25519PrivateKey) error { - if err := keyset.ValidateKeyVersion(key.Version, uint32(ed25519SignerKeyVersion)); err != nil { //nolint:gosec - return fmt.Errorf("ed25519_signer_key_manager: invalid key: %w", err) - } - if len(key.KeyValue) != ed25519.SeedSize { - return fmt.Errorf("ed2219_signer_key_manager: invalid key length, got %d", len(key.KeyValue)) - } - return nil -} diff --git a/pkg/signer/tink_test.go b/pkg/signer/tink_test.go index d08338c58..9a8e027d9 100644 --- a/pkg/signer/tink_test.go +++ b/pkg/signer/tink_test.go @@ -15,31 +15,18 @@ package signer import ( - "context" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/rand" - "crypto/sha256" - "crypto/sha512" - "hash" "os" "path/filepath" "strings" "testing" - "github.com/google/tink/go/aead" "github.com/sigstore/sigstore/pkg/cryptoutils" - - "github.com/google/tink/go/keyset" - "github.com/google/tink/go/proto/tink_go_proto" - "github.com/google/tink/go/signature" + tinkUtils "github.com/sigstore/sigstore/pkg/signature/tink" + "github.com/tink-crypto/tink-go/v2/aead" + "github.com/tink-crypto/tink-go/v2/keyset" + "github.com/tink-crypto/tink-go/v2/signature" ) -type TestStruct struct { - keyTemplate *tink_go_proto.KeyTemplate - h hash.Hash -} - func TestNewTinkSigner(t *testing.T) { aeskh, err := keyset.NewHandle(aead.AES256GCMKeyTemplate()) if err != nil { @@ -53,7 +40,7 @@ func TestNewTinkSigner(t *testing.T) { if err != nil { t.Fatalf("error creating ECDSA key handle: %v", err) } - khsigner, err := KeyHandleToSigner(kh) + khsigner, err := tinkUtils.KeyHandleToSigner(kh) if err != nil { t.Fatalf("error converting ECDSA key handle to signer: %v", err) } @@ -70,7 +57,7 @@ func TestNewTinkSigner(t *testing.T) { t.Fatalf("error writing enc keyset: %v", err) } - signer, err := NewTinkSigner(context.TODO(), keysetPath, a) + signer, err := NewTinkSigner(keysetPath, a) if err != nil { t.Fatalf("unexpected error creating Tink signer: %v", err) } @@ -89,112 +76,8 @@ func TestNewTinkSigner(t *testing.T) { if err != nil { t.Fatalf("error creating AEAD key: %v", err) } - _, err = NewTinkSigner(context.TODO(), keysetPath, a1) + _, err = NewTinkSigner(keysetPath, a1) if err == nil || !strings.Contains(err.Error(), "decryption failed") { t.Fatalf("expected error decrypting keyset, got %v", err) } } - -func TestKeyHandleToSignerECDSA(t *testing.T) { - supportedKeyTypes := []TestStruct{ - { - keyTemplate: signature.ECDSAP256KeyWithoutPrefixTemplate(), - h: sha256.New(), - }, - { - keyTemplate: signature.ECDSAP384KeyWithoutPrefixTemplate(), - h: sha512.New(), - }, - { - keyTemplate: signature.ECDSAP521KeyWithoutPrefixTemplate(), - h: sha512.New(), - }, - } - for _, kt := range supportedKeyTypes { - kh, err := keyset.NewHandle(kt.keyTemplate) - if err != nil { - t.Fatalf("error creating ECDSA key handle: %v", err) - } - // convert to crypto.Signer interface - signer, err := KeyHandleToSigner(kh) - if err != nil { - t.Fatalf("error converting ECDSA key handle to signer: %v", err) - } - msg := []byte("hello there") - - // sign with key handle, verify with signer public key - tinkSigner, err := signature.NewSigner(kh) - if err != nil { - t.Fatalf("error creating tink signer: %v", err) - } - sig, err := tinkSigner.Sign(msg) - if err != nil { - t.Fatalf("error signing with tink signer: %v", err) - } - kt.h.Write(msg) - digest := kt.h.Sum(nil) - if !ecdsa.VerifyASN1(signer.Public().(*ecdsa.PublicKey), digest, sig) { - t.Fatalf("signature from tink signer did not match") - } - - // sign with signer, verify with key handle - sig, err = ecdsa.SignASN1(rand.Reader, signer.(*ecdsa.PrivateKey), digest) - if err != nil { - t.Fatalf("error signing with crypto signer: %v", err) - } - pubkh, err := kh.Public() - if err != nil { - t.Fatalf("error fetching public key handle: %v", err) - } - v, err := signature.NewVerifier(pubkh) - if err != nil { - t.Fatalf("error creating tink verifier: %v", err) - } - if err := v.Verify(sig, msg); err != nil { - t.Fatalf("error verifying with tink verifier: %v", err) - } - } -} - -func TestKeyHandleToSignerED25519(t *testing.T) { - kh, err := keyset.NewHandle(signature.ED25519KeyWithoutPrefixTemplate()) - if err != nil { - t.Fatalf("error creating ED25519 key handle: %v", err) - } - // convert to crypto.Signer interface - signer, err := KeyHandleToSigner(kh) - if err != nil { - t.Fatalf("error converting ED25519 key handle to signer: %v", err) - } - msg := []byte("hello there") - - // sign with key handle, verify with signer public key - tinkSigner, err := signature.NewSigner(kh) - if err != nil { - t.Fatalf("error creating tink signer: %v", err) - } - sig, err := tinkSigner.Sign(msg) - if err != nil { - t.Fatalf("error signing with tink signer: %v", err) - } - if !ed25519.Verify(signer.Public().(ed25519.PublicKey), msg, sig) { - t.Fatalf("signature from tink signer did not match") - } - - // sign with signer, verify with key handle - sig = ed25519.Sign(signer.(ed25519.PrivateKey), msg) - if err != nil { - t.Fatalf("error signing with crypto signer: %v", err) - } - pubkh, err := kh.Public() - if err != nil { - t.Fatalf("error fetching public key handle: %v", err) - } - v, err := signature.NewVerifier(pubkh) - if err != nil { - t.Fatalf("error creating tink verifier: %v", err) - } - if err := v.Verify(sig, msg); err != nil { - t.Fatalf("error verifying with tink verifier: %v", err) - } -} diff --git a/pkg/tests/api_test.go b/pkg/tests/api_test.go index 0de40e120..670251a8a 100644 --- a/pkg/tests/api_test.go +++ b/pkg/tests/api_test.go @@ -33,10 +33,16 @@ import ( "github.com/sigstore/timestamp-authority/pkg/client" "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp" "github.com/sigstore/timestamp-authority/pkg/x509" + "github.com/spf13/viper" "github.com/go-openapi/runtime" + "go.uber.org/goleak" ) +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} + // TestSigner encapsulates a public key for verification type TestSigner struct { pubKey crypto.PublicKey @@ -83,6 +89,7 @@ type timestampTestCase struct { includeCerts bool policyOID asn1.ObjectIdentifier hash crypto.Hash + issuingChain bool } func TestGetTimestampResponse(t *testing.T) { @@ -107,6 +114,15 @@ func TestGetTimestampResponse(t *testing.T) { includeCerts: includeCerts, hash: hashFunc, }, + { + name: "Request with Full Issuing Chain", + reqMediaType: client.TimestampQueryMediaType, + reqBytes: buildTimestampQueryReq(t, []byte(testArtifact), opts), + nonce: testNonce, + includeCerts: includeCerts, + hash: hashFunc, + issuingChain: true, + }, { name: "JSON Request", reqMediaType: client.JSONMediaType, @@ -118,7 +134,12 @@ func TestGetTimestampResponse(t *testing.T) { } for _, tc := range tests { - url := createServer(t) + var url string + if !tc.issuingChain { + url = createServer(t, func() { viper.Set("include-chain-in-response", false) }) + } else { + url = createServer(t, func() { viper.Set("include-chain-in-response", true) }) + } c, err := client.GetTimestampClient(url, client.WithContentType(tc.reqMediaType)) if err != nil { @@ -144,12 +165,30 @@ func TestGetTimestampResponse(t *testing.T) { } // check certificate fields - if len(tsr.Certificates) != 1 { - t.Fatalf("test '%s': expected 1 certificate, got %d", tc.name, len(tsr.Certificates)) - } if !tsr.AddTSACertificate { t.Fatalf("test '%s': expected TSA certificate", tc.name) } + if !tc.issuingChain { + if len(tsr.Certificates) != 1 { + t.Fatalf("test '%s': expected 1 certificate, got %d", tc.name, len(tsr.Certificates)) + } + if tsr.Certificates[0].Subject.CommonName != "Test TSA Timestamping" { + t.Fatalf("test '%s': expected subject to be 'Test TSA Timestamping', got %s", tc.name, tsr.Certificates[0].Subject.CommonName) + } + } else { + if len(tsr.Certificates) != 3 { + t.Fatalf("test '%s': expected 3 certificates, got %d", tc.name, len(tsr.Certificates)) + } + if tsr.Certificates[0].Subject.CommonName != "Test TSA Timestamping" { + t.Fatalf("test '%s': expected subject to be 'Test TSA Timestamping', got %s", tc.name, tsr.Certificates[0].Subject.CommonName) + } + if tsr.Certificates[1].Subject.CommonName != "Test TSA Intermediate" { + t.Fatalf("test '%s': expected subject to be 'Test TSA Intermediate', got %s", tc.name, tsr.Certificates[1].Subject.CommonName) + } + if tsr.Certificates[2].Subject.CommonName != "Test TSA Root" { + t.Fatalf("test '%s': expected subject to be 'Test TSA Root', got %s", tc.name, tsr.Certificates[2].Subject.CommonName) + } + } // check nonce if tsr.Nonce.Cmp(tc.nonce) != 0 { t.Fatalf("test '%s': expected nonce %d, got %d", tc.name, tc.nonce, tsr.Nonce) diff --git a/pkg/tests/server.go b/pkg/tests/server.go index e5ccf6a2b..35c1e6959 100644 --- a/pkg/tests/server.go +++ b/pkg/tests/server.go @@ -26,9 +26,12 @@ import ( "github.com/sigstore/timestamp-authority/pkg/server" ) -func createServer(t *testing.T) string { +func createServer(t *testing.T, flagsToSet ...func()) string { viper.Set("timestamp-signer", "memory") viper.Set("timestamp-signer-hash", "sha256") + for _, flag := range flagsToSet { + flag() + } // unused port apiServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second) server := httptest.NewServer(apiServer.GetHandler()) @@ -39,6 +42,7 @@ func createServer(t *testing.T) string { if err != nil || response.StatusCode != 200 { t.Fatalf("unexpected error starting up server - status code: %d, err: %v", response.StatusCode, err) } + defer response.Body.Close() return server.URL } diff --git a/pkg/verification/verify.go b/pkg/verification/verify.go index 82bebdd2f..5a80375db 100644 --- a/pkg/verification/verify.go +++ b/pkg/verification/verify.go @@ -113,7 +113,15 @@ func verifyLeafCert(ts timestamp.Timestamp, opts VerifyOpts) error { var leafCert *x509.Certificate if len(ts.Certificates) != 0 { - leafCert = ts.Certificates[0] + for _, c := range ts.Certificates { + if !c.IsCA { + leafCert = c + break + } + } + if leafCert == nil { + return fmt.Errorf("no leaf certificate found in chain") + } err := verifyEmbeddedLeafCert(leafCert, opts) if err != nil { @@ -148,7 +156,7 @@ func verifyLeafCert(ts timestamp.Timestamp, opts VerifyOpts) error { return nil } -func verifyExtendedKeyUsage(cert *x509.Certificate) error { +func verifyLeafExtendedKeyUsage(cert *x509.Certificate) error { certEKULen := len(cert.ExtKeyUsage) if certEKULen != 1 { return fmt.Errorf("certificate has %d extended key usages, expected only one", certEKULen) @@ -160,16 +168,40 @@ func verifyExtendedKeyUsage(cert *x509.Certificate) error { return nil } +func verifyIntermediateExtendedKeyUsage(cert *x509.Certificate) error { + // If no EKU specified it means unrestricted usage + if len(cert.ExtKeyUsage) == 0 { + return nil + } + + allowsTimestampingUse := false + for _, eku := range cert.ExtKeyUsage { + if eku == x509.ExtKeyUsageTimeStamping || eku == x509.ExtKeyUsageAny { + allowsTimestampingUse = true + break + } + } + + if !allowsTimestampingUse { + return errors.New("intermediate certificate does not allow Timestamping usage") + } + + return nil +} + // Verify the leaf and intermediate certificates (called "EKU chaining") all -// have the extended key usage set to only time stamping usage +// have the appropriate extended key usage set. +// Leaf certificates must have exactly one EKU set to Timestamping +// Intermediates can have no EKU (unrestricted) or multiple EKUs, +// which need to include Timestamping or UsageAny. func verifyLeafAndIntermediatesTimestampingEKU(leafCert *x509.Certificate, opts VerifyOpts) error { - err := verifyExtendedKeyUsage(leafCert) + err := verifyLeafExtendedKeyUsage(leafCert) if err != nil { return fmt.Errorf("failed to verify EKU on leaf certificate: %w", err) } for _, cert := range opts.Intermediates { - err := verifyExtendedKeyUsage(cert) + err := verifyIntermediateExtendedKeyUsage(cert) if err != nil { return fmt.Errorf("failed to verify EKU on intermediate certificate: %w", err) } diff --git a/pkg/verification/verify_request.go b/pkg/verification/verify_request.go index 3e9db5e55..ba7511d75 100644 --- a/pkg/verification/verify_request.go +++ b/pkg/verification/verify_request.go @@ -16,17 +16,32 @@ package verification import ( "crypto" + "fmt" "github.com/digitorus/timestamp" "github.com/pkg/errors" ) var ErrWeakHashAlg = errors.New("weak hash algorithm: must be SHA-256, SHA-384, or SHA-512") +var ErrUnsupportedHashAlg = errors.New("unsupported hash algorithm") +var ErrInconsistentDigestLength = errors.New("digest length inconsistent with specified hash algorithm") func VerifyRequest(ts *timestamp.Request) error { // only SHA-1, SHA-256, SHA-384, and SHA-512 are supported by the underlying library - if ts.HashAlgorithm == crypto.SHA1 { + switch ts.HashAlgorithm { + case crypto.SHA1: return ErrWeakHashAlg + case crypto.SHA256, crypto.SHA384, crypto.SHA512: + default: + return ErrUnsupportedHashAlg } + + expectedDigestLength := ts.HashAlgorithm.Size() + actualDigestLength := len(ts.HashedMessage) + + if actualDigestLength != expectedDigestLength { + return fmt.Errorf("%w: expected %d bytes, got %d bytes", ErrInconsistentDigestLength, expectedDigestLength, actualDigestLength) + } + return nil } diff --git a/pkg/verification/verify_request_test.go b/pkg/verification/verify_request_test.go index 6b1486234..791faf028 100644 --- a/pkg/verification/verify_request_test.go +++ b/pkg/verification/verify_request_test.go @@ -16,23 +16,63 @@ package verification import ( "crypto" + "errors" "testing" "github.com/digitorus/timestamp" ) func TestVerifyRequest(t *testing.T) { - tsReq := ×tamp.Request{} - - for _, alg := range []crypto.Hash{crypto.SHA256, crypto.SHA384, crypto.SHA512} { - tsReq.HashAlgorithm = alg - if err := VerifyRequest(tsReq); err != nil { - t.Fatalf("unexpected error verifying request, got %v", err) - } + tests := []struct { + name string + tsReq *timestamp.Request + expectedError error + }{ + { + name: "Valid SHA256", + tsReq: ×tamp.Request{HashAlgorithm: crypto.SHA256, HashedMessage: make([]byte, crypto.SHA256.Size())}, + expectedError: nil, + }, + { + name: "Valid SHA384", + tsReq: ×tamp.Request{HashAlgorithm: crypto.SHA384, HashedMessage: make([]byte, crypto.SHA384.Size())}, + expectedError: nil, + }, + { + name: "Valid SHA512", + tsReq: ×tamp.Request{HashAlgorithm: crypto.SHA512, HashedMessage: make([]byte, crypto.SHA512.Size())}, + expectedError: nil, + }, + { + name: "Weak Hash SHA1", + tsReq: ×tamp.Request{HashAlgorithm: crypto.SHA1, HashedMessage: make([]byte, crypto.SHA1.Size())}, + expectedError: ErrWeakHashAlg, + }, + { + name: "Unsupported Hash Algorithm", + tsReq: ×tamp.Request{HashAlgorithm: crypto.SHA224, HashedMessage: make([]byte, crypto.SHA224.Size())}, + expectedError: ErrUnsupportedHashAlg, + }, + { + name: "Inconsistent Digest Length", + tsReq: ×tamp.Request{HashAlgorithm: crypto.SHA256, HashedMessage: make([]byte, 31)}, // SHA256 size is 32 + expectedError: ErrInconsistentDigestLength, + }, } - tsReq.HashAlgorithm = crypto.SHA1 - if err := VerifyRequest(tsReq); err != ErrWeakHashAlg { - t.Fatalf("expected error with weak hash algorithm, got %v", err) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := VerifyRequest(tc.tsReq) + if tc.expectedError != nil { + if err == nil { + t.Fatalf("expected error %v, got nil", tc.expectedError) + } + if !errors.Is(err, tc.expectedError) { + t.Fatalf("expected error to be or wrap %v, but got %v (error message: %q)", tc.expectedError, err, err.Error()) + } + } else if err != nil { + t.Fatalf("expected no error, but got %v", err) + } + }) } } diff --git a/pkg/verification/verify_test.go b/pkg/verification/verify_test.go index b97e679cd..c6249185d 100644 --- a/pkg/verification/verify_test.go +++ b/pkg/verification/verify_test.go @@ -182,7 +182,9 @@ func TestVerifyLeafCert(t *testing.T) { type test struct { useOptsCert bool useTSCert bool + onlyCACerts bool expectVerifySuccess bool + expectedErrMsg string } tests := []test{ @@ -190,6 +192,7 @@ func TestVerifyLeafCert(t *testing.T) { useOptsCert: false, useTSCert: false, expectVerifySuccess: false, + expectedErrMsg: "leaf certificate must be present the in TSR or as a verify option", }, { useOptsCert: true, @@ -206,6 +209,12 @@ func TestVerifyLeafCert(t *testing.T) { useTSCert: true, expectVerifySuccess: true, }, + // test when a chain only contains CA certificates + { + onlyCACerts: true, + expectVerifySuccess: false, + expectedErrMsg: "no leaf certificate found in chain", + }, } for _, tc := range tests { @@ -237,12 +246,21 @@ func TestVerifyLeafCert(t *testing.T) { ts.Certificates = []*x509.Certificate{sampleCert} } + if tc.onlyCACerts { + sampleCert.IsCA = true + ts.Certificates = []*x509.Certificate{sampleCert} + } + err := verifyLeafCert(ts, opts) if err != nil && tc.expectVerifySuccess { t.Fatalf("expected error to be nil, actual error: %v", err) } + if err != nil && !strings.Contains(err.Error(), tc.expectedErrMsg) { + t.Fatalf("expected error message %s, got %s", tc.expectedErrMsg, err.Error()) + } + if err == nil && !tc.expectVerifySuccess { t.Fatal("expected error not to be nil") } @@ -432,7 +450,7 @@ func TestVerifyESSCertID(t *testing.T) { } } -func TestVerifyExtendedKeyUsage(t *testing.T) { +func TestVerifyLeafExtendedKeyUsage(t *testing.T) { type test struct { eku []x509.ExtKeyUsage expectVerifySuccess bool @@ -458,9 +476,53 @@ func TestVerifyExtendedKeyUsage(t *testing.T) { ExtKeyUsage: tc.eku, } - err := verifyExtendedKeyUsage(&cert) + err := verifyLeafExtendedKeyUsage(&cert) + if err != nil && tc.expectVerifySuccess { + t.Errorf("expected verifyLeafExtendedKeyUsage to return nil error") + } + if err == nil && !tc.expectVerifySuccess { + t.Errorf("expected verification to fail") + } + } +} + +func TestVerifyIntermediateExtendedKeyUsage(t *testing.T) { + type test struct { + eku []x509.ExtKeyUsage + expectVerifySuccess bool + } + + tests := []test{ + { + eku: []x509.ExtKeyUsage{}, + expectVerifySuccess: true, + }, + { + eku: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping}, + expectVerifySuccess: true, + }, + { + eku: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping, x509.ExtKeyUsageIPSECTunnel}, + expectVerifySuccess: true, + }, + { + eku: []x509.ExtKeyUsage{x509.ExtKeyUsageAny, x509.ExtKeyUsageIPSECTunnel}, + expectVerifySuccess: true, + }, + { + eku: []x509.ExtKeyUsage{x509.ExtKeyUsageIPSECTunnel}, + expectVerifySuccess: false, + }, + } + + for _, tc := range tests { + cert := x509.Certificate{ + ExtKeyUsage: tc.eku, + } + + err := verifyIntermediateExtendedKeyUsage(&cert) if err != nil && tc.expectVerifySuccess { - t.Errorf("expected verifyExtendedKeyUsage to return nil error") + t.Errorf("expected verifyIntermediateExtendedKeyUsage to return nil error") } if err == nil && !tc.expectVerifySuccess { t.Errorf("expected verification to fail") diff --git a/test/fuzz/oss_fuzz_build.sh b/test/fuzz/oss_fuzz_build.sh new file mode 100755 index 000000000..a0d407aab --- /dev/null +++ b/test/fuzz/oss_fuzz_build.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Copyright 2025 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. + +go get github.com/AdamKorcz/go-118-fuzz-build/testing + +compile_native_go_fuzzer github.com/sigstore/timestamp-authority/pkg/api FuzzParseJSONRequest FuzzParseJSONRequest +compile_native_go_fuzzer github.com/sigstore/timestamp-authority/pkg/api FuzzParseDERRequest FuzzParseDERRequest + +zip -qj $OUT/FuzzParseJSONRequest_seed_corpus.zip $SRC/go-fuzz-corpus/json/corpus/* +cp $SRC/afl-fuzz/dictionaries/json.dict $OUT/FuzzParseJSONRequest.dict