pax_global_header00006660000000000000000000000064147060263630014521gustar00rootroot0000000000000052 comment=124b73ba1c054a0858f20486e1b7427b4e66c0fd golang-github-sigstore-timestamp-authority-1.2.3/000077500000000000000000000000001470602636300221375ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/.github/000077500000000000000000000000001470602636300234775ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/.github/dependabot.yml000066400000000000000000000024501470602636300263300ustar00rootroot00000000000000# # Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "daily" groups: gomod: update-types: - "patch" - package-ecosystem: "gomod" directory: "./hack/tools" schedule: interval: "daily" groups: gomod-hack: update-types: - "minor" - "patch" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" groups: actions: update-types: - "minor" - "patch" - package-ecosystem: "docker" directory: "/" schedule: interval: "daily" groups: docker: update-types: - "minor" - "patch" golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/000077500000000000000000000000001470602636300255345ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/build-snapshot.yaml000066400000000000000000000024441470602636300313600ustar00rootroot00000000000000name: build-snapshot on: pull_request: permissions: {} jobs: snapshot: permissions: contents: read runs-on: ubuntu-latest outputs: hashes: ${{ steps.hash.outputs.hashes }} tag_name: ${{ steps.tag.outputs.tag_name }} steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: './go.mod' check-latest: true - uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # v3.6.0 - uses: anchore/sbom-action/download-syft@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.17.2 - uses: imjasonh/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Set LDFLAGS id: ldflags run: | source ./release/ldflags.sh goflags=$(ldflags) echo "GO_FLAGS="${goflags}"" >> "$GITHUB_ENV" - name: Run GoReleaser id: run-goreleaser uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0 with: version: latest args: release --clean --skip=sign --snapshot env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LDFLAGS: ${{ env.GO_FLAGS }} golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/codeql_analysis.yaml000066400000000000000000000036511470602636300315770ustar00rootroot00000000000000# Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#changing-the-languages-that-are-analyzed name: CodeQL on: push: branches: [ main ] paths-ignore: - '**.md' pull_request: # The branches below must be a subset of the branches above branches: [ main ] schedule: - cron: '45 10 * * 1' permissions: contents: read jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: security-events: write strategy: fail-fast: false matrix: language: [ 'go' ] steps: - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: './go.mod' check-latest: true # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: languages: ${{ matrix.language }} - name: Autobuild uses: github/codeql-action/autobuild@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/dependecy_review.yaml000066400000000000000000000017201470602636300317410ustar00rootroot00000000000000# Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: 'Dependency Review' on: [pull_request] permissions: contents: read jobs: dependency-review: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: 'Dependency Review' uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/release.yaml000066400000000000000000000050021470602636300300350ustar00rootroot00000000000000name: cut-release on: push: tags: - "v*" concurrency: cut-release permissions: read-all jobs: release: permissions: contents: write # needed to write releases id-token: write # needed for keyless signing packages: write # needed for pushing the images to ghcr.io runs-on: ubuntu-latest outputs: hashes: ${{ steps.hash.outputs.hashes }} tag_name: ${{ steps.tag.outputs.tag_name }} steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: './go.mod' check-latest: true - uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # v3.6.0 - uses: anchore/sbom-action/download-syft@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.17.2 - uses: imjasonh/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Set LDFLAGS id: ldflags run: | source ./release/ldflags.sh goflags=$(ldflags) echo "GO_FLAGS="${goflags}"" >> "$GITHUB_ENV" - name: Run GoReleaser id: run-goreleaser uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0 with: version: latest args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LDFLAGS: ${{ env.GO_FLAGS }} - name: Generate subject id: hash env: ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}" run: | set -euo pipefail checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path') echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT" - name: Set tag output id: tag run: echo "tag_name=${GITHUB_REF#refs/*/}" >> "$GITHUB_OUTPUT" - name: build and sign images run: make sign-container-release provenance: needs: [release] permissions: 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 with: base64-subjects: "${{ needs.release.outputs.hashes }}" upload-assets: true upload-tag-name: "${{ needs.release.outputs.tag_name }}" # Upload to tag rather than generate a new release draft-release: true golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/scorecard.yaml000066400000000000000000000051401470602636300303650ustar00rootroot00000000000000# Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: Scorecards supply-chain security on: # Only the default branch is supported. branch_protection_rule: schedule: # Weekly on Saturdays. - cron: '30 1 * * 6' push: branches: [ main ] # Declare default permissions as read only. permissions: read-all jobs: analysis: name: Scorecards analysis runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. security-events: write actions: read contents: read id-token: write steps: - name: "Checkout code" uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif # Read-only PAT token. To create it, # follow the steps in https://github.com/ossf/scorecard-action#installation. repo_token: ${{ secrets.SCORECARD_TOKEN }} # Publish the results for public repositories to enable scorecard badges. For more details, see # https://github.com/ossf/scorecard-action#publishing-results. # For private repositories, `publish_results` will automatically be set to `false`, regardless # of the value entered here. publish_results: true # 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@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: SARIF file path: results.sarif retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@461ef6c76dfe95d5c364de2f431ddbd31a417628 # v3.26.9 with: sarif_file: results.sarif golang-github-sigstore-timestamp-authority-1.2.3/.github/workflows/tests.yaml000066400000000000000000000063701470602636300275700ustar00rootroot00000000000000# Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: ci-checks on: workflow_dispatch: push: branches: - 'main' - 'updates' pull_request: permissions: read-all jobs: unit-tests: name: Run unit tests permissions: contents: read runs-on: ubuntu-latest env: OS: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: # In order: # * Module download cache # * Build cache (Linux) path: | ~/go/pkg/mod ~/.cache/go-build ~/Library/Caches/go-build %LocalAppData%\go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: './go.mod' check-latest: true - name: Build timestamp CLI run: make timestamp-cli - 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@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: env_vars: OS - name: Run Go tests w/ `-race` if: ${{ runner.os == 'Linux' }} run: go test -race $(go list ./... | grep -v third_party/) license-check: name: license boilerplate check runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: './go.mod' check-latest: true - name: Install addlicense run: go install github.com/google/addlicense@2fe3ee94479d08be985a84861de4e6b06a1c7208 # v1.0.0 - name: Check license headers run: | set -e addlicense -check -l apache -c 'The Sigstore Authors' -ignore "third_party/**" -v * golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: './go.mod' check-latest: true - name: golangci-lint uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0 with: version: v1.61 args: --timeout=10m --verbose golang-github-sigstore-timestamp-authority-1.2.3/.gitignore000066400000000000000000000003101470602636300241210ustar00rootroot00000000000000.vscode/* *~ dist/* timestampCLIImagerefs timestampServerImagerefs fetchTSAImagerefs *.tsr hack/tools/bin/* bin/ request.tsq response.tsr request.json myblob ts_chain.pem enc-keyset.cfg chain.crt.pem golang-github-sigstore-timestamp-authority-1.2.3/.golangci.yml000066400000000000000000000017761470602636300245360ustar00rootroot00000000000000# # Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. linters: enable: - errcheck - gofmt - goimports - gosec - gocritic - misspell - revive - unused output: uniq-by-line: false 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 golang-github-sigstore-timestamp-authority-1.2.3/.goreleaser.yml000066400000000000000000000041101470602636300250640ustar00rootroot00000000000000project_name: timestamp-authority env: - GO111MODULE=on - CGO_ENABLED=0 - DOCKER_CLI_EXPERIMENTAL=enabled - COSIGN_YES=true # Prevents parallel builds from stepping on eachothers toes downloading modules before: hooks: - go mod tidy - /bin/bash -c 'if [ -n "$(git --no-pager diff --exit-code go.mod go.sum)" ]; then exit 1; fi' gomod: proxy: true sboms: - artifacts: binary builds: - id: timestamp-server binary: timestamp-server-linux-{{ .Arch }} no_unique_dist_dir: true main: ./cmd/timestamp-server goos: - linux goarch: - amd64 - arm64 - arm goarm: - 7 flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" - id: timestamp-cli binary: timestamp-cli-{{ .Os }}-{{ .Arch }} no_unique_dist_dir: true main: ./cmd/timestamp-cli goos: - linux - darwin - windows goarch: - amd64 - arm64 - arm goarm: - 7 ignore: - goos: windows goarch: arm64 flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" signs: # Keyless - id: keyless signature: "${artifact}-keyless.sig" certificate: "${artifact}-keyless.pem" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] artifacts: binary - id: checksum-keyless signature: "${artifact}-keyless.sig" certificate: "${artifact}-keyless.pem" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] artifacts: checksum archives: - format: binary name_template: "{{ .Binary }}" allow_different_binary_count: true checksum: name_template: "{{ .ProjectName }}_checksums.txt" snapshot: name_template: SNAPSHOT-{{ .ShortCommit }} release: prerelease: auto draft: true # allow for manual edits github: owner: sigstore name: timestamp-authority golang-github-sigstore-timestamp-authority-1.2.3/.ko.yaml000066400000000000000000000024161470602636300235150ustar00rootroot00000000000000# # Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # We need a shell for a lot of redirection/piping to work defaultBaseImage: ghcr.io/chainguard-images/static:latest builds: - id: timestamp-cli dir: . main: ./cmd/timestamp-cli env: - CGO_ENABLED=0 flags: - -trimpath - -tags - "{{ .Env.GIT_HASH }}" - -tags - "{{ .Env.GIT_VERSION }}" ldflags: - -extldflags "-static" - "{{ .Env.LDFLAGS }}" - id: timestamp-server dir: . main: ./cmd/timestamp-server env: - CGO_ENABLED=0 flags: - -trimpath - --tags - "{{ .Env.GIT_HASH }}" - --tags - "{{ .Env.GIT_VERSION }}" ldflags: - -extldflags "-static" - "{{ .Env.LDFLAGS }}" golang-github-sigstore-timestamp-authority-1.2.3/CHANGELOG.md000066400000000000000000000141661470602636300237600ustar00rootroot00000000000000# v1.2.2 ## Changes ### Bug fixes * Go checksum database error on installation due to deleting a tag ### Misc * Dependabot updates # v1.2.1 v1.2.1 includes a minor bug fix to set the SignedData version value in a timestamp response as per the RFC. ## Changes ### Bug Fixes * Bump digitorus/timestamp version to pick up RFC correctness fix (#584) # v1.2.0 v1.2.0 is based on Go 1.21.3. ## Changes ### Enhancements * Support other hash algs for pre-signed timestamp besides SHA256 (#488) * new http-ping-only flag for 'timestamp-server serve' (#474) ### Bug Fixes * Fix bug where TSA signing fails if cert hash != content hash. (#465) ### Misc * expand README on Cloud KMS deployment (#476) * upgrade to Go1.21 (#471) ## Contributors * Billy Lynch * Carlos Tadeu Panato Junior * Dmitry Savintsev * Hayden B # 1.1.2 1.1.2 fixes a signing related hash function bug and a typo. ## Changes ### Enhancements ### Bug Fixes * Fix hash function hardcoding bug by updating dependency (https://github.com/sigstore/timestamp-authority/pull/452) ### Misc * Fix typo in OpenAPI spec (https://github.com/sigstore/timestamp-authority/pull/419) * Update GoReleaser flag (https://github.com/sigstore/timestamp-authority/pull/356) ## Contributors * Carlos Tadeu Panato Junior * Dmitry Savintsev * Meredith Lancaster # 1.1.1 1.1.1 fixes a bug in the JSON format request code. ## Changes ### Enhancements ### Bug Fixes * Update how the JSON body is parsed (https://github.com/sigstore/timestamp-authority/pull/343) ### Misc ## Contributors * Meredith Lancaster # 1.1.0 1.1.0 now supports making timestamp requests in JSON format in addition to DER encoded format. ## Changes ### Enhancements * Support timestamp requests in JSON format (https://github.com/sigstore/timestamp-authority/pull/247) ### Bug Fixes ### Misc * Fix typo in README (https://github.com/sigstore/timestamp-authority/pull/294) ## Contributors * Andrea Cosentino * Meredith Lancaster # 1.0.0 1.0 release of the timestamp authority. No changes from the previous release candidate. Thank you to all contributors! # 1.0.0-rc.1 _Note: This is a prerelease for 1.0. Please try it out and file issues!_ ## Changes * Upgrade to go 1.20.1 (https://github.com/sigstore/timestamp-authority/pull/245) ### Documentation * Update policy (https://github.com/sigstore/timestamp-authority/pull/251, https://github.com/sigstore/timestamp-authority/pull/262) ## Contributors * Carlos Tadeu Panato Junior * Hayden B * Meredith Lancaster # 1.0.0-rc.0 _Note: This is a prerelease for 1.0. Please try it out and file issues!_ ## Changes SLSA provenance is now uploaded with each release. Use [slsa-verifier](https://github.com/slsa-framework/slsa-verifier/) to verify the release. ### Misc * Mock NTP client (https://github.com/sigstore/timestamp-authority/pull/217) ## Contributors * Carlos Tadeu Panato Junior * Hayden B * Meredith Lancaster # 0.2.1 0.2.1 now rejects timestamp requests that use SHA-1. For server operators, it now defaults to using NTP monitoring. ## Changes ### Enhancements * Generate slsa provenance (https://github.com/sigstore/timestamp-authority/pull/193) * Use default NTP monitoring configuration (https://github.com/sigstore/timestamp-authority/pull/186) * Reject requests that use SHA-1 (https://github.com/sigstore/timestamp-authority/pull/202) ### Bug Fixes ### Misc * Update README with more details (https://github.com/sigstore/timestamp-authority/pull/188) ## Contributors * Hayden B * Hector Fernandez * Meredith Lancaster # 0.2.0 0.2.0 improves the verification library (https://github.com/sigstore/timestamp-authority/issues/121). The library now verifies the full certificate chain and additional properties of the timestamp. ## Changes ### Enhancements * Start adding more verification with VerificationOpts struct (https://github.com/sigstore/timestamp-authority/pull/153) * Verify command returns the parsed timestamp (https://github.com/sigstore/timestamp-authority/pull/174) * Add intermediate and root verify flags (https://github.com/sigstore/timestamp-authority/pull/180) * Verify full certificate chain (https://github.com/sigstore/timestamp-authority/pull/181) ### Bug fixes ### Misc * Add mock client (https://github.com/sigstore/timestamp-authority/pull/175) * Update timing accuracy statements in the policy document (https://github.com/sigstore/timestamp-authority/pull/179) ## Contributors * Hayden Blauzvern * Meredith Lancaster # 0.1.3 ## Changes ### Enhancements * Added an optional feature to compare the local time with a set of trusted ntp servers (https://github.com/sigstore/timestamp-authority/pull/143) ### Bug fixes * Register KMS providers (https://github.com/sigstore/timestamp-authority/pull/160) * Added .PHONY target for CLI rebuilding (https://github.com/sigstore/timestamp-authority/pull/159) ### Misc * inspect: remove format flag (https://github.com/sigstore/timestamp-authority/pull/155) ## Contributors * Fredrik Skogman * Hector Fernandez * Meredith Lancaster * neilnaveen # 0.1.2 ## Changes ### Enhancements ### Bug fixes * Fix a bug where certChain was not set correctly (https://github.com/sigstore/timestamp-authority/pull/140) ### Misc ## Contributors * Ville Aikas # 0.1.1 ## Changes ### Enhancements * Update in memory signer to use intermediate certificate (https://github.com/sigstore/timestamp-authority/pull/136) * Move verify logic to pkg (https://github.com/sigstore/timestamp-authority/pull/120) ### Bug fixes * Require the file signer to specify the certificate chain (https://github.com/sigstore/timestamp-authority/pull/137) * Fix hashed message verification (https://github.com/sigstore/timestamp-authority/pull/118) * Update fetch TSA certs script for Tink (https://github.com/sigstore/timestamp-authority/pull/111) ### Misc ## Contributors * Hayden Blauzvern * Hector Fernandez # 0.1.0 Initial release of sigstore/timestamp-authority See the [README](README.md) for instructions on how to run the timestamp authority and fetch and verify signed timestamps. ## Contributors * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) * Hector Fernandez (@hectorj2f) * Meredith Lancaster (@malancas) golang-github-sigstore-timestamp-authority-1.2.3/CODEOWNERS000066400000000000000000000003601470602636300235310ustar00rootroot00000000000000* @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 golang-github-sigstore-timestamp-authority-1.2.3/CODE_OF_CONDUCT.md000066400000000000000000000062161470602636300247430ustar00rootroot00000000000000# 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/golang-github-sigstore-timestamp-authority-1.2.3/CONTRIBUTORS.md000066400000000000000000000104731470602636300244230ustar00rootroot00000000000000# Contributing When contributing to this repository, please first discuss the change you wish to make via an [issue](https://github.com/sigstore/timestamp-authority/issues). ## Pull Request Process 1. Create an [issue](https://github.com/sigstore/timestamp-authority/issues) outlining the fix or feature. 2. Fork the {project-name} repository to your own github account and clone it locally. 3. Hack on your changes. 4. Update the README.md with details of changes to any interface, this includes new environment variables, exposed ports, useful file locations, CLI parameters and new or changed configuration values. 5. Correctly format your commit message see [Commit Messages](#Commit-Message-Guidelines) below. 6. Ensure that CI passes, if it fails, fix the failures. 7. Every pull request requires a review from the [core timestamp-authority team](https://github.com/orgs/github.com/sigstore/teams/tsa-codeowners) before merging. 8. If your pull request consists of more than one commit, please squash your commits as described in [Squash Commits](#Squash-Commits) ## Commit Message Guidelines We follow the commit formatting recommendations found on [Chris Beams' How to Write a Git Commit Message article](https://chris.beams.io/posts/git-commit/). Well formed commit messages not only help reviewers understand the nature of the Pull Request, but also assists the release process where commit messages are used to generate release notes. A good example of a commit message would be as follows: ``` Summarize changes in around 50 characters or less More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of the commit and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); various tools like `log`, `shortlog` and `rebase` can get confused if you run the two together. Explain the problem that this commit is solving. Focus on why you are making this change as opposed to how (the code explains that). Are there side effects or other unintuitive consequences of this change? Here's the place to explain them. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here If you use an issue tracker, put references to them at the bottom, like this: Resolves: #123 See also: #456, #789 ``` Note the `Resolves #123` tag, this references the issue raised and allows us to ensure issues are associated and closed when a pull request is merged. Please refer to [the github help page on message types](https://help.github.com/articles/closing-issues-using-keywords/) for a complete list of issue references. ## Squash Commits Should your pull request consist of more than one commit (perhaps due to a change being requested during the review cycle), please perform a git squash once a reviewer has approved your pull request. A squash can be performed as follows. Let's say you have the following commits: initial commit second commit final commit Run the command below with the number set to the total commits you wish to squash (in our case 3 commits): git rebase -i HEAD~3 You default text editor will then open up and you will see the following:: pick eb36612 initial commit pick 9ac8968 second commit pick a760569 final commit # Rebase eb1429f..a760569 onto eb1429f (3 commands) We want to rebase on top of our first commit, so we change the other two commits to `squash`: pick eb36612 initial commit squash 9ac8968 second commit squash a760569 final commit After this, should you wish to update your commit message to better summarise all of your pull request, run: git commit --amend You will then need to force push (assuming your initial commit(s) were posted to github): git push origin your-branch --force Alternatively, a core member can squash your commits within Github. ## Code of Conduct {project-name} adheres to and enforces the [Contributor Covenant](http://contributor-covenant.org/version/1/4/) Code of Conduct. Please take a moment to read the [CODE_OF_CONDUCT.md](https://github.com/sigstore/timestamp-authority/blob/main/CODE_OF_CONDUCT.md) document.golang-github-sigstore-timestamp-authority-1.2.3/COPYRIGHT.txt000066400000000000000000000010621470602636300242470ustar00rootroot00000000000000Copyright 2022 The Sigstore Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-sigstore-timestamp-authority-1.2.3/Dockerfile000066400000000000000000000032511470602636300241320ustar00rootroot00000000000000# Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM golang:1.23.1@sha256:2fe82a3f3e006b4f2a316c6a21f62b66e1330ae211d039bb8d1128e12ed57bf1 AS builder ENV APP_ROOT=/opt/app-root ENV GOPATH=$APP_ROOT WORKDIR $APP_ROOT/src/ ADD go.mod go.sum $APP_ROOT/src/ RUN go mod download # Add source code ADD ./cmd/ $APP_ROOT/src/cmd/ ADD ./pkg/ $APP_ROOT/src/pkg/ ARG SERVER_LDFLAGS RUN go build -ldflags "${SERVER_LDFLAGS}" ./cmd/timestamp-server RUN CGO_ENABLED=0 go build -gcflags "all=-N -l" -ldflags "${SERVER_LDFLAGS}" -o timestamp-server_debug ./cmd/timestamp-server # Multi-Stage production build FROM golang:1.23.1@sha256:2fe82a3f3e006b4f2a316c6a21f62b66e1330ae211d039bb8d1128e12ed57bf1 as deploy # Retrieve the binary from the previous stage COPY --from=builder /opt/app-root/src/timestamp-server /usr/local/bin/timestamp-server # Set the binary as the entrypoint of the container CMD ["timestamp-server", "serve"] # debug compile options & debugger FROM deploy as debug RUN go install github.com/go-delve/delve/cmd/dlv@v1.22.1 # overwrite server and include debugger COPY --from=builder /opt/app-root/src/timestamp-server_debug /usr/local/bin/timestamp-server golang-github-sigstore-timestamp-authority-1.2.3/LICENSE000066400000000000000000000261341470602636300231520ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.golang-github-sigstore-timestamp-authority-1.2.3/Makefile000066400000000000000000000122231470602636300235770ustar00rootroot00000000000000# # Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. .PHONY: all test clean clean-gen lint gosec ko ko-local all: timestamp-cli timestamp-server GENSRC = pkg/generated/client/%.go pkg/generated/models/%.go pkg/generated/restapi/%.go OPENAPIDEPS = openapi.yaml SRCS = $(shell find cmd -iname "*.go") $(shell find pkg -iname "*.go"|grep -v pkg/generated) pkg/generated/restapi/configure_timestamp_server.go $(GENSRC) TOOLS_DIR := hack/tools TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin) # Set version variables for LDFLAGS GIT_VERSION ?= $(shell git describe --tags --always --dirty) GIT_HASH ?= $(shell git rev-parse HEAD) DATE_FMT = +%Y-%m-%dT%H:%M:%SZ SOURCE_DATE_EPOCH ?= $(shell git log -1 --pretty=%ct) ifdef SOURCE_DATE_EPOCH BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)") else BUILD_DATE ?= $(shell date "$(DATE_FMT)") endif GIT_TREESTATE = "clean" DIFF = $(shell git diff --quiet >/dev/null 2>&1; if [ $$? -eq 1 ]; then echo "1"; fi) ifeq ($(DIFF), 1) GIT_TREESTATE = "dirty" endif KO_PREFIX ?= ghcr.io/sigstore export KO_DOCKER_REPO=$(KO_PREFIX) # Binaries SWAGGER := $(TOOLS_BIN_DIR)/swagger LDFLAGS=-X sigs.k8s.io/release-utils/version.gitVersion=$(GIT_VERSION) \ -X sigs.k8s.io/release-utils/version.gitCommit=$(GIT_HASH) \ -X sigs.k8s.io/release-utils/version.gitTreeState=$(GIT_TREESTATE) \ -X sigs.k8s.io/release-utils/version.buildDate=$(BUILD_DATE) CLI_LDFLAGS=$(LDFLAGS) SERVER_LDFLAGS=$(LDFLAGS) $(GENSRC): $(SWAGGER) $(OPENAPIDEPS) $(SWAGGER) generate client -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated $(SWAGGER) generate server -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --exclude-main -A timestamp_server --flag-strategy=pflag .PHONY: validate-openapi validate-openapi: $(SWAGGER) ## Validate OpenAPI spec $(SWAGGER) validate openapi.yaml # this exists to override pattern match rule above since this file is in the generated directory but should not be treated as generated code pkg/generated/restapi/configure_timestamp_server.go: $(OPENAPIDEPS) lint: ## Go linting $(GOBIN)/golangci-lint run -v ./... gosec: ## Run gosec $(GOBIN)/gosec ./... gen: $(GENSRC) ## Generate code from OpenAPI spec .PHONY : timestamp-cli timestamp-cli: $(SRCS) ## Build the TSA CLI CGO_ENABLED=0 go build -trimpath -ldflags "$(CLI_LDFLAGS)" -o bin/timestamp-cli ./cmd/timestamp-cli timestamp-server: $(SRCS) ## Build the TSA server CGO_ENABLED=0 go build -trimpath -ldflags "$(SERVER_LDFLAGS)" -o bin/timestamp-server ./cmd/timestamp-server test: timestamp-cli ## Run tests go test ./... clean: ## Clean all builds rm -rf dist rm -rf hack/tools/bin rm -rf bin/timestamp-cli bin/timestamp-server clean-gen: clean ## Clean generated code rm -rf $(shell find pkg/generated -iname "*.go"|grep -v pkg/generated/restapi/configure_timestamp_server.go) up: ## Run the TSA with Docker Compose docker-compose -f docker-compose.yml build --build-arg SERVER_LDFLAGS="$(SERVER_LDFLAGS)" docker-compose -f docker-compose.yml up ko: ## Run Ko # timestamp-server LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ KO_DOCKER_REPO=$(KO_PREFIX)/timestamp-server ko build --bare \ --platform=all --tags $(GIT_VERSION) --tags $(GIT_HASH) \ --image-refs timestampServerImagerefs github.com/sigstore/timestamp-authority/cmd/timestamp-server # timestamp-cli LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ KO_DOCKER_REPO=$(KO_PREFIX)/timestamp-cli ko build --bare \ --platform=all --tags $(GIT_VERSION) --tags $(GIT_HASH) \ --image-refs timestampCLIImagerefs github.com/sigstore/timestamp-authority/cmd/timestamp-cli .PHONY: ko-local ko-local: ## Run Ko locally LDFLAGS="$(SERVER_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko publish --base-import-paths \ --tags $(GIT_VERSION) --tags $(GIT_HASH) --local \ github.com/sigstore/timestamp-authority/cmd/timestamp-server LDFLAGS="$(CLI_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko publish --base-import-paths \ --tags $(GIT_VERSION) --tags $(GIT_HASH) --local \ github.com/sigstore/timestamp-authority/cmd/timestamp-cli ## -------------------------------------- ## Tooling Binaries ## -------------------------------------- $(SWAGGER): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/swagger github.com/go-swagger/go-swagger/cmd/swagger ################## # help ################## help: ## Display help @awk -F ':|##' \ '/^[^\t].+?:.*?##/ {\ printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \ }' $(MAKEFILE_LIST) | sort include release/release.mk golang-github-sigstore-timestamp-authority-1.2.3/README.md000066400000000000000000000255521470602636300234270ustar00rootroot00000000000000[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/sigstore/timestamp-authority/badge)](https://api.securityscorecards.dev/projects/github.com/sigstore/timestamp-authority) # Sigstore Timestamp Authority A service for issuing [RFC 3161 timestamps](https://datatracker.ietf.org/doc/html/rfc3161). Timestamps conform to the [RFC 3628 policy](https://datatracker.ietf.org/doc/html/rfc3628). The timestamp structure conforms to the updates in [RFC 5816](https://datatracker.ietf.org/doc/rfc5816). ## Security model [Trusted timestamping](https://en.wikipedia.org/wiki/Trusted_timestamping) is a process that has been around for some time. It provides a timestamp record of when a document was created or modified. A timestamp authority creates signed timestamps using public key infrastructure. The operator of the timestamp authority must secure the signing key material to prevent unauthorized timestamp signing. A timestamp authority should also verify its own clock. We provide a configuration to periodically check the current time against well-known NTP sources. ## Timestamping within Sigstore Timestamps are a critical component of [Rekor](https://github.com/sigstore/rekor), Sigstore's signature transparency log. Timestamps are used to verify short-lived certificates. Currently, the timestamp comes from Rekor's own internal clock, which is not externally verifiable or immutable. Using signed timestamps issued from timestamp authorities mitigates the risk of Rekor's clock being manipulated. As a artifact signer, you can: * Generate a signature over an artifact * Fetch a timestamp for that signature (more below in [What to sign](#what-to-sign)) * Upload the signature, artifact hash, and certificate to Rekor (hashedrekord record type) * Upload the timestamp to Rekor (rfc3161 record type) * This step is important because it makes the timestamps publicly auditable As an artifact verifier: * Fetch the artifact entry from Rekor * If the artifact was signed with a certificate, verify its expiration * If you trust Rekor's clock, verify the certificate with the timestamp in the Rekor response * If you trust an external timestamp authority, fetch the timestamp from Rekor, verify the signed timestamp, and verify the certificate using the signed timestamp ### What to sign For usage within Sigstore, we recommend signing over a value that is associated with a signature. For [Cosign](https://github.com/sigstore/cosign/), we have chosen to sign the artifact signature, a process called "countersigning". We sign over the raw signature bytes, not a base64-encoded value. Signing over the signature ensures that the signature, not the artifact, was created at a certain time. ## Local development Prerequisite: On macOS, we currently require the installation of `openssl`. ```shell brew install openssl ``` To launch the server, run either: * `docker-compose up` * `make timestamp-server && ./bin/timestamp-server serve --port 3000` Both of these commands launch a server with an in-memory signing key and certificate chain. **This should not be used for production.** To fetch a timestamp with the provided `timestamp-cli`: 1. Retrieve the verification chain: `curl http://localhost:3000/api/v1/timestamp/certchain > ts_chain.pem` 1. Create test blob to sign: `echo "myblob" > myblob` 1. Build client: `make timestamp-cli` 1. Fetch timestamp: `./bin/timestamp-cli --timestamp_server http://localhost:3000 timestamp --hash sha256 --artifact myblob --out response.tsr` 1. Verify timestamp: `./bin/timestamp-cli verify --timestamp response.tsr --artifact "myblob" --certificate-chain ts_chain.pem --format json` 1. Inspect timestamp: `./bin/timestamp-cli inspect --timestamp response.tsr --format json` To fetch a timestamp with `openssl` and `curl`: 1. Retrieve the verification chain: `curl http://localhost:3000/api/v1/timestamp/certchain > ts_chain.pem` 1. Split chain into root CA certificate and "untrusted" intermediate and leaf certificates: 1. Split: `csplit -s -f tmpcert- ts_chain.pem '/-----BEGIN CERTIFICATE-----/' '{*}'` * Note, on macOS, you will need to install GNU utilities with `brew install coreutils`, and use `gcsplit` 1. Remove empty file: `rm tmpcert-00` 1. Get root: `mv $(ls tmpcert-* | tail -1) root.crt.pem` 1. Merge remaining certificates: `cat tmpcert-* > chain.crts.pem` 1. Remove temp files: `rm tmpcert-*` 1. Create test blob to sign: `echo "myblob" > myblob` 1. Create timestamp request: `openssl ts -query -data myblob -cert -sha256 -out request.tsq` 1. Fetch timestamp: `curl -sSH "Content-Type: application/timestamp-query" --data-binary @request.tsq http://localhost:3000/api/v1/timestamp -o response.tsr` 1. Verify timestamp: `openssl ts -verify -in response.tsr -data "myblob" -CAfile root.crt.pem -untrusted chain.crts.pem` * Note that you will see a warning that one certificate is "not a CA cert", but this is expected, as you need to provide the TSA signing certificate in case the certificate is not included in the response. When generating the timestamp query, setting `-cert` will mandate the signing certificate is included. 1. Inspect timestamp: `openssl ts -reply -in response.tsr -text` ### Making a request with JSON If you would like to make a request for a timestamp using a JSON based request, you can do with: `curl -sSH "Content-Type: application/json" -d @request.json http://localhost:3000/api/v1/timestamp -o response.tsr` The service expects the JSON body to be in the shape: ``` { "artifactHash": "", "certificates": true, "hashAlgorithm": "sha256", "nonce": 1123343434, "tsaPolicyOID": "1.2.3.4" } ``` The artifact hash must be represented as a base64 encoded string. ## Production deployment To deploy to production, the timestamp authority currently supports signing with Cloud KMS or [Tink](https://github.com/google/tink). You will need to provide 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. ### 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: * 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://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 * assuming you have an external (for example, corporate etc.) Certificate Authority entity that can sign the CSR, make it sign the generated CSR and produce a certificate. Make sure that the leaf certificate - the one that will be used to sign timestamping requests - has the Timestamping EKU (Extended Key Usage) set and it is marked as Critical. * if necessary, combine the CA, intermediate and leaf certificates into the certificate chain file. Verify the certificate chain format with [VerifyCertChain](https://github.com/sigstore/timestamp-authority/blob/main/pkg/x509/x509.go#L35) to ensure it is compatible with what the `timestamp_server` expects. Set `--timestamp-signer=kms`, provide the path to the chain with `--certificate-chain-path`, and the KMS key with `--kms-key-resource`. The key should be prefixed with either `gcpkms://`, `azurekms://`, `awskms://`, or `hashivault://`. ### Tink [Tink](https://github.com/google/tink) is an easy-to-use cross-language crypto library. The timestamp authority provides a signer that uses Tink, which enables in-memory signing with secure on-disk key storage. Instead of being password-protected, the key is encrypted 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. 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 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" ``` 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://`. If using Vault, you may also set `--tink-hcvault-token`. Provide the path to the chain with `--certificate-chain-path`. ## Security Should you discover any security issues, please refer to Sigstore's [security process](https://github.com/sigstore/.github/blob/main/SECURITY.md). golang-github-sigstore-timestamp-authority-1.2.3/cmd/000077500000000000000000000000001470602636300227025ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/fetch-tsa-certs/000077500000000000000000000000001470602636300256765ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/fetch-tsa-certs/fetch_tsa_certs.go000066400000000000000000000222531470602636300313710ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package main import ( "context" "crypto" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "flag" "fmt" "log" "os" "path/filepath" "time" 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" "github.com/sigstore/timestamp-authority/pkg/signer" tsx509 "github.com/sigstore/timestamp-authority/pkg/x509" "google.golang.org/protobuf/types/known/durationpb" // Register the provider-specific plugins "github.com/sigstore/sigstore/pkg/signature/kms" _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" _ "github.com/sigstore/sigstore/pkg/signature/kms/azure" _ "github.com/sigstore/sigstore/pkg/signature/kms/gcp" _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) /* 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" You must have the permissions to read, sign with, and decrypt with the KMS keys, and create a certificate in the CA pool. You can create a GCP KMS encrypted Tink keyset with tinkey (changing the key template as needed): tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key-uri gcp-kms://projects//locations//keyRings//cryptoKeys/ */ 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://") // 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") ) func fetchCertificateChain(ctx context.Context, parent, intermediateKMSKey, leafKMSKey, tinkKeysetPath, tinkKmsKey string, client *privateca.CertificateAuthorityClient) ([]*x509.Certificate, error) { intermediateKMSSigner, err := kms.Get(ctx, intermediateKMSKey, crypto.SHA256) if err != nil { return nil, err } intermediateSigner, _, err := intermediateKMSSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } pemPubKey, err := cryptoutils.MarshalPublicKeyToPEM(intermediateSigner.Public()) if err != nil { return nil, err } // OID for Extended Key Usage Timestamping timestampExt, err := asn1.Marshal([]asn1.ObjectIdentifier{tsx509.EKUTimestampingOID}) if err != nil { return nil, err } additionalExtensions := []*privatecapb.X509Extension{{ ObjectId: &privatecapb.ObjectId{ObjectIdPath: []int32{2, 5, 29, 37}}, Critical: true, 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, }, }, CaOptions: &privatecapb.X509Parameters_CaOptions{ IsCa: &isCa, MaxIssuerPathLength: &maxIssuerPathLength, }, AdditionalExtensions: additionalExtensions, }, SubjectConfig: &privatecapb.CertificateConfig_SubjectConfig{ Subject: &privatecapb.Subject{ CommonName: "sigstore-tsa-intermediate", Organization: "sigstore.dev", }, }, }, }, }, } 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)) if err != nil { return nil, err } if len(certs) != 1 { return nil, errors.New("unexpected number of certificates returned") } parsedCerts = append(parsedCerts, certs[0]) } intermediate := parsedCerts[0] // generate leaf certificate var leafKMSSigner crypto.Signer if len(leafKMSKey) > 0 { kmsSigner, err := kms.Get(ctx, leafKMSKey, crypto.SHA256) if err != nil { return nil, err } leafKMSSigner, _, err = kmsSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } } else { primaryKey, err := signer.GetPrimaryKey(ctx, tinkKmsKey, "") if err != nil { return nil, err } f, err := os.Open(filepath.Clean(tinkKeysetPath)) if err != nil { return nil, err } defer f.Close() kh, err := keyset.Read(keyset.NewJSONReader(f), primaryKey) if err != nil { return nil, err } leafKMSSigner, err = signer.KeyHandleToSigner(kh) if err != nil { return nil, err } } leafPubKey := leafKMSSigner.Public() sn, err := cryptoutils.GenerateSerialNumber() if err != nil { return nil, fmt.Errorf("generating serial number: %w", err) } skid, err := cryptoutils.SKID(leafPubKey) if err != nil { return nil, err } cert := &x509.Certificate{ SerialNumber: sn, Subject: pkix.Name{ CommonName: "sigstore-tsa", Organization: []string{"sigstore.dev"}, }, SubjectKeyId: skid, NotBefore: intermediate.NotBefore, NotAfter: intermediate.NotAfter, IsCA: false, KeyUsage: x509.KeyUsageDigitalSignature, // set EKU to x509.ExtKeyUsageTimeStamping but with a critical bit ExtraExtensions: []pkix.Extension{ { Id: asn1.ObjectIdentifier{2, 5, 29, 37}, Critical: true, Value: timestampExt, }, }, } certDER, err := x509.CreateCertificate(rand.Reader, cert, intermediate, leafPubKey, intermediateSigner) if err != nil { return nil, fmt.Errorf("creating tsa certificate: %w", err) } leafCert, err := x509.ParseCertificate(certDER) if err != nil { return nil, fmt.Errorf("parsing leaf certificate: %w", err) } parsedCerts = append([]*x509.Certificate{leafCert}, parsedCerts...) return parsedCerts, 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 *leafKMSKey == "" && *tinkKeysetPath == "" { log.Fatal("either leaf-kms-resource or tink-keyset-path must be set") } if *tinkKeysetPath != "" && *tinkKmsKey == "" { log.Fatal("tink-keyset-path must be set with tink-kms-resource must be set") } if *outputPath == "" { log.Fatal("output must be set") } client, err := privateca.NewCertificateAuthorityClient(context.Background()) if err != nil { log.Fatal(err) } parsedCerts, err := fetchCertificateChain(context.Background(), *gcpCaParent, *intermediateKMSKey, *leafKMSKey, *tinkKeysetPath, *tinkKmsKey, client) if err != nil { log.Fatal(err) } pemCerts, err := cryptoutils.MarshalCertificatesToPEM(parsedCerts) if err != nil { log.Fatal(err) } err = os.WriteFile(*outputPath, pemCerts, 0600) if err != nil { log.Fatal(err) } } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/000077500000000000000000000000001470602636300254525ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/000077500000000000000000000000001470602636300262325ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/format/000077500000000000000000000000001470602636300275225ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/format/wrap.go000066400000000000000000000026751470602636300310340ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package format import ( "encoding/json" "fmt" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/spf13/cobra" "github.com/spf13/viper" ) type CobraCmd func(cmd *cobra.Command, args []string) type formatCmd func(args []string) (interface{}, error) func WrapCmd(f formatCmd) CobraCmd { return func(_ *cobra.Command, args []string) { obj, err := f(args) if err != nil { log.CliLogger.Fatal(err) } // TODO: add flags to control output formatting (JSON, plaintext, etc.) format := viper.GetString("format") switch format { case "default": if s, ok := obj.(fmt.Stringer); ok { fmt.Print(s.String()) } else { fmt.Println(toJSON(s)) } case "json": fmt.Println(toJSON(obj)) } } } func toJSON(i interface{}) string { b, err := json.Marshal(i) if err != nil { log.CliLogger.Fatal(err) } return string(b) } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/inspect.go000066400000000000000000000040271470602636300302310ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "fmt" "os" "path/filepath" "github.com/digitorus/timestamp" "github.com/sigstore/timestamp-authority/cmd/timestamp-cli/app/format" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/spf13/cobra" "github.com/spf13/viper" ) func addInspectFlags(cmd *cobra.Command) { cmd.Flags().Var(NewFlagValue(fileFlag, ""), "timestamp", "path to timestamp response to inspect") cmd.MarkFlagRequired("timestamp") //nolint:errcheck } type inspectCmdOutput struct { TimestampResponse timestamp.Timestamp } func (t *inspectCmdOutput) String() string { return fmt.Sprintf("%+v", t.TimestampResponse) } var inspectCmd = &cobra.Command{ Use: "inspect", Short: "Inspect timestamp", Long: "Inspect the signed timestamp response.", PreRunE: func(cmd *cobra.Command, _ []string) error { if err := viper.BindPFlags(cmd.Flags()); err != nil { log.CliLogger.Fatal("Error initializing cmd line args: ", err) } return nil }, Run: format.WrapCmd(func(_ []string) (interface{}, error) { 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) } ts, err := timestamp.ParseResponse(tsrBytes) if err != nil { return nil, err } return &inspectCmdOutput{ TimestampResponse: *ts, }, nil }), } func init() { initializePFlagMap() addInspectFlags(inspectCmd) rootCmd.AddCommand(inspectCmd) } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/pflags.go000066400000000000000000000111011470602636300300270ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "fmt" "log" "strings" "time" validator "github.com/go-playground/validator/v10" "github.com/pkg/errors" "github.com/spf13/pflag" ) type FlagType string const ( fileFlag FlagType = "file" urlFlag FlagType = "url" oidFlag FlagType = "oid" formatFlag FlagType = "format" timeoutFlag FlagType = "timeout" ) type newPFlagValueFunc func() pflag.Value var pflagValueFuncMap map[FlagType]newPFlagValueFunc // TODO: unit tests for all of this func initializePFlagMap() { pflagValueFuncMap = map[FlagType]newPFlagValueFunc{ fileFlag: func() pflag.Value { // this validates that the file exists and can be opened by the current uid return valueFactory(fileFlag, validateString("required,file"), "") }, urlFlag: func() pflag.Value { // this validates that the string is a valid http/https URL return valueFactory(urlFlag, validateString("required,url,startswith=http|startswith=https"), "") }, oidFlag: func() pflag.Value { // this validates for an OID, which is a sequence of positive integers separated by periods return valueFactory(oidFlag, validateOID, "") }, formatFlag: func() pflag.Value { // this validates the output format requested return valueFactory(formatFlag, validateString("required,oneof=json default"), "") }, timeoutFlag: func() pflag.Value { // this validates the timeout is >= 0 return valueFactory(formatFlag, validateTimeout, "") }, } } // NewFlagValue creates a new pflag.Value for the specified type with the specified default value. // If a default value is not desired, pass "" for defaultVal. func NewFlagValue(flagType FlagType, defaultVal string) pflag.Value { valFunc := pflagValueFuncMap[flagType] val := valFunc() if defaultVal != "" { if err := val.Set(defaultVal); err != nil { log.Fatal(errors.Wrap(err, "initializing flag")) } } return val } type validationFunc func(string) error func valueFactory(flagType FlagType, v validationFunc, defaultVal string) pflag.Value { return &baseValue{ flagType: flagType, validationFunc: v, value: defaultVal, } } // baseValue implements pflag.Value type baseValue struct { flagType FlagType value string validationFunc validationFunc } // Type returns the type of this Value func (b baseValue) Type() string { return string(b.flagType) } // String returns the string representation of this Value func (b baseValue) String() string { return b.value } // Set validates the provided string against the appropriate validation rule // for b.flagType; if the string validates, it is stored in the Value and nil is returned. // Otherwise the validation error is returned but the state of the Value is not changed. func (b *baseValue) Set(s string) error { if err := b.validationFunc(s); err != nil { return err } b.value = s return nil } // validateOID ensures that the supplied string is a valid ASN.1 object identifier func validateOID(v string) error { o := struct { Oid []string `validate:"dive,numeric"` }{strings.Split(v, ".")} return useValidator(oidFlag, o) } // validateTimeout ensures that the supplied string is a valid time.Duration value >= 0 func validateTimeout(v string) error { duration, err := time.ParseDuration(v) if err != nil { return err } d := struct { Duration time.Duration `validate:"min=0"` }{duration} return useValidator(timeoutFlag, d) } // validateString returns a function that validates an input string against the specified tag, // as defined in the format supported by go-playground/validator func validateString(tag string) validationFunc { return func(v string) error { validator := validator.New() return validator.Var(v, tag) } } // useValidator performs struct level validation on s as defined in the struct's tags using // the go-playground/validator library func useValidator(flagType FlagType, s interface{}) error { validate := validator.New() if err := validate.Struct(s); err != nil { return fmt.Errorf("error parsing %v flag: %w", flagType, err) } return nil } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/pflags_test.go000066400000000000000000000031021470602636300310700ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "testing" ) func TestValidateTimestampServerURL(t *testing.T) { type test struct { caseDesc string timestampServer string expectSuccess bool } tests := []test{ { caseDesc: "value not specified", expectSuccess: false, }, { caseDesc: "valid timestamp_server value", timestampServer: "http://localhost:3000", expectSuccess: true, }, { caseDesc: "valid URL, invalid scheme", timestampServer: "ldap://localhost:3000", expectSuccess: false, }, { caseDesc: "invalid URL", timestampServer: "hteeteepeeColonSlashSlashlocalhost:3000", expectSuccess: false, }, { caseDesc: "local path", timestampServer: "/localhost", expectSuccess: false, }, } for _, tc := range tests { if err := rootCmd.PersistentFlags().Set("timestamp_server", tc.timestampServer); (err == nil) != tc.expectSuccess { t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) } } } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/root.go000066400000000000000000000056421470602636300275530ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "fmt" "strings" homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" "sigs.k8s.io/release-utils/version" "github.com/sigstore/timestamp-authority/pkg/log" ) var rootCmd = &cobra.Command{ Use: "timestamp-cli", Short: "Timestamp CLI", Long: `Timestamp command line interface tool`, PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { return initConfig(cmd) }, } // Execute runs the base CLI func Execute() { if err := rootCmd.Execute(); err != nil { log.CliLogger.Fatal(err) } } func init() { initializePFlagMap() rootCmd.PersistentFlags().String("config", "", "config file (default is $HOME/.timestamp.yaml)") rootCmd.PersistentFlags().Var(NewFlagValue(urlFlag, "https://timestamp.sigstore.dev"), "timestamp_server", "Server host:port") rootCmd.PersistentFlags().Var(NewFlagValue(formatFlag, "default"), "format", "Command output format") rootCmd.PersistentFlags().Var(NewFlagValue(timeoutFlag, "30s"), "timeout", "HTTP timeout") // these are bound here and not in PreRun so that all child commands can use them if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { log.CliLogger.Fatal(err) } rootCmd.AddCommand(version.Version()) } func initConfig(cmd *cobra.Command) error { viper.SetEnvPrefix("timestamp") viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) viper.AutomaticEnv() // manually set all values provided from viper through pflag validation logic var changedFlags []string cmd.Flags().VisitAll(func(f *pflag.Flag) { if !f.Changed && viper.IsSet(f.Name) { changedFlags = append(changedFlags, f.Name) } }) for _, flag := range changedFlags { val := viper.Get(flag) if err := cmd.Flags().Set(flag, fmt.Sprintf("%v", val)); err != nil { return err } } if viper.GetString("config") != "" { viper.SetConfigFile(viper.GetString("config")) } else { // Find home directory. home, err := homedir.Dir() if err != nil { return err } viper.AddConfigPath(home) viper.SetConfigName(".timestamp") } if err := viper.ReadInConfig(); err != nil { switch err.(type) { case viper.ConfigFileNotFoundError: default: return err } } else if viper.GetString("format") == "default" { log.CliLogger.Infof("Using config file:", viper.ConfigFileUsed()) } return nil } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/timestamp.go000066400000000000000000000121021470602636300305600ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "bytes" "crypto" "errors" "fmt" "io" "os" "path/filepath" "strconv" "strings" "time" "github.com/digitorus/timestamp" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/timestamp-authority/cmd/timestamp-cli/app/format" "github.com/sigstore/timestamp-authority/pkg/client" ts "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/spf13/cobra" "github.com/spf13/viper" ) func addTimestampFlags(cmd *cobra.Command) { cmd.Flags().Var(NewFlagValue(fileFlag, ""), "artifact", "path to an artifact to timestamp") cmd.MarkFlagRequired("artifact") //nolint:errcheck cmd.Flags().String("hash", "sha256", "hash algorithm to use - Valid values are sha256, sha384, and sha512") cmd.Flags().Bool("nonce", true, "specify a pseudo-random nonce in the request") cmd.Flags().Bool("certificate", true, "if the timestamp response should contain a certificate chain") cmd.Flags().Var(NewFlagValue(oidFlag, ""), "tsa-policy", "optional dotted OID notation for the policy that the TSA should use to create the response") cmd.Flags().String("out", "response.tsr", "path to a file to write response.") } type timestampCmdOutput struct { Timestamp time.Time Location string } func (t *timestampCmdOutput) String() string { return fmt.Sprintf("Artifact timestamped at %s\nWrote timestamp response to %v\n", t.Timestamp, t.Location) } var timestampCmd = &cobra.Command{ Use: "timestamp", Short: "Signed timestamp command", Long: "Fetches a signed RFC 3161 timestamp. The timestamp response can be verified locally using a timestamp certificate chain.", PreRunE: func(cmd *cobra.Command, _ []string) error { if err := viper.BindPFlags(cmd.Flags()); err != nil { log.CliLogger.Fatal("Error initializing cmd line args: ", err) } return nil }, Run: format.WrapCmd(func(_ []string) (interface{}, error) { return runTimestamp() }), } func createRequestFromFlags() ([]byte, error) { artifactStr := viper.GetString("artifact") artifactBytes, err := os.ReadFile(filepath.Clean(artifactStr)) if err != nil { return nil, fmt.Errorf("error reading request from file: %w", err) } var hash crypto.Hash switch viper.GetString("hash") { case "sha256": hash = crypto.SHA256 case "sha384": hash = crypto.SHA384 case "sha512": hash = crypto.SHA512 default: return nil, errors.New("invalid hash algorithm - must be either sha256, sha384, or sha512") } reqOpts := ×tamp.RequestOptions{ Hash: hash, Certificates: viper.GetBool("certificate"), } if viper.GetBool("nonce") { nonce, err := cryptoutils.GenerateSerialNumber() if err != nil { return nil, err } reqOpts.Nonce = nonce } if policyStr := viper.GetString("tsa-policy"); policyStr != "" { var oidInts []int for _, v := range strings.Split(policyStr, ".") { i, _ := strconv.Atoi(v) oidInts = append(oidInts, i) } reqOpts.TSAPolicyOID = oidInts } return timestamp.CreateRequest(bytes.NewReader(artifactBytes), reqOpts) } func runTimestamp() (interface{}, error) { fmt.Println("Generating a new signed timestamp") // Set the Content-Type header to application/timestamp-query for the // request that will be made to the server. Since the server accepts // both application/timestamp-query and application/json as consumers for // the /api/v1/timestamp endpoint, we need to specify which one we want to use tsClient, err := client.GetTimestampClient(viper.GetString("timestamp_server"), client.WithUserAgent(UserAgent()), client.WithContentType(client.TimestampQueryMediaType)) if err != nil { return nil, err } requestBytes, err := createRequestFromFlags() if err != nil { return nil, err } params := ts.NewGetTimestampResponseParams() params.SetTimeout(viper.GetDuration("timeout")) params.Request = io.NopCloser(bytes.NewReader(requestBytes)) var respBytes bytes.Buffer _, err = tsClient.Timestamp.GetTimestampResponse(params, &respBytes) if err != nil { return nil, err } // validate that timestamp is parseable ts, err := timestamp.ParseResponse(respBytes.Bytes()) if err != nil { return nil, err } // Write response to file outStr := viper.GetString("out") if outStr == "" { outStr = "response.tsr" } if err := os.WriteFile(outStr, respBytes.Bytes(), 0600); err != nil { return nil, err } return ×tampCmdOutput{ Timestamp: ts.Time, Location: outStr, }, nil } func init() { initializePFlagMap() addTimestampFlags(timestampCmd) rootCmd.AddCommand(timestampCmd) } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/timestamp_test.go000066400000000000000000000054251470602636300316310ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "testing" "github.com/spf13/cobra" "github.com/spf13/viper" ) func TestTimestampFlags(t *testing.T) { type test struct { caseDesc string artifact string hash string oid string expectParseSuccess bool expectRequestSuccess bool } tests := []test{ { caseDesc: "valid local artifact", artifact: "timestamp.go", expectParseSuccess: true, expectRequestSuccess: true, }, { caseDesc: "nonexistant local artifact", artifact: "not_a_file", expectParseSuccess: false, expectRequestSuccess: false, }, { caseDesc: "valid local artifact with hash algorithm", artifact: "timestamp.go", hash: "sha512", expectParseSuccess: true, expectRequestSuccess: true, }, { caseDesc: "valid oid", artifact: "timestamp.go", oid: "1.2.3.4", expectParseSuccess: true, expectRequestSuccess: true, }, { caseDesc: "invalid oid", artifact: "timestamp.go", oid: "1.a.3.4", expectParseSuccess: false, expectRequestSuccess: true, }, { caseDesc: "no request or artifact specified", expectParseSuccess: true, expectRequestSuccess: false, }, } for _, tc := range tests { var blankCmd = &cobra.Command{} addTimestampFlags(blankCmd) args := []string{} if tc.artifact != "" { args = append(args, "--artifact", tc.artifact) } if tc.hash != "" { args = append(args, "--hash", tc.hash) } if tc.oid != "" { args = append(args, "--tsa-policy", tc.oid) } if err := blankCmd.ParseFlags(args); (err == nil) != tc.expectParseSuccess { t.Errorf("unexpected result parsing '%v': %v", tc.caseDesc, err) continue } if err := viper.BindPFlags(blankCmd.Flags()); err != nil { t.Fatalf("unexpected result initializing viper in '%v': %v", tc.caseDesc, err) } if _, err := createRequestFromFlags(); (err == nil) != tc.expectRequestSuccess { t.Errorf("unexpected result creating timestamp request '%v': %v", tc.caseDesc, err) continue } } } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/useragent.go000066400000000000000000000021311470602636300305530ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "fmt" "runtime" "sigs.k8s.io/release-utils/version" ) var ( // uaString is meant to resemble the User-Agent sent by browsers with requests. // See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent uaString = fmt.Sprintf("timestamp-cli/%s (%s; %s)", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH) ) // UserAgent returns the User-Agent string which `timestamp-cli` should send with HTTP requests. func UserAgent() string { return uaString } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/app/verify.go000066400000000000000000000217411470602636300300720ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "crypto/x509" "fmt" "math/big" "os" "path/filepath" "strconv" "strings" "github.com/digitorus/timestamp" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/timestamp-authority/cmd/timestamp-cli/app/format" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/sigstore/timestamp-authority/pkg/verification" "github.com/spf13/cobra" "github.com/spf13/viper" ) type verifyCmdOutput struct { TimestampPath string ParsedTimestamp timestamp.Timestamp } func (v *verifyCmdOutput) String() string { return fmt.Sprintf("Successfully verified timestamp %s", v.TimestampPath) } func addVerifyFlags(cmd *cobra.Command) { cmd.Flags().Var(NewFlagValue(fileFlag, ""), "artifact", "path to an blob with signed data") cmd.MarkFlagRequired("artifact") //nolint:errcheck cmd.Flags().Var(NewFlagValue(fileFlag, ""), "timestamp", "path to timestamp response to verify") cmd.MarkFlagRequired("timestamp") //nolint:errcheck cmd.Flags().Var(NewFlagValue(fileFlag, ""), "certificate-chain", "path to file with PEM-encoded certificate chain. Ordered from intermediate CA certificate that issued the TSA certificate, ending with the root CA certificate.") cmd.Flags().String("nonce", "", "optional nonce passed with the request") cmd.Flags().Var(NewFlagValue(oidFlag, ""), "oid", "optional TSA policy OID passed with the request") cmd.Flags().String("common-name", "", "expected leaf certificate subject common name") cmd.Flags().Var(NewFlagValue(fileFlag, ""), "certificate", "path to file with PEM-encoded leaf certificate") cmd.Flags().Var(NewFlagValue(fileFlag, ""), "intermediate-certificates", "path to file with PEM-encoded intermediate certificates. Must be called with the root-certificate flag.") cmd.Flags().Var(NewFlagValue(fileFlag, ""), "root-certificates", "path to file with a PEM-encoded root certificates. Optionally can be called with the intermediate-certificates flag.") } var verifyCmd = &cobra.Command{ Use: "verify", Short: "Verify timestamp", Long: "Verify the timestamp response using a timestamp certificate chain.", PreRunE: func(cmd *cobra.Command, _ []string) error { if err := viper.BindPFlags(cmd.Flags()); err != nil { log.CliLogger.Fatal("Error initializing cmd line args: ", err) } return nil }, Run: format.WrapCmd(func(_ []string) (interface{}, error) { return runVerify() }), } func runVerify() (interface{}, error) { tsrPath := viper.GetString("timestamp") tsrBytes, err := os.ReadFile(filepath.Clean(tsrPath)) if err != nil { return nil, fmt.Errorf("error reading request from file: %w", err) } artifactPath := viper.GetString("artifact") artifact, err := os.Open(filepath.Clean(artifactPath)) if err != nil { return nil, err } opts, err := newVerifyOpts() if err != nil { return verifyCmdOutput{TimestampPath: tsrPath}, fmt.Errorf("failed to created VerifyOpts: %w", err) } ts, err := verification.VerifyTimestampResponse(tsrBytes, artifact, opts) if err != nil { return verifyCmdOutput{TimestampPath: tsrPath}, fmt.Errorf("failed to verify timestamp: %w", err) } return &verifyCmdOutput{TimestampPath: tsrPath, ParsedTimestamp: *ts}, nil } func newVerifyOpts() (verification.VerifyOpts, error) { opts := verification.VerifyOpts{} oid, err := getOID() if err != nil { return verification.VerifyOpts{}, fmt.Errorf("failed to parse value from oid flag: %w", err) } opts.OID = oid certPathFlagVal := viper.GetString("certificate") if certPathFlagVal != "" { cert, err := parseTSACertificate(certPathFlagVal) if err != nil { return verification.VerifyOpts{}, fmt.Errorf("failed to parse cert flag value from PEM file: %w", err) } opts.TSACertificate = cert } roots, intermediates, err := getRootAndIntermediateCerts() if err != nil { return verification.VerifyOpts{}, fmt.Errorf("failed to parse root and intermediate certs from certificate-chain flag: %w", err) } opts.Roots = roots opts.Intermediates = intermediates nonce, err := getNonce() if err != nil { return verification.VerifyOpts{}, fmt.Errorf("failed to parse value from nonce flag: %w", err) } opts.Nonce = nonce commonNameFlagVal := viper.GetString("common-name") opts.CommonName = commonNameFlagVal return opts, nil } func getNonce() (*big.Int, error) { nonceFlagVal := viper.GetString("nonce") if nonceFlagVal == "" { return nil, nil } nonce := new(big.Int) nonce, ok := nonce.SetString(nonceFlagVal, 10) if !ok { return nil, fmt.Errorf("failed to convert string to big.Int") } return nonce, nil } func getRootAndIntermediateCerts() ([]*x509.Certificate, []*x509.Certificate, error) { certChainPEM := viper.GetString("certificate-chain") rootPEM := viper.GetString("root-certificates") intermediatePEM := viper.GetString("intermediate-certificates") // the verify flag must be called with either one of the two flag combinations: // 1. Called with the --root-certificates flag and optionally the --intermediate-certificates flag // 2. Called with only the --certificate-chain flag // this early exit if statement is only entered if neither of those combinations is valid 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") } // return root and intermediate certificates when they've been passed // together with the certificate-chain flag if certChainPEM != "" { pemBytes, err := os.ReadFile(filepath.Clean(certChainPEM)) if err != nil { return nil, nil, fmt.Errorf("error reading request from file: %w", err) } certs, err := cryptoutils.UnmarshalCertificatesFromPEM(pemBytes) if err != nil { return nil, nil, fmt.Errorf("failed to parse intermediate and root certs from PEM file: %w", err) } if len(certs) == 0 { return nil, nil, fmt.Errorf("expected at least one certificate to represent the root") } // intermediate certs are above the root certificate in the PEM file intermediateCerts := certs[0 : len(certs)-1] // the root certificate is last in the PEM file rootCerts := []*x509.Certificate{certs[len(certs)-1]} return rootCerts, intermediateCerts, nil } // return root and intermediate certificates when they've been passed // separately with the root-certificate and intermediate-certificates flags rootPEMBytes, err := os.ReadFile(filepath.Clean(rootPEM)) if err != nil { return nil, nil, fmt.Errorf("error reading request from file: %w", err) } rootCerts, err := cryptoutils.UnmarshalCertificatesFromPEM(rootPEMBytes) if err != nil { return nil, nil, fmt.Errorf("failed to parse intermediate and root certs from PEM file: %w", err) } if len(rootCerts) == 0 { return nil, nil, fmt.Errorf("expected at least one certificate to represent the root") } if intermediatePEM == "" { return rootCerts, []*x509.Certificate{}, nil } // parse intermediate certificates intermediatePEMBytes, err := os.ReadFile(filepath.Clean(intermediatePEM)) if err != nil { return nil, nil, fmt.Errorf("error reading request from file: %w", err) } intermediateCerts, err := cryptoutils.UnmarshalCertificatesFromPEM(intermediatePEMBytes) if err != nil { return nil, nil, fmt.Errorf("failed to parse intermediate and root certs from PEM file: %w", err) } if len(intermediateCerts) == 0 { return nil, nil, fmt.Errorf("expected at least one intermediate certificate") } return rootCerts, intermediateCerts, nil } func getOID() ([]int, error) { oidFlagVal := viper.GetString("oid") if oidFlagVal == "" { return nil, nil } oidStrSlice := strings.Split(oidFlagVal, ".") oid := make([]int, len(oidStrSlice)) for i, el := range oidStrSlice { intVar, err := strconv.Atoi(el) if err != nil { return nil, err } oid[i] = intVar } return oid, nil } func parseTSACertificate(certPath string) (*x509.Certificate, error) { pemBytes, err := os.ReadFile(filepath.Clean(certPath)) if err != nil { return nil, fmt.Errorf("error reading TSA's certificate file: %w", err) } certs, err := cryptoutils.UnmarshalCertificatesFromPEM(pemBytes) if err != nil { return nil, fmt.Errorf("failed to parse TSA certificate during verification: %w", err) } if len(certs) != 1 { return nil, fmt.Errorf("expected one certificate, received %d instead", len(certs)) } return certs[0], nil } func init() { initializePFlagMap() addVerifyFlags(verifyCmd) rootCmd.AddCommand(verifyCmd) } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-cli/main.go000066400000000000000000000013171470602636300267270ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import "github.com/sigstore/timestamp-authority/cmd/timestamp-cli/app" func main() { app.Execute() } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-server/000077500000000000000000000000001470602636300262115ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-server/app/000077500000000000000000000000001470602636300267715ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-server/app/root.go000066400000000000000000000112361470602636300303060ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "fmt" "os" homedir "github.com/mitchellh/go-homedir" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( cfgFile string logType string enablePprof bool httpPingOnly bool ) // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "timestamp-server", Short: "Timestamp authority service", Long: `Timestamp authority service that issues signed timestamps`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { if err := rootCmd.Execute(); err != nil { log.Logger.Error(err) os.Exit(1) } } func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.timestamp-server.yaml)") rootCmd.PersistentFlags().StringVar(&logType, "log-type", "dev", "logger type to use (dev/prod)") rootCmd.PersistentFlags().BoolVar(&enablePprof, "enable-pprof", false, "enable pprof for profiling on port 6060") 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.") // 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 rootCmd.PersistentFlags().String("tink-key-resource", "", "KMS key for signing timestamp responses for Tink keysets. Valid options include: [gcp-kms://resource, aws-kms://resource, hcvault://]") rootCmd.PersistentFlags().String("tink-keyset-path", "", "Path to KMS-encrypted keyset for Tink, decrypted by tink-key-resource") rootCmd.PersistentFlags().String("tink-hcvault-token", "", "Authentication token for Hashicorp Vault API calls") // KMS, Tink and File flags rootCmd.PersistentFlags().String("certificate-chain-path", "", "Path to PEM-encoded certificate chain certifying the kms-key-resource, tink-key-resource, or file-signer-key-path to act as a timestamping authority") // File flags rootCmd.PersistentFlags().String("file-signer-key-path", "", "Path to file containing PEM-encoded private key. Supported formats include PKCS#1, PKCS#8, and RFC5915 for EC") rootCmd.PersistentFlags().String("file-signer-passwd", "", "Password to decrypt private key") // NTP time introspection 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") if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { log.Logger.Fatal(err) } } // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { // Find home directory. home, err := homedir.Dir() if err != nil { fmt.Println(err) os.Exit(1) } viper.AddConfigPath(home) viper.AddConfigPath(".") viper.SetConfigName("timestamp-server") viper.SetConfigType("yaml") } viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { log.Logger.Infof("Using config file: %s", viper.ConfigFileUsed()) } } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-server/app/serve.go000066400000000000000000000067741470602636300304620ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package app import ( "flag" "net/http" "github.com/spf13/cobra" "github.com/spf13/viper" "sigs.k8s.io/release-utils/version" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/sigstore/timestamp-authority/pkg/ntpmonitor" "github.com/sigstore/timestamp-authority/pkg/server" ) // serveCmd represents the serve command var serveCmd = &cobra.Command{ Use: "serve", Short: "start http server with configured api", Long: `Starts a http server and serves the configured api`, Run: func(cmd *cobra.Command, _ []string) { if err := viper.BindPFlags(cmd.Flags()); err != nil { log.Logger.Fatal(err) } // Setup the logger to dev/prod log.ConfigureLogger(viper.GetString("log-type")) // workaround for https://github.com/sigstore/rekor/issues/68 // from https://github.com/golang/glog/commit/fca8c8854093a154ff1eb580aae10276ad6b1b5f _ = flag.CommandLine.Parse([]string{}) vi := version.GetVersionInfo() viStr, err := vi.JSONString() if err != nil { viStr = vi.String() } log.Logger.Infof("starting timestamp-server @ %v", viStr) // create the prometheus, pprof, and rest API servers readTimeout := viper.GetDuration("read-timeout") writeTimeout := viper.GetDuration("write-timeout") go func() { promServer := server.NewPrometheusServer(readTimeout, writeTimeout) if err := promServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Logger.Fatalf("error when starting or running http server for metrics: %v", err) } }() enablePprof := viper.GetBool("enable-pprof") log.Logger.Debugf("pprof enabled: %v", enablePprof) // Enable pprof if enablePprof { go func() { pprofServer := server.NewPprofServer(readTimeout, writeTimeout) if err := pprofServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Logger.Fatalf("error when starting or running http server for pprof: %v", err) } }() } var ntpm *ntpmonitor.NTPMonitor disableNTPMonitoring := viper.GetBool("disable-ntp-monitoring") if disableNTPMonitoring { log.Logger.Info("ntp monitoring disabled") } else { ntpMonitoring := viper.GetString("ntp-monitoring") if ntpMonitoring != "" { log.Logger.Infof("using custom ntp monitoring config: %s", ntpMonitoring) } go func() { ntpm, err = ntpmonitor.New(ntpMonitoring) if err != nil { log.Logger.Fatalf("error initializing ntp monitor %s", err) } ntpm.Start() }() } host := viper.GetString("host") port := int(viper.GetUint("port")) scheme := viper.GetStringSlice("scheme") server := server.NewRestAPIServer(host, port, scheme, httpPingOnly, readTimeout, writeTimeout) defer func() { if err := server.Shutdown(); err != nil { log.Logger.Error(err) } if ntpm != nil { ntpm.Stop() } }() if err := server.Serve(); err != nil { log.Logger.Fatal(err) } }, } func init() { rootCmd.AddCommand(serveCmd) rootCmd.AddCommand(version.Version()) } golang-github-sigstore-timestamp-authority-1.2.3/cmd/timestamp-server/main.go000066400000000000000000000013221470602636300274620ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import "github.com/sigstore/timestamp-authority/cmd/timestamp-server/app" func main() { app.Execute() } golang-github-sigstore-timestamp-authority-1.2.3/codecov.yml000066400000000000000000000011761470602636300243110ustar00rootroot00000000000000# Copyright 2023 The Sigstore Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. coverage: status: project: off patch: off golang-github-sigstore-timestamp-authority-1.2.3/docker-compose.yml000066400000000000000000000022041470602636300255720ustar00rootroot00000000000000# Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: '3.8' services: timestamp-server: build: context: . target: "deploy" command: [ "timestamp-server", "serve", "--host=0.0.0.0", "--port=3000", "--timestamp-signer=memory", # Uncomment this for production logging # "--log-type=prod", ] restart: always # keep the server running ports: - "3000:3000" - "2112:2112" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/ping"] interval: 10s timeout: 3s retries: 3 start_period: 5s golang-github-sigstore-timestamp-authority-1.2.3/docs/000077500000000000000000000000001470602636300230675ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/docs/tsa-policy.md000066400000000000000000001132701470602636300255010ustar00rootroot00000000000000# Abstract This document defines requirements for a baseline time-stamp policy for Time-Stamping Authorities (TSAs) issuing time-stamp tokens, supported by public key certificates, with an accuracy of one second or better. A TSA may define its own policy which enhances the policy defined in this document. Such a policy shall incorporate or further constrain the requirements identified in this document. # 1. Introduction The content of this RFC is based on [RFC 3628](https://datatracker.ietf.org/doc/html/rfc3628). The primary changes in this RFC are the removal of legal requirements, requirements to comply with the EU Directive, and requirements that specify the TSA will use on-premise hardware to manage the TSA primary key and service. In creating reliable and manageable digital evidence it is necessary to have an agreed upon method of associating time data to transaction so that they might be compared to each other at a later time. The quality of this evidence is based on creating and managing the data structure that represent the events and the quality of the parametric data points that anchor them to the real world. In this instance this being the time data and how it was applied. A typical transaction is a digitally signed document, where it is necessary to prove that the digital signature from the signer was applied when the signer's certificate was valid. A timestamp or a time mark (which is an audit record kept in a secure audit trail from a trusted third party) applied to a digital signature value proves that the digital signature was created before the date included in the time-stamp or time mark. To prove the digital signature was generated while the signer's certificate was valid, the digital signature must be verified and the following conditions satisfied: 1. the time-stamp (or time mark) was applied before the end of the validity period of the signer's certificate, 1. the time-stamp (or time mark) was applied either while the signer's certificate was not revoked or before the revocation date of the certificate. Thus a time-stamp (or time mark) applied in this manner proves that the digital signature was created while the signer's certificate was valid. This concept proves the validity of a digital signature over the whole of any certificate chain. Policy requirements to cover that case is the primary reason of this document. However, it should be observed that these policy requirements can be used to address other needs. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/html/bcp14), [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). # 2. Overview These policy requirements are aimed at time-stamping services used in support of qualified electronic signatures but may be applied to any application requiring to prove that a datum existed before a particular time. These policy requirements are based on the use of public key cryptography, public key certificates and reliable time sources. The present document may be used by independent bodies as the basis for confirming that a TSA may be trusted for providing time-stamping services. This document addresses requirements for synchronizing TSAs issuing time-stamp tokens with Coordinated universal time (UTC) and digitally signed by TSUs. Subscriber and relying parties should consult the TSA's practice statement to obtain further details of precisely how this time-stamp policy is implemented by the particular TSA (e.g., protocols used in providing this service). This document does not specify: - protocols used to access the TSUs; NOTE 1: A time-stamping protocol is defined in [RFC 3161](https://datatracker.ietf.org/doc/html/rfc3161) and profiled in [TS 101 861](https://www.etsi.org/deliver/etsi_ts/101800_101899/101861/01.04.01_60/ts_101861v010401p.pdf). - how the requirements identified herein may be assessed by an independent body; - requirements for information to be made available to such independent bodies; - requirements on such independent bodies. # 3. Definitions and Abbreviations ## 3.1. Definitions For the purposes of the present document, the following terms and definitions apply: - relying party: recipient of a time-stamp token who relies on that time-stamp token. - subscriber: entity requiring the services provided by a TSA and which has explicitly or implicitly agreed to its terms and conditions. - time-stamp token: data object that binds a representation of a datum to a particular time, thus establishing evidence that the datum existed before that time. - time-stamping authority: authority which issues time-stamp tokens. - TSA Disclosure statement: set of statements about the policies and practices of a TSA that particularly require emphasis or disclosure to subscribers and relying parties, for example to meet regulatory requirements. - TSA practice statement: statement of the practices that a TSA employs in issuing time-stamp tokens. - TSA system: composition of IT products and components organized to support the provision of time-stamping services. - time-stamp policy: named set of rules that indicates the applicability of a time-stamp token to a particular community and/or class of application with common security requirements. - time-stamping unit: set of hardware and software which is managed as a unit and has a single time-stamp token signing key active at a time. - Coordinated Universal Time (UTC): Time scale based on the second as defined in ITU-R Recommendation TF.460-5. NOTE: For most practical purposes UTC is equivalent to mean solar time at the prime meridian. More specifically, UTC is a compromise between the highly stable atomic time (Temps Atomique International - TAI) and solar time derived from the irregular Earth rotation (related to the Greenwich mean sidereal time (GMST) by a conventional relationship). - UTC(k): Time-scale realized by the laboratory "k" and kept in close agreement with UTC, with the goal to reach plus or minus 100 ns. (See ITU-R Recommendation TF.536-1. NOTE: A list of UTC(k) laboratories is given in section 1 of Circular T disseminated by BIPM and available from the BIPM website (http://www.bipm.org/). ## 3.2. Abbreviations For the purposes of the present document, the following abbreviations apply: - TSA Time-Stamping Authority - TSU Time-Stamping Unit - TST Time-Stamp Token - UTC Coordinated Universal Time # 4. General Concepts ## 4.1. Time-Stamping Services The provision of time-stamping services is broken down into the following component services for the purposes of classifying requirements: - Time-stamping provision: This service component generates time-stamp tokens. - Time-stamping management: The service component that monitors and controls the operation of the time-stamping services to ensure that the service is provided as specified by the TSA. This service component is responsible for the installation and de-installation of the time-stamping provision service. For example, time-stamping management ensures that the clock used for time-stamping is correctly synchronized with UTC. This subdivision of services is only for the purposes of clarifying the requirements specified in the current document and places no restrictions on any subdivision of an implementation of time-stamping services. ## 4.2. Time-Stamping Authority The authority to issue time-stamp tokens, trusted by the users of the time-stamping services, i.e., subscribers and relying parties, is called the Time-Stamping Authority (TSA). TSA has overall responsibility for time-stamping services identified in clause 4.1. The TSA has responsibility for the operation of one or more TSU's which creates and signs on behalf of the TSA. The TSA responsible for issuing a time-stamp token is identifiable (see 7.3.1 h). The TSA may delegate the signing of timestamps to a cloud key management service. However, the TSA always maintains overall responsibility and ensures that the policy requirements identified in the present document are met. A TSA may operate several identifiable time-stamping units. Each unit has a different key. A TSA is a certification-service-provider which issues time-stamp tokens. ## 4.3.Subscriber The subscriber may be an organization comprising several end-users or an individual end-user. When the subscriber is an organization, some of the obligations that apply to that organization will have to apply as well to the end-users. In any case the organization will be held responsible if the obligations from the end-users are not correctly fulfilled and therefore the organization is expected to suitably inform its end users. When the subscriber is an end-user, the end-user will be held directly responsible if its obligations are not correctly fulfilled. ## 4.4. Time-Stamp Policy and TSA Practice Statement This section explains the relative roles of Time-stamp policy and TSA practice statement. It places no restriction on the form of a time- stamp policy or practice statement specification. ### 4.4.1. Purpose In general, the time-stamp policy states "what is to be adhered to," while a TSA practice statement states "how it is adhered to", i.e., the processes it will use in creating time-stamps and maintaining the accuracy of its clock. The relationship between the time-stamp policy and TSA practice statement is similar in nature to the relationship of other business policies which state the requirements of the business, while operational units define the practices and procedures of how these policies are to be carried out. The present document specifies a time-stamp policy to meet general requirements for trusted time-stamping services. TSAs specify in TSA practice statements how these requirements are met. ### 4.4.2. Level of Specificity The TSA practice statement is more specific than a time-stamp policy. A TSA practice statement is a more detailed description of the terms and conditions as well as business and operational practices of a TSA in issuing and otherwise managing time-stamping services. The TSA practice statement of a TSA enforces the rules established by a time-stamp policy. A TSA practice statement defines how a specific TSA meets the technical, organizational and procedural requirements identified in a time-stamp policy. NOTE: Even lower-level internal documentation may be appropriate for a TSA detailing the specific procedures necessary to complete the practices identified in the TSA practice statement. ### 4.4.3. Approach The approach of a time-stamp policy is significantly different from a TSA practice statement. A time-stamp policy is defined independently of the specific details of the specific operating environment of a TSA, whereas a TSA practice statement is tailored to the organizational structure, operating procedures, facilities, and computing environment of a TSA. A time-stamp policy may be defined by the user of times-stamp services, whereas the TSA practice statement is always defined by the provider. # 5. Time-Stamp Policies ## 5.1. Overview A time-stamp policy is a "named set of rules that indicates the applicability of a time-stamp token to a particular community and/or class of application with common security requirements" (see clauses [3.1](#31-definitions) and [4.4](#44-time-stamp-policy-and-tsa-practice-statement)). The present document defines requirements for a baseline time-stamp policy for TSAs issuing time-stamp tokens, supported by public key certificates, with an accuracy of 1 second or better. NOTE 1: Without additional measures the relying party may not be able to ensure the validity of a time-stamp token beyond the end of the validity period of the supporting certificate. See Annex A on verification of the validity of a time-stamp token beyond the validity period of the TSU's certificate. A TSA may define its own policy which enhances the policy defined in this document. Such a policy shall incorporate or further constrain the requirements identified in this document. NOTE 1: It is required that a time-stamp token includes an identifier for the applicable policy (see section [7.3.1](#731-time-stamp-token)). ## 5.2. Identification The object-identifier X.208 of this time-stamp policy is `1.3.6.1.4.1.57264.2`. In the TSA disclosure statement made available to subscribers and relying parties, a TSA shall also include the identifier for the time-stamp policy to indicate its conformance. ## 5.3. User Community and Applicability This service aims to provide binary transparency. This policy may be used for public time-stamping services or time-stamping services used within a closed community. ## 5.4. Conformance The TSA shall use the identifier for the timestamp policy in timestamp tokens as given in section [5.2](#52-identification), or define its own time-stamp policy that incorporates or further constrains the requirements identified in the present document: - If the TSA claims conformance to the identified timestamp policy and makes available to subscribers and relying parties on request the evidence to support the claim of conformance; or - If the TSA has been assessed to conform to the identified timestamp policy by an independent party. A conformant TSA must demonstrate that: - It meets its obligations as defined in section [6.1](#61-tsa-obligation); - It has implemented controls which meet the requirements specified in section [7](#7-requirements-on-tsa-practices). # 6. Obligations and Liability ## 6.1. TSA Obligations ### 6.1.1. General The TSA shall ensure that all requirements on TSA, as detailed in section [7](#7-requirements-on-tsa-practices), are implemented as applicable to the selected trusted time-stamp policy. The TSA shall ensure conformance with the procedures prescribed in this policy, even when the TSA functionality is undertaken by subcontractors. The TSA shall also ensure adherence to any additional obligations indicated in the time-stamp either directly or incorporated by reference. The TSA shall provide all its time-stamping services consistent with its practice statement. ### 6.1.2. TSA Obligations Towards Subscribers The TSA shall meet its claims as given in its terms and conditions including the availability and accuracy of its service. ## 6.2. Subscriber Obligations The current document places no specific obligations on the subscriber beyond any TSA specific requirements stated in the TSA's terms and condition. NOTE: It is advisable that, when obtaining a time-stamp token, the subscriber verifies that the time-stamp token has been correctly signed and that the private key used to sign the time-stamp token has not been compromised. ## 6.3. Relying Party Obligations The terms and conditions made available to relying parties shall include an obligation on the relying party that, when relying on a time-stamp token, it shall: 1. verify that the time-stamp token has been correctly signed and that the private key used to sign the time-stamp has not been compromised until the time of the verification; NOTE: During the TSU's certificate validity period, the validity of the signing key can be checked using current revocation status for the TSU's certificate. If the time of verification exceeds the end of the validity period of the corresponding certificate, see annex A for guidance. 1. take into account any limitations on the usage of the time-stamp indicated by the time-stamp policy; 1. take into account any other precautions prescribed in agreements or elsewhere. # 7. Requirements on TSA Practices The TSA shall implement the controls that meet the following requirements. These policy requirements are not meant to imply any restrictions on charging for TSA services. The requirements are indicated in terms of the security objectives, followed by more specific requirements for controls to meet those objectives where it is necessary to provide confidence that those objective will be met. NOTE: The details of controls required to meet an objective is a balance between achieving the necessary confidence whilst minimizing the restrictions on the techniques that a TSA may employ in issuing time-stamp tokens. In the case of section [7.4](#74-tsa-management-and-operation) (TSA management and operation), a reference is made to a source of more detailed control requirements. Due to these factors the specificity of the requirements given under a given topic may vary. The provision of a time-stamp token in response to a request is at the discretion of the TSA depending on any service level agreements with the subscriber. ## 7.1. Practice and Disclosure Statements ### 7.1.1. TSA Practice Statement The TSA shall ensure that it demonstrates the reliability necessary for providing time-stamping services. In particular: 1. The TSA shall have a risk assessment carried out in order to evaluate business assets and threats to those assets in order to determine the necessary security controls and operational procedures. 1. The TSA shall have a statement of the practices and procedures used to address all the requirements identified in this time-stamp policy. - NOTE 1: This policy makes no requirement as to the structure of the TSA practice statement. 1. The TSA's practice statement shall identify the obligations of all external organizations supporting the TSA services including the applicable policies and practices. 1. The TSA may make available to subscribers and relying parties its practice statement, and other relevant documentation, as necessary, to assess conformance to the time-stamp policy. - NOTE 2: The TSA is not generally required to make all the details of its practices public. 1. Maintainers of the TSA shall have final authority for approving the TSA practice statement and ensuring that the practices are properly implemented. Maintainers shall also review any changes to the TSA to confirm that they follow the approved practice statement. 1. The TSA shall give due notice of changes it intends to make in its practice statement and shall, following approval as in (5) above, make the revised TSA practice statement immediately available as required under (4) above. ## 7.2. Key Management Life Cycle ### 7.2.1. TSA Key Generation The TSA shall ensure that any cryptographic keys are generated in under controlled circumstances. In particular: 1. The generation of the TSU's signing key(s) shall be undertaken by personnel in trusted roles. The personnel authorized to carry out this function shall be limited to those requiring to do so under the TSA's practices. 1. The generation of the TSU's signing key(s) shall be carried out in a secure environment. It MAY be carried out in a cloud based environment that protects the key. 1. The TSU key generation algorithm, the resulting signing key length and signature algorithm used for signing time-stamp tokens key shall be recognized by TSA maintainers as being fit for the purposes of time-stamp tokens as issued by the TSA. ### 7.2.2. TSU Private Key Protection The TSA shall ensure that TSU private keys remain confidential and maintain their integrity. The TSU private signing key shall be securely stored in one of the following: - HSM - Cloud environment - On-prem environment with controlled access ### 7.2.3. TSU Public Key Distribution The TSA shall ensure that the integrity and authenticity of the TSU signature verification (public) keys and any associated parameters are maintained during its distribution to relying parties. In particular: 1. TSU signature verification (public) keys shall be made available to relying parties in a public key certificate. NOTE: For example, TSU's certificates may be issued by a certification authority operated by the same organization as the TSA, or issued by another authority. 1. The TSU's signature verification (public) key certificate shall be issued by a certification authority operating under a certificate policy which provides a level of security equivalent to, or higher than, this time-stamping policy. ### 7.2.4. Rekeying TSU's Key The life-time of TSU's certificate shall be not longer than the period of time that the chosen algorithm and key length is recognized as being fit for purpose (see section [7.2.1c](#721-tsa-key-generation))). NOTE 1: The following additional considerations apply when limiting that lifetime: - Should a TSU private key be compromised, then the longer the life-time, the more affected time-stamp tokens there will be. NOTE 2: TSU key compromise does not only depend on the characteristics of the storage system being used but also on the procedures being used at system initialization and key export (when that function is supported). ### 7.2.5. End of TSU Key Life Cycle The TSA shall ensure that TSU private signing keys are not used beyond the end of their life cycle. In particular: 1. Operational or technical procedures shall be in place to ensure that a new key is put in place when a TSU's key expires. 1. The TSU private signing keys, or any key part, including any copies shall be destroyed such that the private keys cannot be retrieved. 1. The TST generation system SHALL reject any attempt to issue TSTs if the signing private key has expired. ### 7.2.6. Life Cycle Management of the Cryptographic Module used to Sign Time-Stamps The TSA shall use one of the following to host the token signing software: - HSM - Cloud environment - On-prem environment with controlled access ## 7.3. Time-Stamping ### 7.3.1. Time-Stamp Token The TSA shall ensure that time-stamp tokens are issued securely and include the correct time. In particular: 1. The time-stamp token shall include an identifier for the time-stamp policy. 1. Each time-stamp token shall have a unique identifier. 1. The time values the TSU uses in the time-stamp token shall be traceable to at least one of the real time values distributed by a UTC(k) laboratory. 1. The time-stamp provider should periodically monitor its correctness of time with a set of trusted UTC sources. The recorded accuracy should be included in the returned time-stamp token. 1. The time-stamp provider SHOULD monitor for accuracy and alert if it's found to be out of sync. 1. The time-stamp token shall include a representation (e.g., hash value) of the datum being time-stamped as provided by the requestor. 1. The time-stamp token shall be signed using a key generated exclusively for this purpose. NOTE 1: A protocol for a time-stamp token is defined in RFC 3631 and profiled in TS 101 861. NOTE 2: In the case of a number of requests at approximately the same time, the ordering of the time within the accuracy of the TSU clock is not mandated. 1. The time-stamp token shall include: - where applicable, an identifier for the country in which the TSA is established; - an identifier for the TSA; - an identifier for the unit which issues the time-stamps. ### 7.3.2. Clock Synchronization with UTC The TSA shall ensure that its clock is synchronized with UTC within the declared accuracy. In particular: 1. The calibration of the TSU clocks shall be maintained such that the clocks shall not be expected to drift outside the declared accuracy. 1. The TSA shall ensure that, if the time that would be indicated in a time-stamp token drifts or jumps out of synchronization with UTC, this will be detected (see also [7.3.1e](#731-time-stamp-token))). NOTE 1: Relying parties are required to be informed of such events (see section [7.4.8](#748-compromise-of-tsa-services)). 1. The TSA shall ensure that clock synchronization is maintained when a leap second occurs as notified by the appropriate body. The change to take account of the leap second shall occur during the last minute of the day when the leap second is scheduled to occur. NOTE 1: A leap second is an adjustment to UTC by skipping or adding an extra second on the last second of a UTC month. First preference is given to the end of December and June, and second preference is given to the end of March and September. ## 7.4. TSA Management and Operation ### 7.4.1. Security Management The TSA shall ensure that the administrative and management procedures applied are adequate and correspond to recognized best practice. In particular: TSA General 1. The TSA shall retain responsibility for all aspects of the provision of time-stamping services within the scope of this time-stamp policy, whether or not functions are outsourced to subcontractors. Responsibilities of third parties shall be clearly defined by the TSA and appropriate arrangements made to ensure that third parties are bound to implement any controls required by the TSA. The TSA shall retain responsibility for the disclosure of relevant practices of all parties. 1. The TSA management shall provide direction on information security through a suitable high level steering forum that is responsible for defining the TSA's information security policy. The TSA shall ensure publication and communication of this policy to all employees who are impacted by it. 1. The information security infrastructure necessary to manage the security within the TSA shall be maintained at all times. Any changes that will impact on the level of security provided shall be approved by the TSA management forum. 1. The security controls and operating procedures for TSA systems and information assets providing the time-stamping services shall be documented, implemented and maintained. NOTE 1: The present documentation (commonly called a system security policy or manual) should identify all relevant targets, objects and potential threats related to the services provided and the safeguards required to avoid or limit the effects of those threats. It should describe the rules, directives and procedures regarding how the specified services and the associated security assurance are granted in addition to stating policy on incidents and disasters. - TSA shall ensure that the security of information is maintained when the responsibility for TSA functions has been outsourced to another organization or entity. ### 7.4.2. Asset Classification and Management The TSA shall ensure that its information and other assets receive an appropriate level of protection. In particular: - The TSA shall maintain an inventory of all assets and shall assign a classification for the protection requirements to those assets consistent with the risk analysis. ### 7.4.3. Personnel Security The TSA shall follow the principle of least privilege and ensure that those working on the TSA only have the minimal privilege needed to perform functions. ### 7.4.4. Physical and Environmental Security Ths TSA will host the timestamping authority service and store private keys with either on-prem hardware or a trusted cloud provider. If the TSA uses a cloud provider to host the service and private key, it shall ensure it uses a provider that has appropriate physical security settings. For both the time-stamping provision and the time-stamping management: - The TSA shall only use cloud providers that control physical access to facilities that will host the timestamping authority service and private key; - The TSA shall implement controls to avoid loss, damage or compromise of assets and interruption to business activities; - controls shall be implemented to avoid compromise or theft of information. - The following additional controls shall be applied to time-stamping management: - The TSA shall ensure it uses a cloud provider that keeps infrastructure in an environment which physically protects the services from compromise through unauthorized access to systems or data. ### 7.4.5. Operations Management The TSA shall ensure that the TSA system components are secure and correctly operated, with minimal risk of failure. In particular (general): 1. The integrity of TSA system components and information shall be protected against viruses, malicious and unauthorized software. 1. Incident reporting and response procedures shall be employed in such a way that damage from security incidents and malfunctions shall be minimized. 1. Media used within the TSA trustworthy systems shall be securely handled to protect media from damage, theft, unauthorized access and obsolescence. NOTE 1: Every member of personnel with management responsibilities is responsible for planning and effectively implementing the time-stamp policy and associated practices as documented in the TSA practice statement. 1. Procedures shall be established and implemented for all trusted and administrative roles that impact on the provision of time-stamping services. Media handling and security: 1. All media shall be handled securely in accordance with requirements of the information classification scheme (see section [7.4.2](#742-asset-classification-and-management)). Media containing sensitive data shall be securely disposed of when no longer required. System Planning: 1. Capacity demands shall be monitored and projections of future capacity requirements made to ensure that adequate processing power and storage are available. Incident reporting and response: 1. The TSA shall act in a timely and coordinated manner in order to respond quickly to incidents and to limit the impact of breaches of security. All incidents shall be reported as soon as possible after the incident. The following additional controls shall be applied to time-stamping management: Operations procedures and responsibilities 1. TSA security operations shall be separated from other operations. NOTE 1: TSA security operations' responsibilities include: - operational procedures and responsibilities; - secure systems planning and acceptance; - protection from malicious software; - housekeeping; - network management; - active monitoring of audit journals, event analysis and follow-up; - media handling and security; - data and software exchange. These operations shall be managed by TSA trusted personnel, as defined within the appropriate security policy, and, roles and responsibility documents. ### 7.4.6. System Access Management The TSA shall ensure that TSA system access is limited to properly authorized individuals. In particular (general): 1. Controls (e.g., firewalls) shall be implemented to protect the TSA's internal network domains from unauthorized access including access by subscribers and third parties. NOTE: Firewalls should also be configured to prevent all protocols and accesses not required for the operation of the TSA. 1. The TSA shall ensure effective administration of user (this includes operators, administrators and auditors) access to maintain system security, including user account management, auditing and timely modification or removal of access. 1. The TSA shall ensure that access to information and application system functions is restricted in accordance with the access control policy and that the TSA system provides sufficient computer security controls for the separation of trusted roles identified in TSA's practices, including the separation of security administrator and operation functions. Particularly, use of system utility programs is restricted and tightly controlled. 1. TSA personnel shall be accountable for their activities The following additional controls shall be applied to time-stamping management: 1. The TSA shall ensure that it uses a cloud provider that keeps local network components (e.g., routers) in a physically secure environment. ### 7.4.7. Trustworthy Systems Deployment and Maintenance The TSA shall use trustworthy systems and products that are protected against modification. NOTE: The risk analysis carried out on the TSA's services (see section [7.1.1](#711-tsa-practice-statement)) should identify its critical services requiring trustworthy systems and the levels of assurance required. In particular: - An analysis of security requirements shall be carried out at the design and requirements specification stage of any systems development project undertaken by the TSA or on behalf of the TSA to ensure that security is built into IT systems. - Change control procedures shall be applied for releases, modifications and emergency software fixes of any operational software. ### 7.4.8. Compromise of TSA Services The TSA shall ensure in the case of events which affect the security of the TSA's services, including compromise of TSU's private signing keys or detected loss of calibration, that relevant information is made available to subscribers and relying parties. In particular: 1. The TSA's disaster recovery plan shall address the compromise or suspected compromise of TSU's private signing keys or loss of calibration of a TSU clock, which may have affected time-stamp tokens which have been issued. 1. In the case of a compromise, or suspected compromise or loss of calibration the TSA shall make available to all subscribers and relying parties a description of compromise that occurred. 1. In the case of compromise to a TSU's operation (e.g., TSU key compromise), suspected compromise or loss of calibration the TSU shall not issue time-stamp tokens until steps are taken to recover from the compromise. - In case of major compromise of the TSA's operation or loss of calibration, wherever possible, the TSA shall make available to all subscribers and relying parties information which may be used to identify the time-stamp tokens which may have been affected, unless this breaches the privacy of the TSAs users or the security of the TSA services. NOTE: In case the private key does become compromised, an audit trail of all tokens generated by the TSA may provide a means to discriminate between genuine and false backdated tokens. Two time-stamp tokens from two different TSAs may be another way to address this issue. ### 7.4.9. TSA Termination The TSA shall ensure that potential disruptions to subscribers and relying parties are minimized as a result of the cessation of the TSA's time-stamping services, and in particular ensure continued maintenance of information required to verify the correctness of time-stamp tokens. In particular: 1. Before the TSA terminates its time-stamping services the following procedures shall be executed as a minimum: - the TSA shall make available to all subscribers and relying parties information concerning its termination; - TSA shall terminate authorization of any outside services performing key singing - the TSA shall maintain or transfer to a reliable party its obligations to make available its public key or its certificates to relying parties for a reasonable period; - TSU private keys, including backup copies, shall be destroyed in a manner such that the private keys cannot be retrieved. 1. The TSA shall state in its practices the provisions made for termination of service. This shall include: - notification of affected entities; - transferring the TSA obligations to other parties. 1. The TSA shall take steps to have the TSU's certificates revoked. # 8. Security Considerations When verifying time-stamp tokens it is necessary for the verifier to ensure that the TSU certificate is trusted and not revoked. This means that the security is dependent upon the security of the CA that has issued the TSU certificate for both issuing the certificate and providing accurate revocation status information for that certificate. When a time-stamp is verified as valid at a given point of time, this does not mean that it will necessarily remain valid later on. Every time, a time-stamp token is verified during the validity period of the TSU certificate, it must be verified again against the current revocation status information, since in case of compromise of a TSU private key, all the time-stamp tokens generated by that TSU become invalid. Annex A provides guidance about the long term verification of time-stamp tokens. In applying time-stamping to applications, consideration also needs to be given to the security of the application. In particular, when applying time-stamps it is necessary to ensure that the integrity of data is maintained before the time-stamp is applied. The requester ought to really make sure that the hash value included in the time-stamp token matches with the hash of the data. # Annex A (informative): Long Term Verification of Time-Stamp Tokens Usually, a time-stamp token becomes unverifiable beyond the end of the validity period of the certificate from the TSU, because the CA that has issued the certificate does not warrant any more that it will publish revocation data, including data about revocations due to key compromises. However, verification of a time-stamp token might still be performed beyond the end of the validity period of the certificate from the TSU, if, at the time of verification, it can be known that: - the TSU private key has not been compromised at any time up to the time that a relying part verifies a time-stamp token; - the hash algorithms used in the time-stamp token exhibits no collisions at the time of verification; - the signature algorithm and signature key size under which the time-stamp token has been signed is still beyond the reach of cryptographic attacks at the time of verification. If these conditions cannot be met, then the validity may be maintained by applying an additional time-stamp to protect the integrity of the previous one. The present document does not specify the details of how such protection may be obtained. For the time being, and until some enhancements are defined to support these features, the information may be obtained using-out-of bands means or alternatively in the context of closed environments. As an example, should a CA guaranty to maintain the revocation status of TSU certificates after the end of its validity period, this would fulfill the first requirement. golang-github-sigstore-timestamp-authority-1.2.3/go.mod000066400000000000000000000173511470602636300232540ustar00rootroot00000000000000module github.com/sigstore/timestamp-authority go 1.23.1 require ( cloud.google.com/go/security v1.17.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 github.com/go-chi/chi v4.1.2+incompatible github.com/go-openapi/errors v0.22.0 github.com/go-openapi/loads v0.22.0 github.com/go-openapi/runtime v0.28.0 github.com/go-openapi/spec v0.21.0 github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.0 github.com/go-playground/validator/v10 v10.22.1 github.com/golang/protobuf v1.5.4 github.com/google/go-cmp v0.6.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.19.1 github.com/rs/cors v1.11.1 github.com/sigstore/sigstore v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.9 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/urfave/negroni v1.0.0 go.step.sm/crypto v0.51.1 go.uber.org/zap v1.27.0 golang.org/x/net v0.28.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 sigs.k8s.io/release-utils v0.8.5 ) require ( cloud.google.com/go v0.115.1 // indirect cloud.google.com/go/auth v0.9.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/iam v1.1.13 // indirect cloud.google.com/go/kms v1.19.0 // indirect cloud.google.com/go/longrunning v0.5.12 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.31 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.30 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.35.5 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect github.com/aws/smithy-go v1.20.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 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/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-jose/go-jose/v4 v4.0.2 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect 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/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-containerregistry v0.20.2 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // 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 github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/vault/api v1.14.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jellydator/ttlcache/v3 v3.3.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // 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.7.7 // 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/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // 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/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // 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.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/trace v1.28.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.6.0 // indirect google.golang.org/api v0.195.0 // indirect google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c // indirect google.golang.org/grpc v1.65.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) golang-github-sigstore-timestamp-authority-1.2.3/go.sum000066400000000000000000001311771470602636300233040ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w= cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4= cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus= cloud.google.com/go/kms v1.19.0 h1:x0OVJDl6UH1BSX4THKlMfdcFWoE4ruh90ZHuilZekrU= cloud.google.com/go/kms v1.19.0/go.mod h1:e4imokuPJUc17Trz2s6lEXFDt8bgDmvpVynH39bdrHM= cloud.google.com/go/longrunning v0.5.12 h1:5LqSIdERr71CqfUsFlJdBpOkBH8FBCFD7P1nTWy3TYE= cloud.google.com/go/longrunning v0.5.12/go.mod h1:S5hMV8CDJ6r50t2ubVJSKQVv5u0rmik5//KgLO3k4lU= cloud.google.com/go/security v1.17.5 h1:FzjVVdJKgfHmDt1gsecHehVewA0wLuruHvA1g4o5k4c= cloud.google.com/go/security v1.17.5/go.mod h1:MA8w7SbQAQO9CQ9r0R7HR0F7g1AJoqx87SFLpapq3OU= 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.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= 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/security/keyvault/azkeys v1.1.0 h1:DRiANoJTiW6obBQe3SqZizkuV1PEgfiiGivmVocDy64= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0/go.mod h1:qLIye2hwb/ZouqhpSD9Zn3SJipvpEnz1Ywl3VUk9Y0s= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/kms v1.35.5 h1:XUomV7SiclZl1QuXORdGcfFqHxEHET7rmNGtxTfNB+M= github.com/aws/aws-sdk-go-v2/service/kms v1.35.5/go.mod h1:A5CS0VRmxxj2YKYLCY08l/Zzbd01m6JZn0WzxgT1OCA= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho= github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= 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.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE= github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I= github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 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/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 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.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= 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/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= 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.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= 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= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU= github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 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/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 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/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/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.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA= github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= github.com/sigstore/sigstore v1.8.9 h1:NiUZIVWywgYuVTxXmRoTT4O4QAGiTEKup4N1wdxFadk= github.com/sigstore/sigstore v1.8.9/go.mod h1:d9ZAbNDs8JJfxJrYmulaTazU3Pwr8uLL9+mii4BNR3w= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9 h1:tgpdvjyoEgYFeTBFe4MHvBKsG+J4E7NVtstChIExVT8= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9/go.mod h1:wCz6cAZKL/wFumDHX9l8VkVITS2GntrOfs2j/kwH4wo= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.9 h1:eXFm3cte0hvxxYsvGpCMd7aBusEgKJdlUw1Fb5AZQpw= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.9/go.mod h1:RYy9GKnFKKwqbg3Uc6rUyhQdichSVkFlfxnY6f7cAWc= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9 h1:liWcl12dfFeQXU0JemQVgdVQx02Fls9UPdrFzVrCWhs= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9/go.mod h1:Ckx62auqPQvNJWRBAboY+/kHs77gy6L33b6UtB/FB5U= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.9 h1:E+bvFTS6uM//iSAeneNj5pubzntQmio/yAKFzmRzzD0= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.9/go.mod h1:0RKVuZXIZAFhT0frfx+GzyrtlesiRK3ceF55nIgkZI4= 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/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.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/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/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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.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/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= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.step.sm/crypto v0.51.1 h1:ktUg/2hetEMiBAqgz502ktZDGoDoGrcHFg3XpkmkvvA= go.step.sm/crypto v0.51.1/go.mod h1:PdrhttNU/tG9/YsVd4fdlysBN+UV503p0o2irFZQlAw= 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.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.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.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= 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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU= google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok= google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c h1:Kqjm4WpoWvwhMPcrAczoTyMySQmYa9Wy2iL6Con4zn8= google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= sigs.k8s.io/release-utils v0.8.5 h1:FUtFqEAN621gSXv0L7kHyWruBeS7TUU9aWf76olX7uQ= sigs.k8s.io/release-utils v0.8.5/go.mod h1:qsm5bdxdgoHkD8HsXpgme2/c3mdsNaiV53Sz2HmKeJA= golang-github-sigstore-timestamp-authority-1.2.3/hack/000077500000000000000000000000001470602636300230455ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/hack/tools/000077500000000000000000000000001470602636300242055ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/hack/tools/go.mod000066400000000000000000000054101470602636300253130ustar00rootroot00000000000000module github.com/sigstore/timestamp-authority/hack/tools go 1.22 require github.com/go-swagger/go-swagger v0.31.0 require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/inflect v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/loads v0.22.0 // indirect github.com/go-openapi/runtime v0.28.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/jessevdk/go-flags v1.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.18.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect 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.23.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/tools v0.21.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 ) golang-github-sigstore-timestamp-authority-1.2.3/hack/tools/go.sum000066400000000000000000000376731470602636300253600ustar00rootroot00000000000000github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= 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= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 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/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= 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/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 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.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= 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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.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/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.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= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.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= 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.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= 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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/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= golang-github-sigstore-timestamp-authority-1.2.3/hack/tools/tools.go000066400000000000000000000014601470602636300256750ustar00rootroot00000000000000//go:build tools // +build tools // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This package imports things required by build scripts, to force `go mod` to see them as dependencies package tools import ( _ "github.com/go-swagger/go-swagger/cmd/swagger" ) golang-github-sigstore-timestamp-authority-1.2.3/openapi.yaml000066400000000000000000000055721470602636300244670ustar00rootroot00000000000000# # Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. swagger: "2.0" info: title: Timestamp Authority description: Timestamp Authority provides an RFC3161 timestamp authority. version: 0.0.1 host: timestamp.sigstore.dev schemes: - http paths: /api/v1/timestamp: post: summary: Generates a new timestamp response and creates a new log entry for the timestamp in the transparency log operationId: getTimestampResponse tags: - timestamp consumes: - application/timestamp-query - application/json produces: - application/timestamp-reply parameters: - in: body name: request required: true schema: type: string format: binary responses: 201: description: Returns a timestamp response and the location of the log entry in the transprency log schema: type: string format: binary 400: $ref: '#/responses/BadContent' 501: $ref: '#/responses/NotImplemented' default: $ref: '#/responses/InternalServerError' /api/v1/timestamp/certchain: get: summary: Retrieve the certificate chain for timestamping that can be used to validate trusted timestamps description: Returns the certificate chain for timestamping that can be used to validate trusted timestamps operationId: getTimestampCertChain tags: - timestamp consumes: - application/json produces: - application/pem-certificate-chain responses: 200: description: The PEM encoded cert chain schema: type: string 404: $ref: '#/responses/NotFound' default: $ref: '#/responses/InternalServerError' definitions: Error: type: object properties: code: type: integer message: type: string responses: BadContent: description: The content supplied to the server was invalid schema: $ref: "#/definitions/Error" NotFound: description: The content requested could not be found NotImplemented: description: The content requested is not implemented InternalServerError: description: There was an internal error in the server while processing the request schema: $ref: "#/definitions/Error" golang-github-sigstore-timestamp-authority-1.2.3/pkg/000077500000000000000000000000001470602636300227205ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/api/000077500000000000000000000000001470602636300234715ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/api/api.go000066400000000000000000000060511470602636300245730ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "bytes" "context" "crypto" "crypto/x509" "fmt" "os" "path/filepath" "github.com/pkg/errors" "github.com/spf13/viper" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/timestamp-authority/pkg/log" "github.com/sigstore/timestamp-authority/pkg/signer" tsx509 "github.com/sigstore/timestamp-authority/pkg/x509" ) type API struct { tsaSigner crypto.Signer // the signer to use for timestamping tsaSignerHash crypto.Hash // hash algorithm used to hash pre-signed timestamps certChain []*x509.Certificate // timestamping cert chain certChainPem string // PEM encoded timestamping cert chain } func NewAPI() (*API, error) { ctx := context.Background() tsaSignerHash, err := signer.HashToAlg(viper.GetString("timestamp-signer-hash")) if err != nil { return nil, errors.Wrap(err, "error getting hash") } tsaSigner, err := signer.NewCryptoSigner(ctx, tsaSignerHash, viper.GetString("timestamp-signer"), viper.GetString("kms-key-resource"), viper.GetString("tink-key-resource"), viper.GetString("tink-keyset-path"), viper.GetString("tink-hcvault-token"), viper.GetString("file-signer-key-path"), viper.GetString("file-signer-passwd")) if err != nil { return nil, errors.Wrap(err, "getting new tsa signer") } var certChain []*x509.Certificate // KMS, Tink and File signers require a provided certificate chain if viper.GetString("timestamp-signer") != signer.MemoryScheme { certChainPath := viper.GetString("certificate-chain-path") data, err := os.ReadFile(filepath.Clean(certChainPath)) if err != nil { return nil, err } certChain, err = cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(data)) if err != nil { return nil, err } if err := tsx509.VerifyCertChain(certChain, tsaSigner); err != nil { return nil, err } } else { // Generate an in-memory TSA certificate chain certChain, err = signer.NewTimestampingCertWithChain(tsaSigner) if err != nil { return nil, errors.Wrap(err, "generating timestamping cert chain") } } certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(certChain) if err != nil { return nil, fmt.Errorf("marshal certificates to PEM: %w", err) } return &API{ tsaSigner: tsaSigner, tsaSignerHash: tsaSignerHash, certChain: certChain, certChainPem: string(certChainPEM), }, nil } var ( api *API ) func ConfigureAPI() { var err error api, err = NewAPI() if err != nil { log.Logger.Panic(err) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/api/error.go000066400000000000000000000054501470602636300251550ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "fmt" "net/http" "regexp" "github.com/go-openapi/runtime/middleware" "github.com/mitchellh/mapstructure" "github.com/sigstore/timestamp-authority/pkg/generated/models" "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations/timestamp" "github.com/sigstore/timestamp-authority/pkg/log" ) const ( failedToGenerateTimestampResponse = "Error generating timestamp response" WeakHashAlgorithmTimestampRequest = "Weak hash algorithm in timestamp request" ) func errorMsg(message string, code int) *models.Error { return &models.Error{ Code: int64(code), Message: message, } } func handleTimestampAPIError(params interface{}, code int, err error, message string, fields ...interface{}) middleware.Responder { if message == "" { message = http.StatusText(code) } re := regexp.MustCompile("^(.*)Params$") typeStr := fmt.Sprintf("%T", params) handler := re.FindStringSubmatch(typeStr)[1] logMsg := func(r *http.Request) { log.RequestIDLogger(r).Errorw("exiting with error", append([]interface{}{"handler", handler, "statusCode", code, "clientMessage", message, "error", err}, fields...)...) paramsFields := map[string]interface{}{} if err := mapstructure.Decode(params, ¶msFields); err == nil { log.RequestIDLogger(r).Debug(paramsFields) } } switch params := params.(type) { case timestamp.GetTimestampResponseParams: logMsg(params.HTTPRequest) switch code { case http.StatusBadRequest: return timestamp.NewGetTimestampResponseBadRequest().WithPayload(errorMsg(message, code)) case http.StatusNotImplemented: return timestamp.NewGetTimestampResponseNotImplemented() default: return timestamp.NewGetTimestampResponseDefault(code).WithPayload(errorMsg(message, code)) } case timestamp.GetTimestampCertChainParams: logMsg(params.HTTPRequest) switch code { case http.StatusNotFound: return timestamp.NewGetTimestampCertChainNotFound() default: return timestamp.NewGetTimestampCertChainDefault(code).WithPayload(errorMsg(message, code)) } default: log.Logger.Errorf("unable to find method for type %T; error: %v", params, err) return middleware.Error(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/api/metrics.go000066400000000000000000000054161470602636300254740ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "sigs.k8s.io/release-utils/version" ) var ( MetricLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "timestamp_authority_api_latency", Help: "API Latency on calls", }, []string{"path", "code"}) MetricLatencySummary = promauto.NewSummaryVec(prometheus.SummaryOpts{ Name: "timestamp_authority_api_latency_summary", Help: "API Latency on calls", }, []string{"path", "code"}) MetricRequestLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "timestamp_authority_latency_by_api", Help: "API Latency (in ns) by path and method", Buckets: prometheus.ExponentialBucketsRange( float64(time.Millisecond), float64(4*time.Second), 10), }, []string{"path", "method"}) MetricRequestCount = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "timestamp_authority_http_requests_total", Help: "Total number of HTTP requests by status code, path, and method.", }, []string{"code", "path", "method"}) MetricNTPLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "timestamp_authority_ntp_latency", Help: "NTP request latency", }, []string{"host"}) MetricNTPSyncCount = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "timestamp_authority_ntp_sync_total", Help: "Total number of NTP requests against a remote server", }, []string{"host", "failed"}) MetricNTPErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "timestamp_authority_ntp_errors_total", Help: "Total number of NTP related errors", }, []string{"reason"}) _ = promauto.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: "timestamp_authority", Name: "build_info", Help: "A metric with a constant '1' value labeled by version, revision, branch, and goversion from which timestamp-authority was built.", ConstLabels: prometheus.Labels{ "version": version.GetVersionInfo().GitVersion, "revision": version.GetVersionInfo().GitCommit, "build_date": version.GetVersionInfo().BuildDate, "goversion": version.GetVersionInfo().GoVersion, }, }, func() float64 { return 1 }, ) ) golang-github-sigstore-timestamp-authority-1.2.3/pkg/api/timestamp.go000066400000000000000000000133661470602636300260340ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "bytes" "crypto" "encoding/asn1" "encoding/base64" "encoding/json" "fmt" "io" "math/big" "net/http" "strconv" "strings" "time" "github.com/digitorus/timestamp" "github.com/go-openapi/runtime/middleware" "github.com/pkg/errors" ts "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations/timestamp" "github.com/sigstore/timestamp-authority/pkg/verification" ) type JSONRequest struct { ArtifactHash string `json:"artifactHash"` Certificates bool `json:"certificates"` HashAlgorithm string `json:"hashAlgorithm"` Nonce *big.Int `json:"nonce"` TSAPolicyOID string `json:"tsaPolicyOID"` } func getHashAlg(alg string) (crypto.Hash, string, error) { lowercaseAlg := strings.ToLower(alg) switch lowercaseAlg { case "sha256": return crypto.SHA256, "", nil case "sha384": return crypto.SHA384, "", nil case "sha512": return crypto.SHA512, "", nil case "sha1": return 0, WeakHashAlgorithmTimestampRequest, verification.ErrWeakHashAlg default: return 0, failedToGenerateTimestampResponse, fmt.Errorf("unsupported hash algorithm: %s", alg) } } // ParseJSONRequest parses a JSON request into a timestamp.Request struct func ParseJSONRequest(reqBytes []byte) (*timestamp.Request, string, error) { // unmarshal the request bytes into a JSONRequest struct var req JSONRequest if err := json.Unmarshal(reqBytes, &req); err != nil { return nil, failedToGenerateTimestampResponse, fmt.Errorf("failed to parse JSON into request: %v", err) } // after unmarshalling, parse the JSONRequest.Artifact into a Reader and parse the remaining // fields into a a timestamp.RequestOptions struct hashAlgo, errMsg, err := getHashAlg(req.HashAlgorithm) if err != nil { return nil, errMsg, fmt.Errorf("failed to parse hash algorithm: %v", err) } var oidInts []int if req.TSAPolicyOID == "" { oidInts = nil } else { for _, v := range strings.Split(req.TSAPolicyOID, ".") { i, _ := strconv.Atoi(v) oidInts = append(oidInts, i) } } // decode the base64 encoded artifact hash decoded, err := base64.StdEncoding.DecodeString(req.ArtifactHash) if err != nil { return nil, failedToGenerateTimestampResponse, fmt.Errorf("failed to decode base64 encoded artifact hash: %v", err) } // create a timestamp request from the request's JSON body tsReq := timestamp.Request{ HashAlgorithm: hashAlgo, HashedMessage: decoded, Certificates: req.Certificates, Nonce: req.Nonce, TSAPolicyOID: oidInts, } return &tsReq, "", nil } func parseDERRequest(reqBytes []byte) (*timestamp.Request, string, error) { parsed, err := timestamp.ParseRequest(reqBytes) if err != nil { 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 } func getContentType(r *http.Request) (string, error) { contentTypeHeader := r.Header.Get("Content-Type") splitHeader := strings.Split(contentTypeHeader, "application/") if len(splitHeader) != 2 { return "", errors.New("expected header value to be split into two pieces") } return splitHeader[1], nil } func requestBodyToTimestampReq(reqBytes []byte, contentType string) (*timestamp.Request, string, error) { switch contentType { case "json": return ParseJSONRequest(reqBytes) case "timestamp-query": return parseDERRequest(reqBytes) default: return nil, failedToGenerateTimestampResponse, fmt.Errorf("unsupported content type") } } func TimestampResponseHandler(params ts.GetTimestampResponseParams) middleware.Responder { requestBytes, err := io.ReadAll(params.Request) if err != nil { return handleTimestampAPIError(params, http.StatusBadRequest, err, failedToGenerateTimestampResponse) } contentType, err := getContentType(params.HTTPRequest) if err != nil { return handleTimestampAPIError(params, http.StatusUnsupportedMediaType, err, failedToGenerateTimestampResponse) } req, errMsg, err := requestBodyToTimestampReq(requestBytes, contentType) if err != nil { return handleTimestampAPIError(params, http.StatusBadRequest, err, errMsg) } policyID := req.TSAPolicyOID if policyID.String() == "" { policyID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} } duration, _ := time.ParseDuration("1s") tsStruct := timestamp.Timestamp{ HashAlgorithm: req.HashAlgorithm, HashedMessage: req.HashedMessage, Time: time.Now(), Nonce: req.Nonce, Policy: policyID, Ordering: false, Accuracy: duration, // Not qualified for the european directive Qualified: false, AddTSACertificate: req.Certificates, ExtraExtensions: req.Extensions, } resp, err := tsStruct.CreateResponseWithOpts(api.certChain[0], api.tsaSigner, api.tsaSignerHash) if err != nil { return handleTimestampAPIError(params, http.StatusInternalServerError, err, failedToGenerateTimestampResponse) } return ts.NewGetTimestampResponseCreated().WithPayload(io.NopCloser(bytes.NewReader(resp))) } func GetTimestampCertChainHandler(_ ts.GetTimestampCertChainParams) middleware.Responder { return ts.NewGetTimestampCertChainOK().WithPayload(api.certChainPem) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/000077500000000000000000000000001470602636300241765ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/mock/000077500000000000000000000000001470602636300251275ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/mock/mock_tsa_client.go000066400000000000000000000106041470602636300306150ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package mock import ( "bytes" "crypto" "crypto/elliptic" "crypto/rand" "crypto/x509" "encoding/asn1" "fmt" "io" "time" "github.com/go-openapi/runtime" "github.com/pkg/errors" "github.com/digitorus/timestamp" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/timestamp-authority/pkg/generated/client" ts "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp" "github.com/sigstore/timestamp-authority/pkg/signer" ) // TSAClient creates RFC3161 timestamps and implements client.TimestampAuthority. // Messages to sign can either be provided in the initializer or through the request. // Time can be provided in the initializer, or defaults to time.Now(). // All other timestamp parameters are hardcoded. type TSAClient struct { Signer crypto.Signer CertChain []*x509.Certificate CertChainPEM string Time time.Time Message []byte } // TSAClientOptions provide customization for the mock TSA client. type TSAClientOptions struct { // Time is an optional timestamp. Default is time.Now(). Time time.Time // Message is the pre-hashed message to sign over, typically a raw signature. Message []byte // Signer is an optional signer created out of band. Client creates one if not set. Signer crypto.Signer } func NewTSAClient(o TSAClientOptions) (*client.TimestampAuthority, error) { sv := o.Signer if sv == nil { var err error sv, _, err = signature.NewECDSASignerVerifier(elliptic.P256(), rand.Reader, crypto.SHA256) if err != nil { return nil, err } } certChain, err := signer.NewTimestampingCertWithChain(sv) if err != nil { return nil, errors.Wrap(err, "generating timestamping cert chain") } certChainPEM, err := cryptoutils.MarshalCertificatesToPEM(certChain) if err != nil { return nil, fmt.Errorf("marshal certificates to PEM: %w", err) } return &client.TimestampAuthority{ Timestamp: &TSAClient{ Signer: sv, CertChain: certChain, CertChainPEM: string(certChainPEM), Time: o.Time, Message: o.Message, }, }, nil } func (c *TSAClient) GetTimestampCertChain(_ *ts.GetTimestampCertChainParams, _ ...ts.ClientOption) (*ts.GetTimestampCertChainOK, error) { return &ts.GetTimestampCertChainOK{Payload: c.CertChainPEM}, nil } func (c *TSAClient) GetTimestampResponse(params *ts.GetTimestampResponseParams, w io.Writer, _ ...ts.ClientOption) (*ts.GetTimestampResponseCreated, error) { var hashAlg crypto.Hash var hashedMessage []byte if params.Request != nil { requestBytes, err := io.ReadAll(params.Request) if err != nil { return nil, err } req, err := timestamp.ParseRequest(requestBytes) if err != nil { return nil, err } hashAlg = req.HashAlgorithm hashedMessage = req.HashedMessage } else { hashAlg = crypto.SHA256 h := hashAlg.New() h.Write(c.Message) hashedMessage = h.Sum(nil) } nonce, err := cryptoutils.GenerateSerialNumber() if err != nil { return nil, err } duration, _ := time.ParseDuration("1s") tsStruct := timestamp.Timestamp{ HashAlgorithm: hashAlg, HashedMessage: hashedMessage, Nonce: nonce, Policy: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2}, Ordering: false, Accuracy: duration, Qualified: false, AddTSACertificate: true, } if c.Time.IsZero() { tsStruct.Time = time.Now() } else { tsStruct.Time = c.Time } resp, err := tsStruct.CreateResponseWithOpts(c.CertChain[0], c.Signer, crypto.SHA256) if err != nil { return nil, err } // write response to provided buffer and payload if w != nil { _, err := w.Write(resp) if err != nil { return nil, err } } return &ts.GetTimestampResponseCreated{Payload: bytes.NewBuffer(resp)}, nil } func (c *TSAClient) SetTransport(_ runtime.ClientTransport) { // nothing to do } golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/options.go000066400000000000000000000041251470602636300262220ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import "net/http" const ( TimestampQueryMediaType = "application/timestamp-query" JSONMediaType = "application/json" ) // Option is a functional option for customizing static signatures. type Option func(*options) type options struct { UserAgent string ContentType string } func makeOptions(opts ...Option) *options { o := &options{ UserAgent: "", ContentType: "", } for _, opt := range opts { opt(o) } return o } // WithUserAgent sets the media type of the signature. func WithUserAgent(userAgent string) Option { return func(o *options) { o.UserAgent = userAgent } } // WithContentType sets the content type of the request. func WithContentType(contentType string) Option { return func(o *options) { o.ContentType = contentType } } type roundTripper struct { http.RoundTripper UserAgent string ContentType string } // RoundTrip implements `http.RoundTripper` func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { req.Header.Set("User-Agent", rt.UserAgent) req.Header.Set("Content-Type", rt.ContentType) return rt.RoundTripper.RoundTrip(req) } func createRoundTripper(inner http.RoundTripper, o *options) http.RoundTripper { if inner == nil { inner = http.DefaultTransport } if o.UserAgent == "" { // There's nothing to do... return inner } if o.ContentType == "" { // There's nothing to do... return inner } return &roundTripper{ RoundTripper: inner, UserAgent: o.UserAgent, ContentType: o.ContentType, } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/options_test.go000066400000000000000000000057621470602636300272710ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "net/http" "testing" "github.com/google/go-cmp/cmp" ) func TestMakeOptions(t *testing.T) { tests := []struct { desc string opts []Option want *options }{{ desc: "no opts", want: &options{}, }, { desc: "WithUserAgent", opts: []Option{WithUserAgent("test user agent")}, want: &options{UserAgent: "test user agent"}, }} for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { got := makeOptions(tc.opts...) if d := cmp.Diff(tc.want, got); d != "" { t.Errorf("makeOptions() returned unexpected result (-want +got): %s", d) } }) } } type mockRoundTripper struct { gotReqs []*http.Request resp *http.Response err error } // RoundTrip implements `http.RoundTripper` func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { m.gotReqs = append(m.gotReqs, req) return m.resp, m.err } func TestCreateRoundTripper(t *testing.T) { t.Run("always returns non-nil", func(t *testing.T) { got := createRoundTripper(nil, &options{}) if got == nil { t.Errorf("createRoundTripper() should never return a nil `http.RoundTripper`") } }) testReq, err := http.NewRequest("GET", "http://www.example.com/test", nil) if err != nil { t.Fatalf("http.NewRequest() failed: %v", err) } testResp := &http.Response{ Status: "OK", StatusCode: 200, Request: testReq, } expectedUserAgent := "test UserAgent" expectedContentType := "test ContentType" m := &mockRoundTripper{} rt := createRoundTripper(m, &options{ UserAgent: expectedUserAgent, ContentType: expectedContentType, }) m.resp = testResp gotResp, err := rt.RoundTrip(testReq) if err != nil { t.Errorf("RoundTrip() returned error: %v", err) } if len(m.gotReqs) < 1 { t.Fatalf("inner RoundTripper.RoundTrip() was not called") } gotReq := m.gotReqs[0] gotReqUserAgent := gotReq.UserAgent() if gotReqUserAgent != expectedUserAgent { t.Errorf("rt.RoundTrip() did not set the User-Agent properly. Wanted: %q, got: %q", expectedUserAgent, gotReqUserAgent) } gotReqContentType := gotReq.Header.Get("Content-Type") if gotReqContentType != expectedContentType { t.Errorf("rt.RoundTrip() did not set the Content-Type properly. Wanted: %q, got: %q", expectedContentType, gotReqContentType) } if testResp != gotResp { t.Errorf("roundTripper.RoundTrip() should have returned exactly the response of the inner RoundTripper. Wanted %v, got %v", testResp, gotResp) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/timestamp_client.go000066400000000000000000000031341470602636300300670ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "net/url" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" "github.com/sigstore/timestamp-authority/pkg/generated/client" ) func GetTimestampClient(timestampServerURL string, opts ...Option) (*client.TimestampAuthority, error) { url, err := url.Parse(timestampServerURL) if err != nil { return nil, err } o := makeOptions(opts...) rt := httptransport.New(url.Host, client.DefaultBasePath, []string{url.Scheme}) // Input to server rt.Producers["application/timestamp-query"] = runtime.ByteStreamProducer() rt.Producers["application/json"] = runtime.JSONProducer() // Output from server rt.Consumers["application/timestamp-reply"] = runtime.ByteStreamConsumer() rt.Consumers["application/json"] = runtime.JSONConsumer() rt.Consumers["application/pem-certificate-chain"] = runtime.TextConsumer() rt.Transport = createRoundTripper(rt.Transport, o) registry := strfmt.Default return client.New(rt, registry), nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/client/timestamp_client_test.go000066400000000000000000000037661470602636300311410ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package client import ( "net/http" "net/http/httptest" "testing" ) func TestGetTimestampClientWithOptions(t *testing.T) { t.Parallel() expectedUserAgent := "test User-Agent" expectedContentType := "application/timestamp-query" requestReceived := false testServer := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { file := []byte{} got := r.UserAgent() if got != expectedUserAgent { w.WriteHeader(http.StatusInternalServerError) return } var expectedAccept string if r.URL.Path == "/api/v1/timestamp/certchain" { expectedAccept = "application/pem-certificate-chain" } else if r.URL.Path == "/api/v1/timestamp" { expectedAccept = "application/timestamp-reply" } accept := r.Header["Accept"][0] if accept != expectedAccept { w.WriteHeader(http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) _, _ = w.Write(file) requestReceived = true })) defer testServer.Close() client, err := GetTimestampClient(testServer.URL, WithUserAgent(expectedUserAgent), WithContentType(expectedContentType)) if err != nil { t.Error(err) } _, _ = client.Timestamp.GetTimestampCertChain(nil) if !requestReceived { t.Fatal("no requests were received") } // reset requestReceived = false _, _ = client.Timestamp.GetTimestampResponse(nil, nil) if !requestReceived { t.Fatal("no requests were received") } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/000077500000000000000000000000001470602636300246565ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/000077500000000000000000000000001470602636300261345ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp/000077500000000000000000000000001470602636300301375ustar00rootroot00000000000000get_timestamp_cert_chain_parameters.go000066400000000000000000000111521470602636300376530ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "context" "net/http" "time" "github.com/go-openapi/errors" "github.com/go-openapi/runtime" cr "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" ) // NewGetTimestampCertChainParams creates a new GetTimestampCertChainParams object, // with the default timeout for this client. // // Default values are not hydrated, since defaults are normally applied by the API server side. // // To enforce default values in parameter, use SetDefaults or WithDefaults. func NewGetTimestampCertChainParams() *GetTimestampCertChainParams { return &GetTimestampCertChainParams{ timeout: cr.DefaultTimeout, } } // NewGetTimestampCertChainParamsWithTimeout creates a new GetTimestampCertChainParams object // with the ability to set a timeout on a request. func NewGetTimestampCertChainParamsWithTimeout(timeout time.Duration) *GetTimestampCertChainParams { return &GetTimestampCertChainParams{ timeout: timeout, } } // NewGetTimestampCertChainParamsWithContext creates a new GetTimestampCertChainParams object // with the ability to set a context for a request. func NewGetTimestampCertChainParamsWithContext(ctx context.Context) *GetTimestampCertChainParams { return &GetTimestampCertChainParams{ Context: ctx, } } // NewGetTimestampCertChainParamsWithHTTPClient creates a new GetTimestampCertChainParams object // with the ability to set a custom HTTPClient for a request. func NewGetTimestampCertChainParamsWithHTTPClient(client *http.Client) *GetTimestampCertChainParams { return &GetTimestampCertChainParams{ HTTPClient: client, } } /* GetTimestampCertChainParams contains all the parameters to send to the API endpoint for the get timestamp cert chain operation. Typically these are written to a http.Request. */ type GetTimestampCertChainParams struct { timeout time.Duration Context context.Context HTTPClient *http.Client } // WithDefaults hydrates default values in the get timestamp cert chain params (not the query body). // // All values with no default are reset to their zero value. func (o *GetTimestampCertChainParams) WithDefaults() *GetTimestampCertChainParams { o.SetDefaults() return o } // SetDefaults hydrates default values in the get timestamp cert chain params (not the query body). // // All values with no default are reset to their zero value. func (o *GetTimestampCertChainParams) SetDefaults() { // no default values defined for this parameter } // WithTimeout adds the timeout to the get timestamp cert chain params func (o *GetTimestampCertChainParams) WithTimeout(timeout time.Duration) *GetTimestampCertChainParams { o.SetTimeout(timeout) return o } // SetTimeout adds the timeout to the get timestamp cert chain params func (o *GetTimestampCertChainParams) SetTimeout(timeout time.Duration) { o.timeout = timeout } // WithContext adds the context to the get timestamp cert chain params func (o *GetTimestampCertChainParams) WithContext(ctx context.Context) *GetTimestampCertChainParams { o.SetContext(ctx) return o } // SetContext adds the context to the get timestamp cert chain params func (o *GetTimestampCertChainParams) SetContext(ctx context.Context) { o.Context = ctx } // WithHTTPClient adds the HTTPClient to the get timestamp cert chain params func (o *GetTimestampCertChainParams) WithHTTPClient(client *http.Client) *GetTimestampCertChainParams { o.SetHTTPClient(client) return o } // SetHTTPClient adds the HTTPClient to the get timestamp cert chain params func (o *GetTimestampCertChainParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } // WriteToRequest writes these params to a swagger request func (o *GetTimestampCertChainParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { if err := r.SetTimeout(o.timeout); err != nil { return err } var res []error if len(res) > 0 { return errors.CompositeValidationError(res...) } return nil } get_timestamp_cert_chain_responses.go000066400000000000000000000205521470602636300375350ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "encoding/json" "fmt" "io" "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/sigstore/timestamp-authority/pkg/generated/models" ) // GetTimestampCertChainReader is a Reader for the GetTimestampCertChain structure. type GetTimestampCertChainReader struct { formats strfmt.Registry } // ReadResponse reads a server response into the received o. func (o *GetTimestampCertChainReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { switch response.Code() { case 200: result := NewGetTimestampCertChainOK() if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } return result, nil case 404: result := NewGetTimestampCertChainNotFound() if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } return nil, result default: result := NewGetTimestampCertChainDefault(response.Code()) if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } if response.Code()/100 == 2 { return result, nil } return nil, result } } // NewGetTimestampCertChainOK creates a GetTimestampCertChainOK with default headers values func NewGetTimestampCertChainOK() *GetTimestampCertChainOK { return &GetTimestampCertChainOK{} } /* GetTimestampCertChainOK describes a response with status code 200, with default header values. The PEM encoded cert chain */ type GetTimestampCertChainOK struct { Payload string } // IsSuccess returns true when this get timestamp cert chain o k response has a 2xx status code func (o *GetTimestampCertChainOK) IsSuccess() bool { return true } // IsRedirect returns true when this get timestamp cert chain o k response has a 3xx status code func (o *GetTimestampCertChainOK) IsRedirect() bool { return false } // IsClientError returns true when this get timestamp cert chain o k response has a 4xx status code func (o *GetTimestampCertChainOK) IsClientError() bool { return false } // IsServerError returns true when this get timestamp cert chain o k response has a 5xx status code func (o *GetTimestampCertChainOK) IsServerError() bool { return false } // IsCode returns true when this get timestamp cert chain o k response a status code equal to that given func (o *GetTimestampCertChainOK) IsCode(code int) bool { return code == 200 } // Code gets the status code for the get timestamp cert chain o k response func (o *GetTimestampCertChainOK) Code() int { return 200 } func (o *GetTimestampCertChainOK) Error() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[GET /api/v1/timestamp/certchain][%d] getTimestampCertChainOK %s", 200, payload) } func (o *GetTimestampCertChainOK) String() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[GET /api/v1/timestamp/certchain][%d] getTimestampCertChainOK %s", 200, payload) } func (o *GetTimestampCertChainOK) GetPayload() string { return o.Payload } func (o *GetTimestampCertChainOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { // response payload if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF { return err } return nil } // NewGetTimestampCertChainNotFound creates a GetTimestampCertChainNotFound with default headers values func NewGetTimestampCertChainNotFound() *GetTimestampCertChainNotFound { return &GetTimestampCertChainNotFound{} } /* GetTimestampCertChainNotFound describes a response with status code 404, with default header values. The content requested could not be found */ type GetTimestampCertChainNotFound struct { } // IsSuccess returns true when this get timestamp cert chain not found response has a 2xx status code func (o *GetTimestampCertChainNotFound) IsSuccess() bool { return false } // IsRedirect returns true when this get timestamp cert chain not found response has a 3xx status code func (o *GetTimestampCertChainNotFound) IsRedirect() bool { return false } // IsClientError returns true when this get timestamp cert chain not found response has a 4xx status code func (o *GetTimestampCertChainNotFound) IsClientError() bool { return true } // IsServerError returns true when this get timestamp cert chain not found response has a 5xx status code func (o *GetTimestampCertChainNotFound) IsServerError() bool { return false } // IsCode returns true when this get timestamp cert chain not found response a status code equal to that given func (o *GetTimestampCertChainNotFound) IsCode(code int) bool { return code == 404 } // Code gets the status code for the get timestamp cert chain not found response func (o *GetTimestampCertChainNotFound) Code() int { return 404 } func (o *GetTimestampCertChainNotFound) Error() string { return fmt.Sprintf("[GET /api/v1/timestamp/certchain][%d] getTimestampCertChainNotFound", 404) } func (o *GetTimestampCertChainNotFound) String() string { return fmt.Sprintf("[GET /api/v1/timestamp/certchain][%d] getTimestampCertChainNotFound", 404) } func (o *GetTimestampCertChainNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { return nil } // NewGetTimestampCertChainDefault creates a GetTimestampCertChainDefault with default headers values func NewGetTimestampCertChainDefault(code int) *GetTimestampCertChainDefault { return &GetTimestampCertChainDefault{ _statusCode: code, } } /* GetTimestampCertChainDefault describes a response with status code -1, with default header values. There was an internal error in the server while processing the request */ type GetTimestampCertChainDefault struct { _statusCode int Payload *models.Error } // IsSuccess returns true when this get timestamp cert chain default response has a 2xx status code func (o *GetTimestampCertChainDefault) IsSuccess() bool { return o._statusCode/100 == 2 } // IsRedirect returns true when this get timestamp cert chain default response has a 3xx status code func (o *GetTimestampCertChainDefault) IsRedirect() bool { return o._statusCode/100 == 3 } // IsClientError returns true when this get timestamp cert chain default response has a 4xx status code func (o *GetTimestampCertChainDefault) IsClientError() bool { return o._statusCode/100 == 4 } // IsServerError returns true when this get timestamp cert chain default response has a 5xx status code func (o *GetTimestampCertChainDefault) IsServerError() bool { return o._statusCode/100 == 5 } // IsCode returns true when this get timestamp cert chain default response a status code equal to that given func (o *GetTimestampCertChainDefault) IsCode(code int) bool { return o._statusCode == code } // Code gets the status code for the get timestamp cert chain default response func (o *GetTimestampCertChainDefault) Code() int { return o._statusCode } func (o *GetTimestampCertChainDefault) Error() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[GET /api/v1/timestamp/certchain][%d] getTimestampCertChain default %s", o._statusCode, payload) } func (o *GetTimestampCertChainDefault) String() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[GET /api/v1/timestamp/certchain][%d] getTimestampCertChain default %s", o._statusCode, payload) } func (o *GetTimestampCertChainDefault) GetPayload() *models.Error { return o.Payload } func (o *GetTimestampCertChainDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { o.Payload = new(models.Error) // response payload if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { return err } return nil } get_timestamp_response_parameters.go000066400000000000000000000121141470602636300374110ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "context" "io" "net/http" "time" "github.com/go-openapi/errors" "github.com/go-openapi/runtime" cr "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" ) // NewGetTimestampResponseParams creates a new GetTimestampResponseParams object, // with the default timeout for this client. // // Default values are not hydrated, since defaults are normally applied by the API server side. // // To enforce default values in parameter, use SetDefaults or WithDefaults. func NewGetTimestampResponseParams() *GetTimestampResponseParams { return &GetTimestampResponseParams{ timeout: cr.DefaultTimeout, } } // NewGetTimestampResponseParamsWithTimeout creates a new GetTimestampResponseParams object // with the ability to set a timeout on a request. func NewGetTimestampResponseParamsWithTimeout(timeout time.Duration) *GetTimestampResponseParams { return &GetTimestampResponseParams{ timeout: timeout, } } // NewGetTimestampResponseParamsWithContext creates a new GetTimestampResponseParams object // with the ability to set a context for a request. func NewGetTimestampResponseParamsWithContext(ctx context.Context) *GetTimestampResponseParams { return &GetTimestampResponseParams{ Context: ctx, } } // NewGetTimestampResponseParamsWithHTTPClient creates a new GetTimestampResponseParams object // with the ability to set a custom HTTPClient for a request. func NewGetTimestampResponseParamsWithHTTPClient(client *http.Client) *GetTimestampResponseParams { return &GetTimestampResponseParams{ HTTPClient: client, } } /* GetTimestampResponseParams contains all the parameters to send to the API endpoint for the get timestamp response operation. Typically these are written to a http.Request. */ type GetTimestampResponseParams struct { // Request. // // Format: binary Request io.ReadCloser timeout time.Duration Context context.Context HTTPClient *http.Client } // WithDefaults hydrates default values in the get timestamp response params (not the query body). // // All values with no default are reset to their zero value. func (o *GetTimestampResponseParams) WithDefaults() *GetTimestampResponseParams { o.SetDefaults() return o } // SetDefaults hydrates default values in the get timestamp response params (not the query body). // // All values with no default are reset to their zero value. func (o *GetTimestampResponseParams) SetDefaults() { // no default values defined for this parameter } // WithTimeout adds the timeout to the get timestamp response params func (o *GetTimestampResponseParams) WithTimeout(timeout time.Duration) *GetTimestampResponseParams { o.SetTimeout(timeout) return o } // SetTimeout adds the timeout to the get timestamp response params func (o *GetTimestampResponseParams) SetTimeout(timeout time.Duration) { o.timeout = timeout } // WithContext adds the context to the get timestamp response params func (o *GetTimestampResponseParams) WithContext(ctx context.Context) *GetTimestampResponseParams { o.SetContext(ctx) return o } // SetContext adds the context to the get timestamp response params func (o *GetTimestampResponseParams) SetContext(ctx context.Context) { o.Context = ctx } // WithHTTPClient adds the HTTPClient to the get timestamp response params func (o *GetTimestampResponseParams) WithHTTPClient(client *http.Client) *GetTimestampResponseParams { o.SetHTTPClient(client) return o } // SetHTTPClient adds the HTTPClient to the get timestamp response params func (o *GetTimestampResponseParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } // WithRequest adds the request to the get timestamp response params func (o *GetTimestampResponseParams) WithRequest(request io.ReadCloser) *GetTimestampResponseParams { o.SetRequest(request) return o } // SetRequest adds the request to the get timestamp response params func (o *GetTimestampResponseParams) SetRequest(request io.ReadCloser) { o.Request = request } // WriteToRequest writes these params to a swagger request func (o *GetTimestampResponseParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { if err := r.SetTimeout(o.timeout); err != nil { return err } var res []error if o.Request != nil { if err := r.SetBodyParam(o.Request); err != nil { return err } } if len(res) > 0 { return errors.CompositeValidationError(res...) } return nil } get_timestamp_response_responses.go000066400000000000000000000257351470602636300373040ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "encoding/json" "fmt" "io" "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/sigstore/timestamp-authority/pkg/generated/models" ) // GetTimestampResponseReader is a Reader for the GetTimestampResponse structure. type GetTimestampResponseReader struct { formats strfmt.Registry writer io.Writer } // ReadResponse reads a server response into the received o. func (o *GetTimestampResponseReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { switch response.Code() { case 201: result := NewGetTimestampResponseCreated(o.writer) if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } return result, nil case 400: result := NewGetTimestampResponseBadRequest() if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } return nil, result case 501: result := NewGetTimestampResponseNotImplemented() if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } return nil, result default: result := NewGetTimestampResponseDefault(response.Code()) if err := result.readResponse(response, consumer, o.formats); err != nil { return nil, err } if response.Code()/100 == 2 { return result, nil } return nil, result } } // NewGetTimestampResponseCreated creates a GetTimestampResponseCreated with default headers values func NewGetTimestampResponseCreated(writer io.Writer) *GetTimestampResponseCreated { return &GetTimestampResponseCreated{ Payload: writer, } } /* GetTimestampResponseCreated describes a response with status code 201, with default header values. Returns a timestamp response and the location of the log entry in the transprency log */ type GetTimestampResponseCreated struct { Payload io.Writer } // IsSuccess returns true when this get timestamp response created response has a 2xx status code func (o *GetTimestampResponseCreated) IsSuccess() bool { return true } // IsRedirect returns true when this get timestamp response created response has a 3xx status code func (o *GetTimestampResponseCreated) IsRedirect() bool { return false } // IsClientError returns true when this get timestamp response created response has a 4xx status code func (o *GetTimestampResponseCreated) IsClientError() bool { return false } // IsServerError returns true when this get timestamp response created response has a 5xx status code func (o *GetTimestampResponseCreated) IsServerError() bool { return false } // IsCode returns true when this get timestamp response created response a status code equal to that given func (o *GetTimestampResponseCreated) IsCode(code int) bool { return code == 201 } // Code gets the status code for the get timestamp response created response func (o *GetTimestampResponseCreated) Code() int { return 201 } func (o *GetTimestampResponseCreated) Error() string { return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponseCreated", 201) } func (o *GetTimestampResponseCreated) String() string { return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponseCreated", 201) } func (o *GetTimestampResponseCreated) GetPayload() io.Writer { return o.Payload } func (o *GetTimestampResponseCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { // response payload if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { return err } return nil } // NewGetTimestampResponseBadRequest creates a GetTimestampResponseBadRequest with default headers values func NewGetTimestampResponseBadRequest() *GetTimestampResponseBadRequest { return &GetTimestampResponseBadRequest{} } /* GetTimestampResponseBadRequest describes a response with status code 400, with default header values. The content supplied to the server was invalid */ type GetTimestampResponseBadRequest struct { Payload *models.Error } // IsSuccess returns true when this get timestamp response bad request response has a 2xx status code func (o *GetTimestampResponseBadRequest) IsSuccess() bool { return false } // IsRedirect returns true when this get timestamp response bad request response has a 3xx status code func (o *GetTimestampResponseBadRequest) IsRedirect() bool { return false } // IsClientError returns true when this get timestamp response bad request response has a 4xx status code func (o *GetTimestampResponseBadRequest) IsClientError() bool { return true } // IsServerError returns true when this get timestamp response bad request response has a 5xx status code func (o *GetTimestampResponseBadRequest) IsServerError() bool { return false } // IsCode returns true when this get timestamp response bad request response a status code equal to that given func (o *GetTimestampResponseBadRequest) IsCode(code int) bool { return code == 400 } // Code gets the status code for the get timestamp response bad request response func (o *GetTimestampResponseBadRequest) Code() int { return 400 } func (o *GetTimestampResponseBadRequest) Error() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponseBadRequest %s", 400, payload) } func (o *GetTimestampResponseBadRequest) String() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponseBadRequest %s", 400, payload) } func (o *GetTimestampResponseBadRequest) GetPayload() *models.Error { return o.Payload } func (o *GetTimestampResponseBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { o.Payload = new(models.Error) // response payload if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { return err } return nil } // NewGetTimestampResponseNotImplemented creates a GetTimestampResponseNotImplemented with default headers values func NewGetTimestampResponseNotImplemented() *GetTimestampResponseNotImplemented { return &GetTimestampResponseNotImplemented{} } /* GetTimestampResponseNotImplemented describes a response with status code 501, with default header values. The content requested is not implemented */ type GetTimestampResponseNotImplemented struct { } // IsSuccess returns true when this get timestamp response not implemented response has a 2xx status code func (o *GetTimestampResponseNotImplemented) IsSuccess() bool { return false } // IsRedirect returns true when this get timestamp response not implemented response has a 3xx status code func (o *GetTimestampResponseNotImplemented) IsRedirect() bool { return false } // IsClientError returns true when this get timestamp response not implemented response has a 4xx status code func (o *GetTimestampResponseNotImplemented) IsClientError() bool { return false } // IsServerError returns true when this get timestamp response not implemented response has a 5xx status code func (o *GetTimestampResponseNotImplemented) IsServerError() bool { return true } // IsCode returns true when this get timestamp response not implemented response a status code equal to that given func (o *GetTimestampResponseNotImplemented) IsCode(code int) bool { return code == 501 } // Code gets the status code for the get timestamp response not implemented response func (o *GetTimestampResponseNotImplemented) Code() int { return 501 } func (o *GetTimestampResponseNotImplemented) Error() string { return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponseNotImplemented", 501) } func (o *GetTimestampResponseNotImplemented) String() string { return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponseNotImplemented", 501) } func (o *GetTimestampResponseNotImplemented) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { return nil } // NewGetTimestampResponseDefault creates a GetTimestampResponseDefault with default headers values func NewGetTimestampResponseDefault(code int) *GetTimestampResponseDefault { return &GetTimestampResponseDefault{ _statusCode: code, } } /* GetTimestampResponseDefault describes a response with status code -1, with default header values. There was an internal error in the server while processing the request */ type GetTimestampResponseDefault struct { _statusCode int Payload *models.Error } // IsSuccess returns true when this get timestamp response default response has a 2xx status code func (o *GetTimestampResponseDefault) IsSuccess() bool { return o._statusCode/100 == 2 } // IsRedirect returns true when this get timestamp response default response has a 3xx status code func (o *GetTimestampResponseDefault) IsRedirect() bool { return o._statusCode/100 == 3 } // IsClientError returns true when this get timestamp response default response has a 4xx status code func (o *GetTimestampResponseDefault) IsClientError() bool { return o._statusCode/100 == 4 } // IsServerError returns true when this get timestamp response default response has a 5xx status code func (o *GetTimestampResponseDefault) IsServerError() bool { return o._statusCode/100 == 5 } // IsCode returns true when this get timestamp response default response a status code equal to that given func (o *GetTimestampResponseDefault) IsCode(code int) bool { return o._statusCode == code } // Code gets the status code for the get timestamp response default response func (o *GetTimestampResponseDefault) Code() int { return o._statusCode } func (o *GetTimestampResponseDefault) Error() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponse default %s", o._statusCode, payload) } func (o *GetTimestampResponseDefault) String() string { payload, _ := json.Marshal(o.Payload) return fmt.Sprintf("[POST /api/v1/timestamp][%d] getTimestampResponse default %s", o._statusCode, payload) } func (o *GetTimestampResponseDefault) GetPayload() *models.Error { return o.Payload } func (o *GetTimestampResponseDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { o.Payload = new(models.Error) // response payload if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { return err } return nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp/timestamp_client.go000066400000000000000000000174261470602636300340410ustar00rootroot00000000000000// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "io" "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" ) // New creates a new timestamp API client. func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { return &Client{transport: transport, formats: formats} } // New creates a new timestamp API client with basic auth credentials. // It takes the following parameters: // - host: http host (github.com). // - basePath: any base path for the API client ("/v1", "/v3"). // - scheme: http scheme ("http", "https"). // - user: user for basic authentication header. // - password: password for basic authentication header. func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService { transport := httptransport.New(host, basePath, []string{scheme}) transport.DefaultAuthentication = httptransport.BasicAuth(user, password) return &Client{transport: transport, formats: strfmt.Default} } // New creates a new timestamp API client with a bearer token for authentication. // It takes the following parameters: // - host: http host (github.com). // - basePath: any base path for the API client ("/v1", "/v3"). // - scheme: http scheme ("http", "https"). // - bearerToken: bearer token for Bearer authentication header. func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService { transport := httptransport.New(host, basePath, []string{scheme}) transport.DefaultAuthentication = httptransport.BearerToken(bearerToken) return &Client{transport: transport, formats: strfmt.Default} } /* Client for timestamp API */ type Client struct { transport runtime.ClientTransport formats strfmt.Registry } // ClientOption may be used to customize the behavior of Client methods. type ClientOption func(*runtime.ClientOperation) // This client is generated with a few options you might find useful for your swagger spec. // // Feel free to add you own set of options. // WithContentType allows the client to force the Content-Type header // to negotiate a specific Consumer from the server. // // You may use this option to set arbitrary extensions to your MIME media type. func WithContentType(mime string) ClientOption { return func(r *runtime.ClientOperation) { r.ConsumesMediaTypes = []string{mime} } } // WithContentTypeApplicationJSON sets the Content-Type header to "application/json". func WithContentTypeApplicationJSON(r *runtime.ClientOperation) { r.ConsumesMediaTypes = []string{"application/json"} } // WithContentTypeApplicationTimestampQuery sets the Content-Type header to "application/timestamp-query". func WithContentTypeApplicationTimestampQuery(r *runtime.ClientOperation) { r.ConsumesMediaTypes = []string{"application/timestamp-query"} } // WithAccept allows the client to force the Accept header // to negotiate a specific Producer from the server. // // You may use this option to set arbitrary extensions to your MIME media type. func WithAccept(mime string) ClientOption { return func(r *runtime.ClientOperation) { r.ProducesMediaTypes = []string{mime} } } // WithAcceptApplicationJSON sets the Accept header to "application/json". func WithAcceptApplicationJSON(r *runtime.ClientOperation) { r.ProducesMediaTypes = []string{"application/json"} } // WithAcceptApplicationPemCertificateChain sets the Accept header to "application/pem-certificate-chain". func WithAcceptApplicationPemCertificateChain(r *runtime.ClientOperation) { r.ProducesMediaTypes = []string{"application/pem-certificate-chain"} } // WithAcceptApplicationTimestampReply sets the Accept header to "application/timestamp-reply". func WithAcceptApplicationTimestampReply(r *runtime.ClientOperation) { r.ProducesMediaTypes = []string{"application/timestamp-reply"} } // ClientService is the interface for Client methods type ClientService interface { GetTimestampCertChain(params *GetTimestampCertChainParams, opts ...ClientOption) (*GetTimestampCertChainOK, error) GetTimestampResponse(params *GetTimestampResponseParams, writer io.Writer, opts ...ClientOption) (*GetTimestampResponseCreated, error) SetTransport(transport runtime.ClientTransport) } /* GetTimestampCertChain retrieves the certificate chain for timestamping that can be used to validate trusted timestamps Returns the certificate chain for timestamping that can be used to validate trusted timestamps */ func (a *Client) GetTimestampCertChain(params *GetTimestampCertChainParams, opts ...ClientOption) (*GetTimestampCertChainOK, error) { // TODO: Validate the params before sending if params == nil { params = NewGetTimestampCertChainParams() } op := &runtime.ClientOperation{ ID: "getTimestampCertChain", Method: "GET", PathPattern: "/api/v1/timestamp/certchain", ProducesMediaTypes: []string{"application/pem-certificate-chain"}, ConsumesMediaTypes: []string{"application/json"}, Schemes: []string{"http"}, Params: params, Reader: &GetTimestampCertChainReader{formats: a.formats}, Context: params.Context, Client: params.HTTPClient, } for _, opt := range opts { opt(op) } result, err := a.transport.Submit(op) if err != nil { return nil, err } success, ok := result.(*GetTimestampCertChainOK) if ok { return success, nil } // unexpected success response unexpectedSuccess := result.(*GetTimestampCertChainDefault) return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } /* GetTimestampResponse generates a new timestamp response and creates a new log entry for the timestamp in the transparency log */ func (a *Client) GetTimestampResponse(params *GetTimestampResponseParams, writer io.Writer, opts ...ClientOption) (*GetTimestampResponseCreated, error) { // TODO: Validate the params before sending if params == nil { params = NewGetTimestampResponseParams() } op := &runtime.ClientOperation{ ID: "getTimestampResponse", Method: "POST", PathPattern: "/api/v1/timestamp", ProducesMediaTypes: []string{"application/timestamp-reply"}, ConsumesMediaTypes: []string{"application/timestamp-query", "application/json"}, Schemes: []string{"http"}, Params: params, Reader: &GetTimestampResponseReader{formats: a.formats, writer: writer}, Context: params.Context, Client: params.HTTPClient, } for _, opt := range opts { opt(op) } result, err := a.transport.Submit(op) if err != nil { return nil, err } success, ok := result.(*GetTimestampResponseCreated) if ok { return success, nil } // unexpected success response unexpectedSuccess := result.(*GetTimestampResponseDefault) return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/client/timestamp_authority_client.go000066400000000000000000000075361470602636300341470ustar00rootroot00000000000000// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package client // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "github.com/go-openapi/runtime" httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp" ) // Default timestamp authority HTTP client. var Default = NewHTTPClient(nil) const ( // DefaultHost is the default Host // found in Meta (info) section of spec file DefaultHost string = "timestamp.sigstore.dev" // DefaultBasePath is the default BasePath // found in Meta (info) section of spec file DefaultBasePath string = "/" ) // DefaultSchemes are the default schemes found in Meta (info) section of spec file var DefaultSchemes = []string{"http"} // NewHTTPClient creates a new timestamp authority HTTP client. func NewHTTPClient(formats strfmt.Registry) *TimestampAuthority { return NewHTTPClientWithConfig(formats, nil) } // NewHTTPClientWithConfig creates a new timestamp authority HTTP client, // using a customizable transport config. func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *TimestampAuthority { // ensure nullable parameters have default if cfg == nil { cfg = DefaultTransportConfig() } // create transport and client transport := httptransport.New(cfg.Host, cfg.BasePath, cfg.Schemes) return New(transport, formats) } // New creates a new timestamp authority client func New(transport runtime.ClientTransport, formats strfmt.Registry) *TimestampAuthority { // ensure nullable parameters have default if formats == nil { formats = strfmt.Default } cli := new(TimestampAuthority) cli.Transport = transport cli.Timestamp = timestamp.New(transport, formats) return cli } // DefaultTransportConfig creates a TransportConfig with the // default settings taken from the meta section of the spec file. func DefaultTransportConfig() *TransportConfig { return &TransportConfig{ Host: DefaultHost, BasePath: DefaultBasePath, Schemes: DefaultSchemes, } } // TransportConfig contains the transport related info, // found in the meta section of the spec file. type TransportConfig struct { Host string BasePath string Schemes []string } // WithHost overrides the default host, // provided by the meta section of the spec file. func (cfg *TransportConfig) WithHost(host string) *TransportConfig { cfg.Host = host return cfg } // WithBasePath overrides the default basePath, // provided by the meta section of the spec file. func (cfg *TransportConfig) WithBasePath(basePath string) *TransportConfig { cfg.BasePath = basePath return cfg } // WithSchemes overrides the default schemes, // provided by the meta section of the spec file. func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig { cfg.Schemes = schemes return cfg } // TimestampAuthority is a client for timestamp authority type TimestampAuthority struct { Timestamp timestamp.ClientService Transport runtime.ClientTransport } // SetTransport changes the transport on the client and all its subresources func (c *TimestampAuthority) SetTransport(transport runtime.ClientTransport) { c.Transport = transport c.Timestamp.SetTransport(transport) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/models/000077500000000000000000000000001470602636300261415ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/models/error.go000066400000000000000000000032201470602636300276160ustar00rootroot00000000000000// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package models // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "context" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" ) // Error error // // swagger:model Error type Error struct { // code Code int64 `json:"code,omitempty"` // message Message string `json:"message,omitempty"` } // Validate validates this error func (m *Error) Validate(formats strfmt.Registry) error { return nil } // ContextValidate validates this error based on context it is used func (m *Error) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil } // MarshalBinary interface implementation func (m *Error) MarshalBinary() ([]byte, error) { if m == nil { return nil, nil } return swag.WriteJSON(m) } // UnmarshalBinary interface implementation func (m *Error) UnmarshalBinary(b []byte) error { var res Error if err := swag.ReadJSON(b, &res); err != nil { return err } *m = res return nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/000077500000000000000000000000001470602636300263255ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/configure_timestamp_server.go000066400000000000000000000161561470602636300343170ustar00rootroot00000000000000// This file is safe to edit. Once it exists it will not be overwritten // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package restapi import ( "crypto/tls" "net/http" "strconv" "strings" "time" "github.com/go-chi/chi/middleware" "github.com/go-openapi/errors" "github.com/go-openapi/runtime" "github.com/mitchellh/mapstructure" "github.com/rs/cors" "github.com/urfave/negroni" pkgapi "github.com/sigstore/timestamp-authority/pkg/api" "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations" "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations/timestamp" "github.com/sigstore/timestamp-authority/pkg/internal/cmdparams" "github.com/sigstore/timestamp-authority/pkg/log" ) //go:generate swagger generate server --target ../../generated --name TimestampServer --spec ../../../openapi.yaml --principal interface{} --exclude-main --exclude-spec func configureFlags(_ *operations.TimestampServerAPI) { // api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ ... } } func configureAPI(api *operations.TimestampServerAPI) http.Handler { // configure the api here api.ServeError = logAndServeError // Set your custom logger if needed. Default one is log.Printf // Expected interface func(string, ...interface{}) // // Example: // api.Logger = log.Printf api.Logger = log.Logger.Infof // api.UseSwaggerUI() // To continue using redoc as your UI, uncomment the following line // api.UseRedoc() api.JSONConsumer = runtime.JSONConsumer() api.ApplicationPemCertificateChainProducer = runtime.TextProducer() api.ApplicationTimestampQueryConsumer = runtime.ByteStreamConsumer() api.ApplicationTimestampReplyProducer = runtime.ByteStreamProducer() api.TimestampGetTimestampResponseHandler = timestamp.GetTimestampResponseHandlerFunc(pkgapi.TimestampResponseHandler) api.TimestampGetTimestampCertChainHandler = timestamp.GetTimestampCertChainHandlerFunc(pkgapi.GetTimestampCertChainHandler) api.PreServerShutdown = func() {} api.ServerShutdown = func() {} api.AddMiddlewareFor("POST", "/api/v1/timestamp", middleware.NoCache) api.AddMiddlewareFor("GET", "/api/v1/timestamp/certchain", cacheForDay) return setupGlobalMiddleware(api.Serve(setupMiddlewares)) } // The TLS configuration before HTTPS server starts. func configureTLS(_ *tls.Config) { // Make all necessary changes to the TLS configuration here. } // As soon as server is initialized but not run yet, this function will be called. // If you need to modify a config, store server instance to stop it individually later, this is the place. // This function can be called multiple times, depending on the number of serving schemes. // scheme value will be set accordingly: "http", "https" or "unix". func configureServer(s *http.Server, scheme, addr string) { //nolint: revive } // The middleware configuration is for the handler executors. These do not apply to the swagger.json document. // The middleware executes after routing but before authentication, binding and validation. func setupMiddlewares(handler http.Handler) http.Handler { return handler } // We need this type to act as an adapter between zap and the middleware request logger. type logAdapter struct { } func (l *logAdapter) Print(v ...interface{}) { log.Logger.Info(v...) } const pingPath = "/ping" // httpPingOnly custom middleware prohibits all entrypoints except // "/ping" on the http (non-HTTPS) server. 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) { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusNotFound) w.Write([]byte("http server supports only the " + pingPath + " entrypoint")) //nolint:errcheck return } h.ServeHTTP(w, r) } return http.HandlerFunc(fn) } return f } // The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document. // So this is a good place to plug in a panic handling middleware, logging and metrics. func setupGlobalMiddleware(handler http.Handler) http.Handler { middleware.DefaultLogger = middleware.RequestLogger( &middleware.DefaultLogFormatter{Logger: &logAdapter{}}) returnHandler := middleware.Logger(handler) returnHandler = middleware.Recoverer(returnHandler) returnHandler = middleware.Heartbeat(pingPath)(returnHandler) if cmdparams.IsHTTPPingOnly { returnHandler = httpPingOnly()(returnHandler) } handleCORS := cors.Default().Handler returnHandler = handleCORS(returnHandler) returnHandler = wrapMetrics(returnHandler) return middleware.RequestID(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() r = r.WithContext(log.WithRequestID(ctx, middleware.GetReqID(ctx))) defer func() { _ = log.RequestIDLogger(r).Sync() }() returnHandler.ServeHTTP(w, r) })) } func wrapMetrics(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) defer func() { // This logs latency broken down by URL path and response code pkgapi.MetricLatency.With(map[string]string{ "path": r.URL.Path, "code": strconv.Itoa(ww.Status()), }).Observe(float64(time.Since(start))) pkgapi.MetricLatencySummary.With(map[string]string{ "path": r.URL.Path, "code": strconv.Itoa(ww.Status()), }).Observe(float64(time.Since(start))) pkgapi.MetricRequestLatency.With(map[string]string{ "path": r.URL.Path, "method": r.Method, }).Observe(float64(time.Since(start))) pkgapi.MetricRequestCount.With(map[string]string{ "path": r.URL.Path, "method": r.Method, "code": strconv.Itoa(ww.Status()), }).Inc() }() handler.ServeHTTP(ww, r) }) } func cacheForDay(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ww := negroni.NewResponseWriter(w) ww.Before(func(w negroni.ResponseWriter) { if w.Status() >= 200 && w.Status() <= 299 { w.Header().Set("Cache-Control", "max-age=86400, immutable") } }) handler.ServeHTTP(ww, r) }) } func logAndServeError(w http.ResponseWriter, r *http.Request, err error) { if apiErr, ok := err.(errors.Error); ok && apiErr.Code() == http.StatusNotFound { log.RequestIDLogger(r).Warn(err) } else { log.RequestIDLogger(r).Error(err) } requestFields := map[string]interface{}{} if err := mapstructure.Decode(r, &requestFields); err == nil { log.RequestIDLogger(r).Debug(requestFields) } errors.ServeError(w, r, err) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/doc.go000066400000000000000000000020231470602636300274160ustar00rootroot00000000000000// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Package restapi Timestamp Authority // // Timestamp Authority provides an RFC3161 timestamp authority. // Schemes: // http // Host: timestamp.sigstore.dev // BasePath: / // Version: 0.0.1 // // Consumes: // - application/timestamp-query // - application/json // // Produces: // - application/pem-certificate-chain // - application/timestamp-reply // // swagger:meta package restapi golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/embedded_spec.go000066400000000000000000000174341470602636300314300ustar00rootroot00000000000000// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package restapi // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "encoding/json" ) var ( // SwaggerJSON embedded version of the swagger document used at generation time SwaggerJSON json.RawMessage // FlatSwaggerJSON embedded flattened version of the swagger document used at generation time FlatSwaggerJSON json.RawMessage ) func init() { SwaggerJSON = json.RawMessage([]byte(`{ "schemes": [ "http" ], "swagger": "2.0", "info": { "description": "Timestamp Authority provides an RFC3161 timestamp authority.", "title": "Timestamp Authority", "version": "0.0.1" }, "host": "timestamp.sigstore.dev", "paths": { "/api/v1/timestamp": { "post": { "consumes": [ "application/timestamp-query", "application/json" ], "produces": [ "application/timestamp-reply" ], "tags": [ "timestamp" ], "summary": "Generates a new timestamp response and creates a new log entry for the timestamp in the transparency log", "operationId": "getTimestampResponse", "parameters": [ { "name": "request", "in": "body", "required": true, "schema": { "type": "string", "format": "binary" } } ], "responses": { "201": { "description": "Returns a timestamp response and the location of the log entry in the transprency log", "schema": { "type": "string", "format": "binary" } }, "400": { "$ref": "#/responses/BadContent" }, "501": { "$ref": "#/responses/NotImplemented" }, "default": { "$ref": "#/responses/InternalServerError" } } } }, "/api/v1/timestamp/certchain": { "get": { "description": "Returns the certificate chain for timestamping that can be used to validate trusted timestamps", "consumes": [ "application/json" ], "produces": [ "application/pem-certificate-chain" ], "tags": [ "timestamp" ], "summary": "Retrieve the certificate chain for timestamping that can be used to validate trusted timestamps", "operationId": "getTimestampCertChain", "responses": { "200": { "description": "The PEM encoded cert chain", "schema": { "type": "string" } }, "404": { "$ref": "#/responses/NotFound" }, "default": { "$ref": "#/responses/InternalServerError" } } } } }, "definitions": { "Error": { "type": "object", "properties": { "code": { "type": "integer" }, "message": { "type": "string" } } } }, "responses": { "BadContent": { "description": "The content supplied to the server was invalid", "schema": { "$ref": "#/definitions/Error" } }, "InternalServerError": { "description": "There was an internal error in the server while processing the request", "schema": { "$ref": "#/definitions/Error" } }, "NotFound": { "description": "The content requested could not be found" }, "NotImplemented": { "description": "The content requested is not implemented" } } }`)) FlatSwaggerJSON = json.RawMessage([]byte(`{ "schemes": [ "http" ], "swagger": "2.0", "info": { "description": "Timestamp Authority provides an RFC3161 timestamp authority.", "title": "Timestamp Authority", "version": "0.0.1" }, "host": "timestamp.sigstore.dev", "paths": { "/api/v1/timestamp": { "post": { "consumes": [ "application/timestamp-query", "application/json" ], "produces": [ "application/timestamp-reply" ], "tags": [ "timestamp" ], "summary": "Generates a new timestamp response and creates a new log entry for the timestamp in the transparency log", "operationId": "getTimestampResponse", "parameters": [ { "name": "request", "in": "body", "required": true, "schema": { "type": "string", "format": "binary" } } ], "responses": { "201": { "description": "Returns a timestamp response and the location of the log entry in the transprency log", "schema": { "type": "string", "format": "binary" } }, "400": { "description": "The content supplied to the server was invalid", "schema": { "$ref": "#/definitions/Error" } }, "501": { "description": "The content requested is not implemented" }, "default": { "description": "There was an internal error in the server while processing the request", "schema": { "$ref": "#/definitions/Error" } } } } }, "/api/v1/timestamp/certchain": { "get": { "description": "Returns the certificate chain for timestamping that can be used to validate trusted timestamps", "consumes": [ "application/json" ], "produces": [ "application/pem-certificate-chain" ], "tags": [ "timestamp" ], "summary": "Retrieve the certificate chain for timestamping that can be used to validate trusted timestamps", "operationId": "getTimestampCertChain", "responses": { "200": { "description": "The PEM encoded cert chain", "schema": { "type": "string" } }, "404": { "description": "The content requested could not be found" }, "default": { "description": "There was an internal error in the server while processing the request", "schema": { "$ref": "#/definitions/Error" } } } } } }, "definitions": { "Error": { "type": "object", "properties": { "code": { "type": "integer" }, "message": { "type": "string" } } } }, "responses": { "BadContent": { "description": "The content supplied to the server was invalid", "schema": { "$ref": "#/definitions/Error" } }, "InternalServerError": { "description": "There was an internal error in the server while processing the request", "schema": { "$ref": "#/definitions/Error" } }, "NotFound": { "description": "The content requested could not be found" }, "NotImplemented": { "description": "The content requested is not implemented" } } }`)) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/000077500000000000000000000000001470602636300305105ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp/000077500000000000000000000000001470602636300325135ustar00rootroot00000000000000get_timestamp_cert_chain.go000066400000000000000000000051231470602636300400050ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the generate command import ( "net/http" "github.com/go-openapi/runtime/middleware" ) // GetTimestampCertChainHandlerFunc turns a function with the right signature into a get timestamp cert chain handler type GetTimestampCertChainHandlerFunc func(GetTimestampCertChainParams) middleware.Responder // Handle executing the request and returning a response func (fn GetTimestampCertChainHandlerFunc) Handle(params GetTimestampCertChainParams) middleware.Responder { return fn(params) } // GetTimestampCertChainHandler interface for that can handle valid get timestamp cert chain params type GetTimestampCertChainHandler interface { Handle(GetTimestampCertChainParams) middleware.Responder } // NewGetTimestampCertChain creates a new http.Handler for the get timestamp cert chain operation func NewGetTimestampCertChain(ctx *middleware.Context, handler GetTimestampCertChainHandler) *GetTimestampCertChain { return &GetTimestampCertChain{Context: ctx, Handler: handler} } /* GetTimestampCertChain swagger:route GET /api/v1/timestamp/certchain timestamp getTimestampCertChain # Retrieve the certificate chain for timestamping that can be used to validate trusted timestamps Returns the certificate chain for timestamping that can be used to validate trusted timestamps */ type GetTimestampCertChain struct { Context *middleware.Context Handler GetTimestampCertChainHandler } func (o *GetTimestampCertChain) ServeHTTP(rw http.ResponseWriter, r *http.Request) { route, rCtx, _ := o.Context.RouteInfo(r) if rCtx != nil { *r = *rCtx } var Params = NewGetTimestampCertChainParams() if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params o.Context.Respond(rw, r, route.Produces, route, err) return } res := o.Handler.Handle(Params) // actually handle the request o.Context.Respond(rw, r, route.Produces, route, res) } get_timestamp_cert_chain_parameters.go000066400000000000000000000037271470602636300422400ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "net/http" "github.com/go-openapi/errors" "github.com/go-openapi/runtime/middleware" ) // NewGetTimestampCertChainParams creates a new GetTimestampCertChainParams object // // There are no default values defined in the spec. func NewGetTimestampCertChainParams() GetTimestampCertChainParams { return GetTimestampCertChainParams{} } // GetTimestampCertChainParams contains all the bound params for the get timestamp cert chain operation // typically these are obtained from a http.Request // // swagger:parameters getTimestampCertChain type GetTimestampCertChainParams struct { // HTTP Request Object HTTPRequest *http.Request `json:"-"` } // BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface // for simple values it will use straight method calls. // // To ensure default values, the struct must have been initialized with NewGetTimestampCertChainParams() beforehand. func (o *GetTimestampCertChainParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { var res []error o.HTTPRequest = r if len(res) > 0 { return errors.CompositeValidationError(res...) } return nil } get_timestamp_cert_chain_responses.go000066400000000000000000000107601470602636300421110ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "net/http" "github.com/go-openapi/runtime" "github.com/sigstore/timestamp-authority/pkg/generated/models" ) // GetTimestampCertChainOKCode is the HTTP code returned for type GetTimestampCertChainOK const GetTimestampCertChainOKCode int = 200 /* GetTimestampCertChainOK The PEM encoded cert chain swagger:response getTimestampCertChainOK */ type GetTimestampCertChainOK struct { /* In: Body */ Payload string `json:"body,omitempty"` } // NewGetTimestampCertChainOK creates GetTimestampCertChainOK with default headers values func NewGetTimestampCertChainOK() *GetTimestampCertChainOK { return &GetTimestampCertChainOK{} } // WithPayload adds the payload to the get timestamp cert chain o k response func (o *GetTimestampCertChainOK) WithPayload(payload string) *GetTimestampCertChainOK { o.Payload = payload return o } // SetPayload sets the payload to the get timestamp cert chain o k response func (o *GetTimestampCertChainOK) SetPayload(payload string) { o.Payload = payload } // WriteResponse to the client func (o *GetTimestampCertChainOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.WriteHeader(200) payload := o.Payload if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } } // GetTimestampCertChainNotFoundCode is the HTTP code returned for type GetTimestampCertChainNotFound const GetTimestampCertChainNotFoundCode int = 404 /* GetTimestampCertChainNotFound The content requested could not be found swagger:response getTimestampCertChainNotFound */ type GetTimestampCertChainNotFound struct { } // NewGetTimestampCertChainNotFound creates GetTimestampCertChainNotFound with default headers values func NewGetTimestampCertChainNotFound() *GetTimestampCertChainNotFound { return &GetTimestampCertChainNotFound{} } // WriteResponse to the client func (o *GetTimestampCertChainNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses rw.WriteHeader(404) } /* GetTimestampCertChainDefault There was an internal error in the server while processing the request swagger:response getTimestampCertChainDefault */ type GetTimestampCertChainDefault struct { _statusCode int /* In: Body */ Payload *models.Error `json:"body,omitempty"` } // NewGetTimestampCertChainDefault creates GetTimestampCertChainDefault with default headers values func NewGetTimestampCertChainDefault(code int) *GetTimestampCertChainDefault { if code <= 0 { code = 500 } return &GetTimestampCertChainDefault{ _statusCode: code, } } // WithStatusCode adds the status to the get timestamp cert chain default response func (o *GetTimestampCertChainDefault) WithStatusCode(code int) *GetTimestampCertChainDefault { o._statusCode = code return o } // SetStatusCode sets the status to the get timestamp cert chain default response func (o *GetTimestampCertChainDefault) SetStatusCode(code int) { o._statusCode = code } // WithPayload adds the payload to the get timestamp cert chain default response func (o *GetTimestampCertChainDefault) WithPayload(payload *models.Error) *GetTimestampCertChainDefault { o.Payload = payload return o } // SetPayload sets the payload to the get timestamp cert chain default response func (o *GetTimestampCertChainDefault) SetPayload(payload *models.Error) { o.Payload = payload } // WriteResponse to the client func (o *GetTimestampCertChainDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.WriteHeader(o._statusCode) if o.Payload != nil { payload := o.Payload if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } } } get_timestamp_cert_chain_urlbuilder.go000066400000000000000000000056421470602636300422440ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the generate command import ( "errors" "net/url" golangswaggerpaths "path" ) // GetTimestampCertChainURL generates an URL for the get timestamp cert chain operation type GetTimestampCertChainURL struct { _basePath string } // WithBasePath sets the base path for this url builder, only required when it's different from the // base path specified in the swagger spec. // When the value of the base path is an empty string func (o *GetTimestampCertChainURL) WithBasePath(bp string) *GetTimestampCertChainURL { o.SetBasePath(bp) return o } // SetBasePath sets the base path for this url builder, only required when it's different from the // base path specified in the swagger spec. // When the value of the base path is an empty string func (o *GetTimestampCertChainURL) SetBasePath(bp string) { o._basePath = bp } // Build a url path and query string func (o *GetTimestampCertChainURL) Build() (*url.URL, error) { var _result url.URL var _path = "/api/v1/timestamp/certchain" _basePath := o._basePath _result.Path = golangswaggerpaths.Join(_basePath, _path) return &_result, nil } // Must is a helper function to panic when the url builder returns an error func (o *GetTimestampCertChainURL) Must(u *url.URL, err error) *url.URL { if err != nil { panic(err) } if u == nil { panic("url can't be nil") } return u } // String returns the string representation of the path with query string func (o *GetTimestampCertChainURL) String() string { return o.Must(o.Build()).String() } // BuildFull builds a full url with scheme, host, path and query string func (o *GetTimestampCertChainURL) BuildFull(scheme, host string) (*url.URL, error) { if scheme == "" { return nil, errors.New("scheme is required for a full url on GetTimestampCertChainURL") } if host == "" { return nil, errors.New("host is required for a full url on GetTimestampCertChainURL") } base, err := o.Build() if err != nil { return nil, err } base.Scheme = scheme base.Host = host return base, nil } // StringFull returns the string representation of a complete url func (o *GetTimestampCertChainURL) StringFull(scheme, host string) string { return o.Must(o.BuildFull(scheme, host)).String() } get_timestamp_response.go000066400000000000000000000047301470602636300375470ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the generate command import ( "net/http" "github.com/go-openapi/runtime/middleware" ) // GetTimestampResponseHandlerFunc turns a function with the right signature into a get timestamp response handler type GetTimestampResponseHandlerFunc func(GetTimestampResponseParams) middleware.Responder // Handle executing the request and returning a response func (fn GetTimestampResponseHandlerFunc) Handle(params GetTimestampResponseParams) middleware.Responder { return fn(params) } // GetTimestampResponseHandler interface for that can handle valid get timestamp response params type GetTimestampResponseHandler interface { Handle(GetTimestampResponseParams) middleware.Responder } // NewGetTimestampResponse creates a new http.Handler for the get timestamp response operation func NewGetTimestampResponse(ctx *middleware.Context, handler GetTimestampResponseHandler) *GetTimestampResponse { return &GetTimestampResponse{Context: ctx, Handler: handler} } /* GetTimestampResponse swagger:route POST /api/v1/timestamp timestamp getTimestampResponse Generates a new timestamp response and creates a new log entry for the timestamp in the transparency log */ type GetTimestampResponse struct { Context *middleware.Context Handler GetTimestampResponseHandler } func (o *GetTimestampResponse) ServeHTTP(rw http.ResponseWriter, r *http.Request) { route, rCtx, _ := o.Context.RouteInfo(r) if rCtx != nil { *r = *rCtx } var Params = NewGetTimestampResponseParams() if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params o.Context.Respond(rw, r, route.Produces, route, err) return } res := o.Handler.Handle(Params) // actually handle the request o.Context.Respond(rw, r, route.Produces, route, res) } get_timestamp_response_parameters.go000066400000000000000000000042471470602636300417750ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "io" "net/http" "github.com/go-openapi/errors" "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" ) // NewGetTimestampResponseParams creates a new GetTimestampResponseParams object // // There are no default values defined in the spec. func NewGetTimestampResponseParams() GetTimestampResponseParams { return GetTimestampResponseParams{} } // GetTimestampResponseParams contains all the bound params for the get timestamp response operation // typically these are obtained from a http.Request // // swagger:parameters getTimestampResponse type GetTimestampResponseParams struct { // HTTP Request Object HTTPRequest *http.Request `json:"-"` /* Required: true In: body */ Request io.ReadCloser } // BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface // for simple values it will use straight method calls. // // To ensure default values, the struct must have been initialized with NewGetTimestampResponseParams() beforehand. func (o *GetTimestampResponseParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { var res []error o.HTTPRequest = r if runtime.HasBody(r) { o.Request = r.Body } else { res = append(res, errors.Required("request", "body", "")) } if len(res) > 0 { return errors.CompositeValidationError(res...) } return nil } get_timestamp_response_responses.go000066400000000000000000000140101470602636300416400ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "io" "net/http" "github.com/go-openapi/runtime" "github.com/sigstore/timestamp-authority/pkg/generated/models" ) // GetTimestampResponseCreatedCode is the HTTP code returned for type GetTimestampResponseCreated const GetTimestampResponseCreatedCode int = 201 /* GetTimestampResponseCreated Returns a timestamp response and the location of the log entry in the transprency log swagger:response getTimestampResponseCreated */ type GetTimestampResponseCreated struct { /* In: Body */ Payload io.ReadCloser `json:"body,omitempty"` } // NewGetTimestampResponseCreated creates GetTimestampResponseCreated with default headers values func NewGetTimestampResponseCreated() *GetTimestampResponseCreated { return &GetTimestampResponseCreated{} } // WithPayload adds the payload to the get timestamp response created response func (o *GetTimestampResponseCreated) WithPayload(payload io.ReadCloser) *GetTimestampResponseCreated { o.Payload = payload return o } // SetPayload sets the payload to the get timestamp response created response func (o *GetTimestampResponseCreated) SetPayload(payload io.ReadCloser) { o.Payload = payload } // WriteResponse to the client func (o *GetTimestampResponseCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.WriteHeader(201) payload := o.Payload if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } } // GetTimestampResponseBadRequestCode is the HTTP code returned for type GetTimestampResponseBadRequest const GetTimestampResponseBadRequestCode int = 400 /* GetTimestampResponseBadRequest The content supplied to the server was invalid swagger:response getTimestampResponseBadRequest */ type GetTimestampResponseBadRequest struct { /* In: Body */ Payload *models.Error `json:"body,omitempty"` } // NewGetTimestampResponseBadRequest creates GetTimestampResponseBadRequest with default headers values func NewGetTimestampResponseBadRequest() *GetTimestampResponseBadRequest { return &GetTimestampResponseBadRequest{} } // WithPayload adds the payload to the get timestamp response bad request response func (o *GetTimestampResponseBadRequest) WithPayload(payload *models.Error) *GetTimestampResponseBadRequest { o.Payload = payload return o } // SetPayload sets the payload to the get timestamp response bad request response func (o *GetTimestampResponseBadRequest) SetPayload(payload *models.Error) { o.Payload = payload } // WriteResponse to the client func (o *GetTimestampResponseBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.WriteHeader(400) if o.Payload != nil { payload := o.Payload if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } } } // GetTimestampResponseNotImplementedCode is the HTTP code returned for type GetTimestampResponseNotImplemented const GetTimestampResponseNotImplementedCode int = 501 /* GetTimestampResponseNotImplemented The content requested is not implemented swagger:response getTimestampResponseNotImplemented */ type GetTimestampResponseNotImplemented struct { } // NewGetTimestampResponseNotImplemented creates GetTimestampResponseNotImplemented with default headers values func NewGetTimestampResponseNotImplemented() *GetTimestampResponseNotImplemented { return &GetTimestampResponseNotImplemented{} } // WriteResponse to the client func (o *GetTimestampResponseNotImplemented) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses rw.WriteHeader(501) } /* GetTimestampResponseDefault There was an internal error in the server while processing the request swagger:response getTimestampResponseDefault */ type GetTimestampResponseDefault struct { _statusCode int /* In: Body */ Payload *models.Error `json:"body,omitempty"` } // NewGetTimestampResponseDefault creates GetTimestampResponseDefault with default headers values func NewGetTimestampResponseDefault(code int) *GetTimestampResponseDefault { if code <= 0 { code = 500 } return &GetTimestampResponseDefault{ _statusCode: code, } } // WithStatusCode adds the status to the get timestamp response default response func (o *GetTimestampResponseDefault) WithStatusCode(code int) *GetTimestampResponseDefault { o._statusCode = code return o } // SetStatusCode sets the status to the get timestamp response default response func (o *GetTimestampResponseDefault) SetStatusCode(code int) { o._statusCode = code } // WithPayload adds the payload to the get timestamp response default response func (o *GetTimestampResponseDefault) WithPayload(payload *models.Error) *GetTimestampResponseDefault { o.Payload = payload return o } // SetPayload sets the payload to the get timestamp response default response func (o *GetTimestampResponseDefault) SetPayload(payload *models.Error) { o.Payload = payload } // WriteResponse to the client func (o *GetTimestampResponseDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { rw.WriteHeader(o._statusCode) if o.Payload != nil { payload := o.Payload if err := producer.Produce(rw, payload); err != nil { panic(err) // let the recovery middleware deal with this } } } get_timestamp_response_urlbuilder.go000066400000000000000000000056121470602636300420000ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations/timestamp// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package timestamp // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the generate command import ( "errors" "net/url" golangswaggerpaths "path" ) // GetTimestampResponseURL generates an URL for the get timestamp response operation type GetTimestampResponseURL struct { _basePath string } // WithBasePath sets the base path for this url builder, only required when it's different from the // base path specified in the swagger spec. // When the value of the base path is an empty string func (o *GetTimestampResponseURL) WithBasePath(bp string) *GetTimestampResponseURL { o.SetBasePath(bp) return o } // SetBasePath sets the base path for this url builder, only required when it's different from the // base path specified in the swagger spec. // When the value of the base path is an empty string func (o *GetTimestampResponseURL) SetBasePath(bp string) { o._basePath = bp } // Build a url path and query string func (o *GetTimestampResponseURL) Build() (*url.URL, error) { var _result url.URL var _path = "/api/v1/timestamp" _basePath := o._basePath _result.Path = golangswaggerpaths.Join(_basePath, _path) return &_result, nil } // Must is a helper function to panic when the url builder returns an error func (o *GetTimestampResponseURL) Must(u *url.URL, err error) *url.URL { if err != nil { panic(err) } if u == nil { panic("url can't be nil") } return u } // String returns the string representation of the path with query string func (o *GetTimestampResponseURL) String() string { return o.Must(o.Build()).String() } // BuildFull builds a full url with scheme, host, path and query string func (o *GetTimestampResponseURL) BuildFull(scheme, host string) (*url.URL, error) { if scheme == "" { return nil, errors.New("scheme is required for a full url on GetTimestampResponseURL") } if host == "" { return nil, errors.New("host is required for a full url on GetTimestampResponseURL") } base, err := o.Build() if err != nil { return nil, err } base.Scheme = scheme base.Host = host return base, nil } // StringFull returns the string representation of a complete url func (o *GetTimestampResponseURL) StringFull(scheme, host string) string { return o.Must(o.BuildFull(scheme, host)).String() } timestamp_server_api.go000066400000000000000000000315351470602636300352110ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/operations// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package operations // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command import ( "fmt" "io" "net/http" "strings" "github.com/go-openapi/errors" "github.com/go-openapi/loads" "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/runtime/security" "github.com/go-openapi/spec" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations/timestamp" ) // NewTimestampServerAPI creates a new TimestampServer instance func NewTimestampServerAPI(spec *loads.Document) *TimestampServerAPI { return &TimestampServerAPI{ handlers: make(map[string]map[string]http.Handler), formats: strfmt.Default, defaultConsumes: "application/json", defaultProduces: "application/json", customConsumers: make(map[string]runtime.Consumer), customProducers: make(map[string]runtime.Producer), PreServerShutdown: func() {}, ServerShutdown: func() {}, spec: spec, useSwaggerUI: false, ServeError: errors.ServeError, BasicAuthenticator: security.BasicAuth, APIKeyAuthenticator: security.APIKeyAuth, BearerAuthenticator: security.BearerAuth, ApplicationTimestampQueryConsumer: runtime.ConsumerFunc(func(r io.Reader, target interface{}) error { return errors.NotImplemented("applicationTimestampQuery consumer has not yet been implemented") }), JSONConsumer: runtime.JSONConsumer(), ApplicationPemCertificateChainProducer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error { return errors.NotImplemented("applicationPemCertificateChain producer has not yet been implemented") }), ApplicationTimestampReplyProducer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error { return errors.NotImplemented("applicationTimestampReply producer has not yet been implemented") }), TimestampGetTimestampCertChainHandler: timestamp.GetTimestampCertChainHandlerFunc(func(params timestamp.GetTimestampCertChainParams) middleware.Responder { return middleware.NotImplemented("operation timestamp.GetTimestampCertChain has not yet been implemented") }), TimestampGetTimestampResponseHandler: timestamp.GetTimestampResponseHandlerFunc(func(params timestamp.GetTimestampResponseParams) middleware.Responder { return middleware.NotImplemented("operation timestamp.GetTimestampResponse has not yet been implemented") }), } } /*TimestampServerAPI Timestamp Authority provides an RFC3161 timestamp authority. */ type TimestampServerAPI struct { spec *loads.Document context *middleware.Context handlers map[string]map[string]http.Handler formats strfmt.Registry customConsumers map[string]runtime.Consumer customProducers map[string]runtime.Producer defaultConsumes string defaultProduces string Middleware func(middleware.Builder) http.Handler useSwaggerUI bool // BasicAuthenticator generates a runtime.Authenticator from the supplied basic auth function. // It has a default implementation in the security package, however you can replace it for your particular usage. BasicAuthenticator func(security.UserPassAuthentication) runtime.Authenticator // APIKeyAuthenticator generates a runtime.Authenticator from the supplied token auth function. // It has a default implementation in the security package, however you can replace it for your particular usage. APIKeyAuthenticator func(string, string, security.TokenAuthentication) runtime.Authenticator // BearerAuthenticator generates a runtime.Authenticator from the supplied bearer token auth function. // It has a default implementation in the security package, however you can replace it for your particular usage. BearerAuthenticator func(string, security.ScopedTokenAuthentication) runtime.Authenticator // ApplicationTimestampQueryConsumer registers a consumer for the following mime types: // - application/timestamp-query ApplicationTimestampQueryConsumer runtime.Consumer // JSONConsumer registers a consumer for the following mime types: // - application/json JSONConsumer runtime.Consumer // ApplicationPemCertificateChainProducer registers a producer for the following mime types: // - application/pem-certificate-chain ApplicationPemCertificateChainProducer runtime.Producer // ApplicationTimestampReplyProducer registers a producer for the following mime types: // - application/timestamp-reply ApplicationTimestampReplyProducer runtime.Producer // TimestampGetTimestampCertChainHandler sets the operation handler for the get timestamp cert chain operation TimestampGetTimestampCertChainHandler timestamp.GetTimestampCertChainHandler // TimestampGetTimestampResponseHandler sets the operation handler for the get timestamp response operation TimestampGetTimestampResponseHandler timestamp.GetTimestampResponseHandler // ServeError is called when an error is received, there is a default handler // but you can set your own with this ServeError func(http.ResponseWriter, *http.Request, error) // PreServerShutdown is called before the HTTP(S) server is shutdown // This allows for custom functions to get executed before the HTTP(S) server stops accepting traffic PreServerShutdown func() // ServerShutdown is called when the HTTP(S) server is shut down and done // handling all active connections and does not accept connections any more ServerShutdown func() // Custom command line argument groups with their descriptions CommandLineOptionsGroups []swag.CommandLineOptionsGroup // User defined logger function. Logger func(string, ...interface{}) } // UseRedoc for documentation at /docs func (o *TimestampServerAPI) UseRedoc() { o.useSwaggerUI = false } // UseSwaggerUI for documentation at /docs func (o *TimestampServerAPI) UseSwaggerUI() { o.useSwaggerUI = true } // SetDefaultProduces sets the default produces media type func (o *TimestampServerAPI) SetDefaultProduces(mediaType string) { o.defaultProduces = mediaType } // SetDefaultConsumes returns the default consumes media type func (o *TimestampServerAPI) SetDefaultConsumes(mediaType string) { o.defaultConsumes = mediaType } // SetSpec sets a spec that will be served for the clients. func (o *TimestampServerAPI) SetSpec(spec *loads.Document) { o.spec = spec } // DefaultProduces returns the default produces media type func (o *TimestampServerAPI) DefaultProduces() string { return o.defaultProduces } // DefaultConsumes returns the default consumes media type func (o *TimestampServerAPI) DefaultConsumes() string { return o.defaultConsumes } // Formats returns the registered string formats func (o *TimestampServerAPI) Formats() strfmt.Registry { return o.formats } // RegisterFormat registers a custom format validator func (o *TimestampServerAPI) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) { o.formats.Add(name, format, validator) } // Validate validates the registrations in the TimestampServerAPI func (o *TimestampServerAPI) Validate() error { var unregistered []string if o.ApplicationTimestampQueryConsumer == nil { unregistered = append(unregistered, "ApplicationTimestampQueryConsumer") } if o.JSONConsumer == nil { unregistered = append(unregistered, "JSONConsumer") } if o.ApplicationPemCertificateChainProducer == nil { unregistered = append(unregistered, "ApplicationPemCertificateChainProducer") } if o.ApplicationTimestampReplyProducer == nil { unregistered = append(unregistered, "ApplicationTimestampReplyProducer") } if o.TimestampGetTimestampCertChainHandler == nil { unregistered = append(unregistered, "timestamp.GetTimestampCertChainHandler") } if o.TimestampGetTimestampResponseHandler == nil { unregistered = append(unregistered, "timestamp.GetTimestampResponseHandler") } if len(unregistered) > 0 { return fmt.Errorf("missing registration: %s", strings.Join(unregistered, ", ")) } return nil } // ServeErrorFor gets a error handler for a given operation id func (o *TimestampServerAPI) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) { return o.ServeError } // AuthenticatorsFor gets the authenticators for the specified security schemes func (o *TimestampServerAPI) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator { return nil } // Authorizer returns the registered authorizer func (o *TimestampServerAPI) Authorizer() runtime.Authorizer { return nil } // ConsumersFor gets the consumers for the specified media types. // MIME type parameters are ignored here. func (o *TimestampServerAPI) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer { result := make(map[string]runtime.Consumer, len(mediaTypes)) for _, mt := range mediaTypes { switch mt { case "application/timestamp-query": result["application/timestamp-query"] = o.ApplicationTimestampQueryConsumer case "application/json": result["application/json"] = o.JSONConsumer } if c, ok := o.customConsumers[mt]; ok { result[mt] = c } } return result } // ProducersFor gets the producers for the specified media types. // MIME type parameters are ignored here. func (o *TimestampServerAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer { result := make(map[string]runtime.Producer, len(mediaTypes)) for _, mt := range mediaTypes { switch mt { case "application/pem-certificate-chain": result["application/pem-certificate-chain"] = o.ApplicationPemCertificateChainProducer case "application/timestamp-reply": result["application/timestamp-reply"] = o.ApplicationTimestampReplyProducer } if p, ok := o.customProducers[mt]; ok { result[mt] = p } } return result } // HandlerFor gets a http.Handler for the provided operation method and path func (o *TimestampServerAPI) HandlerFor(method, path string) (http.Handler, bool) { if o.handlers == nil { return nil, false } um := strings.ToUpper(method) if _, ok := o.handlers[um]; !ok { return nil, false } if path == "/" { path = "" } h, ok := o.handlers[um][path] return h, ok } // Context returns the middleware context for the timestamp server API func (o *TimestampServerAPI) Context() *middleware.Context { if o.context == nil { o.context = middleware.NewRoutableContext(o.spec, o, nil) } return o.context } func (o *TimestampServerAPI) initHandlerCache() { o.Context() // don't care about the result, just that the initialization happened if o.handlers == nil { o.handlers = make(map[string]map[string]http.Handler) } if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } o.handlers["GET"]["/api/v1/timestamp/certchain"] = timestamp.NewGetTimestampCertChain(o.context, o.TimestampGetTimestampCertChainHandler) if o.handlers["POST"] == nil { o.handlers["POST"] = make(map[string]http.Handler) } o.handlers["POST"]["/api/v1/timestamp"] = timestamp.NewGetTimestampResponse(o.context, o.TimestampGetTimestampResponseHandler) } // Serve creates a http handler to serve the API over HTTP // can be used directly in http.ListenAndServe(":8000", api.Serve(nil)) func (o *TimestampServerAPI) Serve(builder middleware.Builder) http.Handler { o.Init() if o.Middleware != nil { return o.Middleware(builder) } if o.useSwaggerUI { return o.context.APIHandlerSwaggerUI(builder) } return o.context.APIHandler(builder) } // Init allows you to just initialize the handler cache, you can then recompose the middleware as you see fit func (o *TimestampServerAPI) Init() { if len(o.handlers) == 0 { o.initHandlerCache() } } // RegisterConsumer allows you to add (or override) a consumer for a media type. func (o *TimestampServerAPI) RegisterConsumer(mediaType string, consumer runtime.Consumer) { o.customConsumers[mediaType] = consumer } // RegisterProducer allows you to add (or override) a producer for a media type. func (o *TimestampServerAPI) RegisterProducer(mediaType string, producer runtime.Producer) { o.customProducers[mediaType] = producer } // AddMiddlewareFor adds a http middleware to existing handler func (o *TimestampServerAPI) AddMiddlewareFor(method, path string, builder middleware.Builder) { um := strings.ToUpper(method) if path == "/" { path = "" } o.Init() if h, ok := o.handlers[um][path]; ok { o.handlers[um][path] = builder(h) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/generated/restapi/server.go000066400000000000000000000436131470602636300301710ustar00rootroot00000000000000// Code generated by go-swagger; DO NOT EDIT. // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package restapi import ( "context" "crypto/tls" "crypto/x509" "errors" "fmt" "log" "net" "net/http" "os" "os/signal" "strconv" "sync" "sync/atomic" "syscall" "time" "github.com/go-openapi/runtime/flagext" "github.com/go-openapi/swag" flag "github.com/spf13/pflag" "golang.org/x/net/netutil" "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations" ) const ( schemeHTTP = "http" schemeHTTPS = "https" schemeUnix = "unix" ) var defaultSchemes []string func init() { defaultSchemes = []string{ schemeHTTP, } } var ( enabledListeners []string cleanupTimeout time.Duration gracefulTimeout time.Duration maxHeaderSize flagext.ByteSize socketPath string host string port int listenLimit int keepAlive time.Duration readTimeout time.Duration writeTimeout time.Duration tlsHost string tlsPort int tlsListenLimit int tlsKeepAlive time.Duration tlsReadTimeout time.Duration tlsWriteTimeout time.Duration tlsCertificate string tlsCertificateKey string tlsCACertificate string ) func init() { maxHeaderSize = flagext.ByteSize(1000000) flag.StringSliceVar(&enabledListeners, "scheme", defaultSchemes, "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec") flag.DurationVar(&cleanupTimeout, "cleanup-timeout", 10*time.Second, "grace period for which to wait before killing idle connections") flag.DurationVar(&gracefulTimeout, "graceful-timeout", 15*time.Second, "grace period for which to wait before shutting down the server") flag.Var(&maxHeaderSize, "max-header-size", "controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body") flag.StringVar(&socketPath, "socket-path", "/var/run/todo-list.sock", "the unix socket to listen on") flag.StringVar(&host, "host", "localhost", "the IP to listen on") flag.IntVar(&port, "port", 0, "the port to listen on for insecure connections, defaults to a random value") flag.IntVar(&listenLimit, "listen-limit", 0, "limit the number of outstanding requests") flag.DurationVar(&keepAlive, "keep-alive", 3*time.Minute, "sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)") flag.DurationVar(&readTimeout, "read-timeout", 30*time.Second, "maximum duration before timing out read of the request") flag.DurationVar(&writeTimeout, "write-timeout", 30*time.Second, "maximum duration before timing out write of the response") flag.StringVar(&tlsHost, "tls-host", "localhost", "the IP to listen on") flag.IntVar(&tlsPort, "tls-port", 0, "the port to listen on for secure connections, defaults to a random value") flag.StringVar(&tlsCertificate, "tls-certificate", "", "the certificate file to use for secure connections") flag.StringVar(&tlsCertificateKey, "tls-key", "", "the private key file to use for secure connections (without passphrase)") flag.StringVar(&tlsCACertificate, "tls-ca", "", "the certificate authority certificate file to be used with mutual tls auth") flag.IntVar(&tlsListenLimit, "tls-listen-limit", 0, "limit the number of outstanding requests") flag.DurationVar(&tlsKeepAlive, "tls-keep-alive", 3*time.Minute, "sets the TCP keep-alive timeouts on accepted connections. It prunes dead TCP connections ( e.g. closing laptop mid-download)") flag.DurationVar(&tlsReadTimeout, "tls-read-timeout", 30*time.Second, "maximum duration before timing out read of the request") flag.DurationVar(&tlsWriteTimeout, "tls-write-timeout", 30*time.Second, "maximum duration before timing out write of the response") } func stringEnvOverride(orig string, def string, keys ...string) string { for _, k := range keys { if os.Getenv(k) != "" { return os.Getenv(k) } } if def != "" && orig == "" { return def } return orig } func intEnvOverride(orig int, def int, keys ...string) int { for _, k := range keys { if os.Getenv(k) != "" { v, err := strconv.Atoi(os.Getenv(k)) if err != nil { fmt.Fprintln(os.Stderr, k, "is not a valid number") os.Exit(1) } return v } } if def != 0 && orig == 0 { return def } return orig } // NewServer creates a new api timestamp server server but does not configure it func NewServer(api *operations.TimestampServerAPI) *Server { s := new(Server) s.EnabledListeners = enabledListeners s.CleanupTimeout = cleanupTimeout s.GracefulTimeout = gracefulTimeout s.MaxHeaderSize = maxHeaderSize s.SocketPath = socketPath s.Host = stringEnvOverride(host, "", "HOST") s.Port = intEnvOverride(port, 0, "PORT") s.ListenLimit = listenLimit s.KeepAlive = keepAlive s.ReadTimeout = readTimeout s.WriteTimeout = writeTimeout s.TLSHost = stringEnvOverride(tlsHost, s.Host, "TLS_HOST", "HOST") s.TLSPort = intEnvOverride(tlsPort, 0, "TLS_PORT") s.TLSCertificate = stringEnvOverride(tlsCertificate, "", "TLS_CERTIFICATE") s.TLSCertificateKey = stringEnvOverride(tlsCertificateKey, "", "TLS_PRIVATE_KEY") s.TLSCACertificate = stringEnvOverride(tlsCACertificate, "", "TLS_CA_CERTIFICATE") s.TLSListenLimit = tlsListenLimit s.TLSKeepAlive = tlsKeepAlive s.TLSReadTimeout = tlsReadTimeout s.TLSWriteTimeout = tlsWriteTimeout s.shutdown = make(chan struct{}) s.api = api s.interrupt = make(chan os.Signal, 1) return s } // ConfigureAPI configures the API and handlers. func (s *Server) ConfigureAPI() { if s.api != nil { s.handler = configureAPI(s.api) } } // ConfigureFlags configures the additional flags defined by the handlers. Needs to be called before the parser.Parse func (s *Server) ConfigureFlags() { if s.api != nil { configureFlags(s.api) } } // Server for the timestamp server API type Server struct { EnabledListeners []string CleanupTimeout time.Duration GracefulTimeout time.Duration MaxHeaderSize flagext.ByteSize SocketPath string domainSocketL net.Listener Host string Port int ListenLimit int KeepAlive time.Duration ReadTimeout time.Duration WriteTimeout time.Duration httpServerL net.Listener TLSHost string TLSPort int TLSCertificate string TLSCertificateKey string TLSCACertificate string TLSListenLimit int TLSKeepAlive time.Duration TLSReadTimeout time.Duration TLSWriteTimeout time.Duration httpsServerL net.Listener api *operations.TimestampServerAPI handler http.Handler hasListeners bool shutdown chan struct{} shuttingDown int32 interrupted bool interrupt chan os.Signal } // Logf logs message either via defined user logger or via system one if no user logger is defined. func (s *Server) Logf(f string, args ...interface{}) { if s.api != nil && s.api.Logger != nil { s.api.Logger(f, args...) } else { log.Printf(f, args...) } } // Fatalf logs message either via defined user logger or via system one if no user logger is defined. // Exits with non-zero status after printing func (s *Server) Fatalf(f string, args ...interface{}) { if s.api != nil && s.api.Logger != nil { s.api.Logger(f, args...) os.Exit(1) } else { log.Fatalf(f, args...) } } // SetAPI configures the server with the specified API. Needs to be called before Serve func (s *Server) SetAPI(api *operations.TimestampServerAPI) { if api == nil { s.api = nil s.handler = nil return } s.api = api s.handler = configureAPI(api) } func (s *Server) hasScheme(scheme string) bool { schemes := s.EnabledListeners if len(schemes) == 0 { schemes = defaultSchemes } for _, v := range schemes { if v == scheme { return true } } return false } // Serve the api func (s *Server) Serve() (err error) { if !s.hasListeners { if err = s.Listen(); err != nil { return err } } // set default handler, if none is set if s.handler == nil { if s.api == nil { return errors.New("can't create the default handler, as no api is set") } s.SetHandler(s.api.Serve(nil)) } wg := new(sync.WaitGroup) once := new(sync.Once) signalNotify(s.interrupt) go handleInterrupt(once, s) servers := []*http.Server{} if s.hasScheme(schemeUnix) { domainSocket := new(http.Server) domainSocket.MaxHeaderBytes = int(s.MaxHeaderSize) domainSocket.Handler = s.handler if int64(s.CleanupTimeout) > 0 { domainSocket.IdleTimeout = s.CleanupTimeout } configureServer(domainSocket, "unix", string(s.SocketPath)) servers = append(servers, domainSocket) wg.Add(1) s.Logf("Serving timestamp server at unix://%s", s.SocketPath) go func(l net.Listener) { defer wg.Done() if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed { s.Fatalf("%v", err) } s.Logf("Stopped serving timestamp server at unix://%s", s.SocketPath) }(s.domainSocketL) } if s.hasScheme(schemeHTTP) { httpServer := new(http.Server) httpServer.MaxHeaderBytes = int(s.MaxHeaderSize) httpServer.ReadTimeout = s.ReadTimeout httpServer.WriteTimeout = s.WriteTimeout httpServer.SetKeepAlivesEnabled(int64(s.KeepAlive) > 0) if s.ListenLimit > 0 { s.httpServerL = netutil.LimitListener(s.httpServerL, s.ListenLimit) } if int64(s.CleanupTimeout) > 0 { httpServer.IdleTimeout = s.CleanupTimeout } httpServer.Handler = s.handler configureServer(httpServer, "http", s.httpServerL.Addr().String()) servers = append(servers, httpServer) wg.Add(1) s.Logf("Serving timestamp server at http://%s", s.httpServerL.Addr()) go func(l net.Listener) { defer wg.Done() if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed { s.Fatalf("%v", err) } s.Logf("Stopped serving timestamp server at http://%s", l.Addr()) }(s.httpServerL) } if s.hasScheme(schemeHTTPS) { httpsServer := new(http.Server) httpsServer.MaxHeaderBytes = int(s.MaxHeaderSize) httpsServer.ReadTimeout = s.TLSReadTimeout httpsServer.WriteTimeout = s.TLSWriteTimeout httpsServer.SetKeepAlivesEnabled(int64(s.TLSKeepAlive) > 0) if s.TLSListenLimit > 0 { s.httpsServerL = netutil.LimitListener(s.httpsServerL, s.TLSListenLimit) } if int64(s.CleanupTimeout) > 0 { httpsServer.IdleTimeout = s.CleanupTimeout } httpsServer.Handler = s.handler // Inspired by https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go httpsServer.TLSConfig = &tls.Config{ // Causes servers to use Go's default ciphersuite preferences, // which are tuned to avoid attacks. Does nothing on clients. PreferServerCipherSuites: true, // Only use curves which have assembly implementations // https://github.com/golang/go/tree/master/src/crypto/elliptic CurvePreferences: []tls.CurveID{tls.CurveP256}, // Use modern tls mode https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility NextProtos: []string{"h2", "http/1.1"}, // https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols MinVersion: tls.VersionTLS12, // These ciphersuites support Forward Secrecy: https://en.wikipedia.org/wiki/Forward_secrecy CipherSuites: []uint16{ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, }, } // build standard config from server options if s.TLSCertificate != "" && s.TLSCertificateKey != "" { httpsServer.TLSConfig.Certificates = make([]tls.Certificate, 1) httpsServer.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(s.TLSCertificate, s.TLSCertificateKey) if err != nil { return err } } if s.TLSCACertificate != "" { // include specified CA certificate caCert, caCertErr := os.ReadFile(s.TLSCACertificate) if caCertErr != nil { return caCertErr } caCertPool := x509.NewCertPool() ok := caCertPool.AppendCertsFromPEM(caCert) if !ok { return fmt.Errorf("cannot parse CA certificate") } httpsServer.TLSConfig.ClientCAs = caCertPool httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert } // call custom TLS configurator configureTLS(httpsServer.TLSConfig) if len(httpsServer.TLSConfig.Certificates) == 0 && httpsServer.TLSConfig.GetCertificate == nil { // after standard and custom config are passed, this ends up with no certificate if s.TLSCertificate == "" { if s.TLSCertificateKey == "" { s.Fatalf("the required flags `--tls-certificate` and `--tls-key` were not specified") } s.Fatalf("the required flag `--tls-certificate` was not specified") } if s.TLSCertificateKey == "" { s.Fatalf("the required flag `--tls-key` was not specified") } // this happens with a wrong custom TLS configurator s.Fatalf("no certificate was configured for TLS") } configureServer(httpsServer, "https", s.httpsServerL.Addr().String()) servers = append(servers, httpsServer) wg.Add(1) s.Logf("Serving timestamp server at https://%s", s.httpsServerL.Addr()) go func(l net.Listener) { defer wg.Done() if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed { s.Fatalf("%v", err) } s.Logf("Stopped serving timestamp server at https://%s", l.Addr()) }(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig)) } wg.Add(1) go s.handleShutdown(wg, &servers) wg.Wait() return nil } // Listen creates the listeners for the server func (s *Server) Listen() error { if s.hasListeners { // already done this return nil } if s.hasScheme(schemeHTTPS) { // Use http host if https host wasn't defined if s.TLSHost == "" { s.TLSHost = s.Host } // Use http listen limit if https listen limit wasn't defined if s.TLSListenLimit == 0 { s.TLSListenLimit = s.ListenLimit } // Use http tcp keep alive if https tcp keep alive wasn't defined if int64(s.TLSKeepAlive) == 0 { s.TLSKeepAlive = s.KeepAlive } // Use http read timeout if https read timeout wasn't defined if int64(s.TLSReadTimeout) == 0 { s.TLSReadTimeout = s.ReadTimeout } // Use http write timeout if https write timeout wasn't defined if int64(s.TLSWriteTimeout) == 0 { s.TLSWriteTimeout = s.WriteTimeout } } if s.hasScheme(schemeUnix) { domSockListener, err := net.Listen("unix", string(s.SocketPath)) if err != nil { return err } s.domainSocketL = domSockListener } if s.hasScheme(schemeHTTP) { listener, err := net.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port))) if err != nil { return err } h, p, err := swag.SplitHostPort(listener.Addr().String()) if err != nil { return err } s.Host = h s.Port = p s.httpServerL = listener } if s.hasScheme(schemeHTTPS) { tlsListener, err := net.Listen("tcp", net.JoinHostPort(s.TLSHost, strconv.Itoa(s.TLSPort))) if err != nil { return err } sh, sp, err := swag.SplitHostPort(tlsListener.Addr().String()) if err != nil { return err } s.TLSHost = sh s.TLSPort = sp s.httpsServerL = tlsListener } s.hasListeners = true return nil } // Shutdown server and clean up resources func (s *Server) Shutdown() error { if atomic.CompareAndSwapInt32(&s.shuttingDown, 0, 1) { close(s.shutdown) } return nil } func (s *Server) handleShutdown(wg *sync.WaitGroup, serversPtr *[]*http.Server) { // wg.Done must occur last, after s.api.ServerShutdown() // (to preserve old behaviour) defer wg.Done() <-s.shutdown servers := *serversPtr ctx, cancel := context.WithTimeout(context.TODO(), s.GracefulTimeout) defer cancel() // first execute the pre-shutdown hook s.api.PreServerShutdown() shutdownChan := make(chan bool) for i := range servers { server := servers[i] go func() { var success bool defer func() { shutdownChan <- success }() if err := server.Shutdown(ctx); err != nil { // Error from closing listeners, or context timeout: s.Logf("HTTP server Shutdown: %v", err) } else { success = true } }() } // Wait until all listeners have successfully shut down before calling ServerShutdown success := true for range servers { success = success && <-shutdownChan } if success { s.api.ServerShutdown() } } // GetHandler returns a handler useful for testing func (s *Server) GetHandler() http.Handler { return s.handler } // SetHandler allows for setting a http handler on this server func (s *Server) SetHandler(handler http.Handler) { s.handler = handler } // UnixListener returns the domain socket listener func (s *Server) UnixListener() (net.Listener, error) { if !s.hasListeners { if err := s.Listen(); err != nil { return nil, err } } return s.domainSocketL, nil } // HTTPListener returns the http listener func (s *Server) HTTPListener() (net.Listener, error) { if !s.hasListeners { if err := s.Listen(); err != nil { return nil, err } } return s.httpServerL, nil } // TLSListener returns the https listener func (s *Server) TLSListener() (net.Listener, error) { if !s.hasListeners { if err := s.Listen(); err != nil { return nil, err } } return s.httpsServerL, nil } func handleInterrupt(once *sync.Once, s *Server) { once.Do(func() { for range s.interrupt { if s.interrupted { s.Logf("Server already shutting down") continue } s.interrupted = true s.Logf("Shutting down... ") if err := s.Shutdown(); err != nil { s.Logf("HTTP server Shutdown: %v", err) } } }) } func signalNotify(interrupt chan<- os.Signal) { signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/internal/000077500000000000000000000000001470602636300245345ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/internal/cmdparams/000077500000000000000000000000001470602636300265035ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/internal/cmdparams/cmdparams.go000066400000000000000000000016611470602636300310050ustar00rootroot00000000000000// // Copyright 2023 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cmdparams // IsHTTPPingOnly is set off the command-line flag to enforce limiting // the non-mTLS http server to only serving the /ping entrypoint. // It should be set only once when processing command-line flags // and then used only in pkg/generated/restapi/configure_timestamp_server.go // and as read-only. var IsHTTPPingOnly bool golang-github-sigstore-timestamp-authority-1.2.3/pkg/internal/cmdparams/doc.go000066400000000000000000000014111470602636300275740ustar00rootroot00000000000000// // Copyright 2023 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package cmdparams contains variables to propagate from command-line // flags to their handling in // pkg/generated/restapi/configure_timestamp_server.go. package cmdparams golang-github-sigstore-timestamp-authority-1.2.3/pkg/log/000077500000000000000000000000001470602636300235015ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/log/log.go000066400000000000000000000040201470602636300246050ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package log import ( "context" "log" "net/http" "github.com/go-chi/chi/middleware" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) // Logger set the default logger to development mode var Logger *zap.SugaredLogger func init() { ConfigureLogger("dev") } func ConfigureLogger(logType string) { var cfg zap.Config if logType == "prod" { cfg = zap.NewProductionConfig() cfg.EncoderConfig.LevelKey = "severity" cfg.EncoderConfig.MessageKey = "message" } else { cfg = zap.NewDevelopmentConfig() cfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder } logger, err := cfg.Build() if err != nil { log.Fatalln("createLogger", err) } Logger = logger.Sugar() } var CliLogger = createCliLogger() func createCliLogger() *zap.SugaredLogger { cfg := zap.NewDevelopmentConfig() cfg.EncoderConfig.TimeKey = "" cfg.EncoderConfig.LevelKey = "" cfg.DisableCaller = true cfg.DisableStacktrace = true logger, err := cfg.Build() if err != nil { log.Fatalln("createLogger", err) } return logger.Sugar() } func WithRequestID(ctx context.Context, id string) context.Context { return context.WithValue(ctx, middleware.RequestIDKey, id) } func RequestIDLogger(r *http.Request) *zap.SugaredLogger { proposedLogger := Logger if r != nil { if ctxRequestID, ok := r.Context().Value(middleware.RequestIDKey).(string); ok { proposedLogger = proposedLogger.With(zap.String("requestID", ctxRequestID)) } } return proposedLogger } golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/000077500000000000000000000000001470602636300251315ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/config.go000066400000000000000000000034471470602636300267350ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ntpmonitor import ( // a blank import is recommended by the Go docs // when using embed with byte slices _ "embed" "fmt" "os" "gopkg.in/yaml.v3" ) //go:embed ntpsync.yaml 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"` } // LoadConfig reads a yaml file from a provided path, instantiating a new // Config object with the vales found. No sanity checking is made of the // loaded values. func LoadConfig(path string) (*Config, error) { var configData []byte if path == "" { configData = defaultConfigData } else { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("failed to read file: %s %w", path, err) } configData = data } var cfg Config if err := yaml.Unmarshal(configData, &cfg); err != nil { return nil, fmt.Errorf("failed to parse YAML: %w", err) } return &cfg, nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/config_test.go000066400000000000000000000071161470602636300277710ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ntpmonitor import ( "os" "path" "testing" "gopkg.in/yaml.v3" ) var yamlData = ` # Number of attempts to contact a ntp server before giving up. request_attempts: 2 # The timeout in seconds for a request to respond. This value must be # smaller than max_time_delta. request_timeout: 1 # Number of randomly selected ntp servers to interrogate. num_servers: 2 # Number of servers who must agree with local time. server_threshold: 1 # Maximum number of seconds the local time is allowed to drift from the # response of a ntp server max_time_delta: 2 # Period (in seconds) for polling ntp servers period: 80 # List of servers to contact. Many DNS names resolves to multiple A records. servers: # # stratum 1 servers: # # Apple AS6185 - "time.apple.com" # Google AS15169 - "time.google.com" ` func TestLoadConfig(t *testing.T) { // create test custom config for testing var dir = t.TempDir() var path = path.Join(dir, "cfg.yaml") f, err := os.Create(path) if err != nil { t.Fatal(err) } if _, err = f.Write([]byte(yamlData)); err != nil { t.Fatal(err) } f.Close() // create default config for testing var defaultConfig Config if err = yaml.Unmarshal(defaultConfigData, &defaultConfig); err != nil { t.Fatalf("failed to parse default config YAML: %v", err) } type test struct { configPath string expectedConfig Config } tests := []test{ { configPath: path, expectedConfig: Config{ RequestAttempts: 2, RequestTimeout: 1, NumServers: 2, ServerThreshold: 1, MaxTimeDelta: 2, Period: 80, Servers: []string{"a", "b"}, }, }, { configPath: "ntpsync.yaml", expectedConfig: defaultConfig, }, } for _, tc := range tests { cfg, err := LoadConfig(tc.configPath) if err != nil { t.Fatal(err) } if cfg == nil { t.Fatal("no config returned") } if cfg.RequestAttempts != tc.expectedConfig.RequestAttempts { t.Errorf("request attempts, got %d expected %d", cfg.RequestAttempts, tc.expectedConfig.RequestAttempts) } if cfg.RequestTimeout != tc.expectedConfig.RequestTimeout { t.Errorf("request timeout, got %d expected %d", cfg.RequestTimeout, tc.expectedConfig.RequestTimeout) } if cfg.NumServers != tc.expectedConfig.NumServers { t.Errorf("num servers, got %d expected %d", cfg.NumServers, tc.expectedConfig.NumServers) } if cfg.ServerThreshold != tc.expectedConfig.ServerThreshold { t.Errorf("server threshold, got %d expected %d", cfg.ServerThreshold, tc.expectedConfig.ServerThreshold) } if cfg.MaxTimeDelta != tc.expectedConfig.MaxTimeDelta { t.Errorf("max time delta, got %d expected %d", cfg.MaxTimeDelta, tc.expectedConfig.MaxTimeDelta) } if cfg.Period != tc.expectedConfig.Period { t.Errorf("period, got %d expected %d", cfg.Period, tc.expectedConfig.Period) } if len(cfg.Servers) != len(tc.expectedConfig.Servers) { t.Errorf("number of servers in list, got %d expected %d", len(cfg.Servers), len(tc.expectedConfig.Servers)) } } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/ntpmonitor.go000066400000000000000000000145441470602636300277010ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ntpmonitor import ( "errors" "fmt" "math/rand" "sync/atomic" "time" "github.com/beevik/ntp" pkgapi "github.com/sigstore/timestamp-authority/pkg/api" "github.com/sigstore/timestamp-authority/pkg/log" ) var ( // ErrInvTime indicates that the local time has drifted too much // from the monitored NTP servers. ErrInvTime = errors.New("local time differs from observed") // ErrTooFewServers means that the number of trusted servers are // smaller then the selected num servers to query. ErrTooFewServers = errors.New("too few ntp servers configured") // ErrNoResponse indicates that there is an error to communicate with // the remote NTP servers ErrNoResponse = errors.New("no ntp response") // ErrThreshold means that there is no positive threshold value ErrThreshold = errors.New("no valid server threshold set") // ErrDeltaTooSmall is referring to when the max delta time is // smaller than the request timeout which can give unstable behaviour. ErrDeltaTooSmall = errors.New("delta is too small") ) type serverResponses struct { tooFewServerResponses bool tooManyInvalidResponses bool } type NTPClient interface { QueryWithOptions(srv string, opts ntp.QueryOptions) (*ntp.Response, error) } type LiveNTPClient struct{} func (c LiveNTPClient) QueryWithOptions(srv string, opts ntp.QueryOptions) (*ntp.Response, error) { return ntp.QueryWithOptions(srv, opts) } // NTPMonitor compares the local time with a set of trusted NTP servers. type NTPMonitor struct { cfg *Config run atomic.Bool ntpClient NTPClient } // New creates a NTPMonitor, reading the configuration from the provided // path. func New(configFile string) (*NTPMonitor, error) { cfg, err := LoadConfig(configFile) if err != nil { return nil, err } return NewFromConfig(cfg) } // NewFromConfig creates a NTPMonitor from an instantiated configuration. func NewFromConfig(cfg *Config) (*NTPMonitor, error) { // default to using a live NTP client liveNTPClient := LiveNTPClient{} return NewFromConfigWithClient(cfg, liveNTPClient) } func NewFromConfigWithClient(cfg *Config, client NTPClient) (*NTPMonitor, error) { if len(cfg.Servers) == 0 || len(cfg.Servers) < cfg.NumServers { return nil, ErrTooFewServers } if cfg.ServerThreshold < 1 { return nil, ErrThreshold } if cfg.ServerThreshold > cfg.NumServers { return nil, ErrTooFewServers } if cfg.RequestTimeout < 1 || cfg.MaxTimeDelta < cfg.RequestTimeout { return nil, ErrDeltaTooSmall } return &NTPMonitor{cfg: cfg, ntpClient: client}, nil } func (n *NTPMonitor) queryServers(delta time.Duration, servers []string) serverResponses { validResponses := 0 noResponse := 0 for _, srv := range servers { // Create a time interval from 'now' with the max // time delta added/removed // Make sure the time from the remote NTP server lies // within this interval. resp, err := n.queryNTPServer(srv) if err != nil { log.Logger.Errorf("ntp response timeout from %s", srv) noResponse++ continue } // ClockOffset is the estimated difference from // local time to NTP server's time. // The estimate assumes latency is similar for both // sending and receiving data. // The estimated offset does not depend on the value // of the latency. if resp.ClockOffset.Abs() > delta { log.Logger.Warnf("local time is different from %s: %s", srv, resp.Time) } else { validResponses++ } } // Did enough NTP servers respond? return serverResponses{ tooFewServerResponses: n.cfg.ServerThreshold > n.cfg.NumServers-noResponse, tooManyInvalidResponses: n.cfg.ServerThreshold > validResponses, } } // Start the periodic monitor. Once started, it runs until Stop() is called, func (n *NTPMonitor) Start() { n.run.Store(true) if n.cfg.RequestTimeout < 1 { log.Logger.Warnf("NTP request timeout not set, default to 1s") n.cfg.RequestTimeout = 1 } delta := time.Duration(n.cfg.MaxTimeDelta) * time.Second log.Logger.Info("ntp monitoring starting") //nolint:gosec r := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) // initialize local pseudorandom generator //nolint:gosec for n.run.Load() { servers := RandomChoice(n.cfg.Servers, n.cfg.NumServers, r) responses := n.queryServers(delta, servers) // Did enough NTP servers respond? if responses.tooFewServerResponses { pkgapi.MetricNTPErrorCount.With(map[string]string{ "reason": "err_too_few", }).Inc() } if responses.tooManyInvalidResponses { pkgapi.MetricNTPErrorCount.With(map[string]string{ "reason": "err_inv_time", }).Inc() } // Local time is in sync. Wait for next poll. time.Sleep(time.Duration(n.cfg.Period) * time.Second) } log.Logger.Info("ntp monitoring stopped") } // Stop the monitoring. func (n *NTPMonitor) Stop() { log.Logger.Info("stopping ntp monitoring") n.run.Store(false) } // queryNTPServer queries a provided ntp server, trying up to a configured // amount of times. There is one second sleep between each attempt. func (n *NTPMonitor) queryNTPServer(srv string) (*ntp.Response, error) { var i = 1 for { log.Logger.Debugf("querying ntp server %s", srv) start := time.Now() opts := ntp.QueryOptions{ Timeout: time.Duration(n.cfg.RequestTimeout) * time.Second, } resp, err := n.ntpClient.QueryWithOptions(srv, opts) pkgapi.MetricNTPLatency.With(map[string]string{ "host": srv, }).Observe(float64(time.Since(start))) if err == nil { pkgapi.MetricNTPSyncCount.With(map[string]string{ "failed": "false", "host": srv, }).Inc() return resp, nil } pkgapi.MetricNTPSyncCount.With(map[string]string{ "failed": "true", "host": srv, }).Inc() log.Logger.Infof("ntp timeout from %s, attempt %d/%d", srv, i, n.cfg.RequestAttempts) if i == n.cfg.RequestAttempts { break } i++ time.Sleep(time.Second) } return nil, fmt.Errorf("ntp timeout: %s", srv) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/ntpmonitor_test.go000066400000000000000000000213131470602636300307300ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ntpmonitor import ( "errors" "testing" "time" "github.com/beevik/ntp" "github.com/prometheus/client_golang/prometheus/testutil" pkgapi "github.com/sigstore/timestamp-authority/pkg/api" ) type MockNTPClient struct { // add the names of servers that MockNTPClient#QueryWithOptions should // always return an error response for ignoredServers map[string]string } func (c MockNTPClient) QueryWithOptions(srv string, _ ntp.QueryOptions) (*ntp.Response, error) { if _, ok := c.ignoredServers[srv]; ok { return nil, errors.New("failed to query NTP server") } return &ntp.Response{ ClockOffset: 1, Time: time.Now(), }, nil } type driftedTimeNTPClient struct { driftedOffset time.Duration } func (c driftedTimeNTPClient) QueryWithOptions(_ string, _ ntp.QueryOptions) (*ntp.Response, error) { return &ntp.Response{ ClockOffset: c.driftedOffset, Time: time.Now(), }, nil } func TestNewFromConfig(t *testing.T) { var cfg Config var nm *NTPMonitor var err error // No servers listed nm, err = NewFromConfig(&cfg) if nm != nil { t.Error("non expected monitor returned") } if err != ErrTooFewServers { t.Errorf("expected error %s got %s", ErrTooFewServers, err) } // Number of servers are smaller than requested cfg.Servers = append(cfg.Servers, "foo.bar") cfg.NumServers = 2 nm, err = NewFromConfig(&cfg) if nm != nil { t.Error("non expected monitor returned") } if err != ErrTooFewServers { t.Errorf("expected error %s got %s", ErrTooFewServers, err) } // Add a new server so len(servers) == num servers cfg.Servers = append(cfg.Servers, "foo.bar") // Threshold smaller than num servers cfg.ServerThreshold = 3 nm, err = NewFromConfig(&cfg) if nm != nil { t.Error("non expected monitor returned") } if err != ErrTooFewServers { t.Errorf("expected error %s got %s", ErrTooFewServers, err) } // Set threshold to zero cfg.ServerThreshold = 0 nm, err = NewFromConfig(&cfg) if nm != nil { t.Error("non expected monitor returned") } if err != ErrThreshold { t.Errorf("expected error %s got %s", ErrThreshold, err) } // Set threshold to two (len of servers) cfg.ServerThreshold = 2 // Max delta is 0 nm, err = NewFromConfig(&cfg) if nm != nil { t.Error("non expected monitor returned") } if err != ErrDeltaTooSmall { t.Errorf("expected error %s got %s", ErrDeltaTooSmall, err) } // Max delta is greater than request timeout cfg.RequestTimeout = 1 nm, err = NewFromConfig(&cfg) if nm != nil { t.Error("non expected monitor returned") } if err != ErrDeltaTooSmall { t.Errorf("expected error %s got %s", ErrDeltaTooSmall, err) } // Valid config cfg.MaxTimeDelta = 1 nm, err = NewFromConfig(&cfg) if nm == nil { t.Error("expected monitor returned") } if err != nil { t.Errorf("unexpected error %s", err) } } func TestNTPMonitorQueryNTPServer(t *testing.T) { mockNTP := MockNTPClient{} failNTP := MockNTPClient{ ignoredServers: map[string]string{ "s1": "", }, } testCases := []struct { name string client MockNTPClient config Config expectedSuccessfulMetricCount int expectedFailedMetricCount int expectTestToPass bool }{ { name: "Successfully query NTP server", client: mockNTP, config: Config{ Servers: []string{"s1"}, NumServers: 1, RequestAttempts: 1, ServerThreshold: 1, RequestTimeout: 1, MaxTimeDelta: 1, }, expectedSuccessfulMetricCount: 1, expectedFailedMetricCount: 0, expectTestToPass: true, }, { name: "Fail to query NTP server", client: failNTP, config: Config{ Servers: []string{"s1"}, NumServers: 1, RequestAttempts: 3, ServerThreshold: 1, RequestTimeout: 5, MaxTimeDelta: 6, }, expectedSuccessfulMetricCount: 0, expectedFailedMetricCount: 3, expectTestToPass: false, }, } for _, tc := range testCases { // reset the CounterVec before each test case so we can check for // the expected metric count pkgapi.MetricNTPSyncCount.Reset() monitor, err := NewFromConfigWithClient(&tc.config, tc.client) if err != nil { t.Fatalf("unexpectedly failed to create NTP monitor: %v", err) } resp, err := monitor.queryNTPServer("s1") if tc.expectTestToPass && err != nil { t.Errorf("test '%s' unexpectedly failed with non-nil error: %v", tc.name, err) } if tc.expectTestToPass && resp == nil { t.Errorf("test '%s' unexpectedly failed with nil ntp.Response", tc.name) } if !tc.expectTestToPass && err == nil { t.Errorf("test '%s' unexpectedly passed with a nil error", tc.name) } // check that the actual metric value was incremented by one as expected successfulMetricCount := testutil.ToFloat64(pkgapi.MetricNTPSyncCount.With(map[string]string{ "failed": "false", "host": "s1", })) if tc.expectedSuccessfulMetricCount != int(successfulMetricCount) { t.Errorf("test '%s' unexpectedly failed with wrong successful metric value %d, expected %d", tc.name, int(successfulMetricCount), tc.expectedSuccessfulMetricCount) } // check that the actual metric value was incremented by one as expected failedMetricCount := testutil.ToFloat64(pkgapi.MetricNTPSyncCount.With(map[string]string{ "failed": "true", "host": "s1", })) if tc.expectedFailedMetricCount != int(failedMetricCount) { t.Errorf("test '%s' unexpectedly failed with wrong failed metric value %d, expected %d", tc.name, int(failedMetricCount), tc.expectedFailedMetricCount) } } } func TestNTPMonitorQueryServers(t *testing.T) { mockNTP := MockNTPClient{} failNTP := MockNTPClient{ ignoredServers: map[string]string{"s1": "", "s2": "", "s3": ""}, } partialFailNTP := MockNTPClient{ ignoredServers: map[string]string{"s2": "", "s3": ""}, } offsetDuration, err := time.ParseDuration("5s") if err != nil { t.Fatalf("unexpected failed to parse duration: %v", err) } driftedNTP := driftedTimeNTPClient{ driftedOffset: offsetDuration, } testCases := []struct { name string client NTPClient serverThreshold int maxTimeDelta int expectEnoughServerResponse bool expectValidServerResponse bool }{ { name: "Successfully query all NTP servers", client: mockNTP, serverThreshold: 3, maxTimeDelta: 3, expectEnoughServerResponse: true, expectValidServerResponse: true, }, { name: "Receive too few server responses", client: partialFailNTP, serverThreshold: 2, maxTimeDelta: 5, expectEnoughServerResponse: false, expectValidServerResponse: false, }, { name: "Receive too many drifted time responses", client: driftedNTP, serverThreshold: 2, maxTimeDelta: 2, expectEnoughServerResponse: true, expectValidServerResponse: false, }, { name: "Fail to receive any responses", client: failNTP, serverThreshold: 1, maxTimeDelta: 4, expectEnoughServerResponse: false, expectValidServerResponse: false, }, } for _, tc := range testCases { monitor, err := NewFromConfigWithClient(&Config{ Servers: []string{"s1", "s2", "s3", "s4", "s5", "s6"}, NumServers: 3, Period: 1, RequestAttempts: 1, RequestTimeout: 1, ServerThreshold: tc.serverThreshold, MaxTimeDelta: tc.maxTimeDelta, }, tc.client) if err != nil { t.Fatalf("unexpectedly failed to create NTP monitor: %v", err) } delta := time.Duration(tc.maxTimeDelta) * time.Second testedServers := []string{"s1", "s2", "s3"} responses := monitor.queryServers(delta, testedServers) if tc.expectEnoughServerResponse && responses.tooFewServerResponses { t.Errorf("test '%s' unexpectedly failed with too few server responses", tc.name) } if tc.expectValidServerResponse && responses.tooManyInvalidResponses { t.Errorf("test '%s' unexpectedly failed with too many invalid responses", tc.name) } } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/ntpsync.yaml000066400000000000000000000040401470602636300275110ustar00rootroot00000000000000# # Copyright 2022 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Number of attempts to contact a ntp server before giving up. request_attempts: 3 # The timeout in seconds for a request to respond. This value must be # smaller than max_time_delta. request_timeout: 5 # Number of randomly selected ntp servers to interrogate. num_servers: 4 # Number of servers who must agree with local time. server_threshold: 3 # Maximum number of seconds the local time is allowed to drift from the # response of a ntp server max_time_delta: 6 # Period (in seconds) for polling ntp servers period: 60 # List of servers to contact. Many DNS names resolves to multiple A records. servers: # # stratum 1 servers: # # Apple AS6185 - "time.apple.com" # Google AS15169 - "time.google.com" - "time1.google.com" - "time2.google.com" - "time3.google.com" - "time4.google.com" # Nist AS49 AS104 - "time-a-b.nist.gov" - "time-b-b.nist.gov" - "time-c-b.nist.gov" - "time-d-b.nist.gov" # time-*-g.nist.gov times out a lot # "time-a-g.nist.gov" # "time-b-g.nist.gov" # "time-c-g.nist.gov" # "time-d-g.nist.gov" # Netnod AS57021 - "gbg1.ntp.se" - "gbg2.ntp.se" - "mmo1.ntp.se" - "mmo2.ntp.se" - "sth1.ntp.se" - "sth2.ntp.se" - "svl1.ntp.se" - "svl2.ntp.se" # Berkely AS25 - "ntp1.net.berkeley.edu" - "ntp2.net.berkeley.edu" # # stratum 3 servers: # # Cloudflare AS13335 - "time.cloudflare.com" # Microsoft AS8075 - "time.windows.com" # # stratum 4 servers: # # AWS AS16509 - "time.aws.com" golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/randomchoice.go000066400000000000000000000025301470602636300301130ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ntpmonitor import ( "math/rand" ) // RandomChoice returns a random selection of n items from the slice s. // The choice is made using a PSEUDO RANDOM selection. // If n is greater than len(s), an empty slice is returned. func RandomChoice[T any](s []T, n int, r *rand.Rand) []T { if n > len(s) || n < 1 { return []T{} } if n == len(s) { return s } var indices = make([]int, len(s)) var result = make([]T, 0, n) for i := range s { indices[i] = i } for { // The use of deterministic (pseudo) random generators are // ok for this use-case. //nolint:gosec i := r.Intn(len(indices)) result = append(result, s[indices[i]]) if len(result) == n { break } indices = append(indices[:i], indices[i+1:]...) } return result } golang-github-sigstore-timestamp-authority-1.2.3/pkg/ntpmonitor/randomchoice_test.go000066400000000000000000000036651470602636300311640ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ntpmonitor import ( "math/rand" "testing" ) var seed = int64(1668159633) func TestEmptySelection(t *testing.T) { cases := []struct { input []string n int }{ { input: []string{}, n: -1, }, { input: []string{}, n: 0, }, { input: []string{}, n: 1, }, { input: []string{"a", "b"}, n: -1, }, { input: []string{"a", "b"}, n: 0, }, { input: []string{"a", "b"}, n: 4, }, } r := rand.New(rand.NewSource(seed)) // initialize local pseudorandom generator for _, c := range cases { got := RandomChoice(c.input, c.n, r) if len(got) != 0 { t.Fail() } } } func TestSelection(t *testing.T) { cases := []struct { input []string n int want []string }{ { input: []string{"a"}, n: 1, want: []string{"a"}, }, { input: []string{"a", "b", "c", "d"}, n: 1, want: []string{"b"}, }, { input: []string{"a", "b", "c", "d", "e", "f", "g"}, n: 3, want: []string{"d", "e", "a"}, }, } r := rand.New(rand.NewSource(seed)) // initialize local pseudorandom generator for _, c := range cases { got := RandomChoice(c.input, c.n, r) if len(got) != len(c.want) { t.Fail() } for i := range got { if got[i] != c.want[i] { t.Errorf("expected '%s' got '%s'", c.want[i], got[i]) } } } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/server/000077500000000000000000000000001470602636300242265ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/server/pprof.go000066400000000000000000000021251470602636300257030ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package server import ( "net/http" "net/http/pprof" "time" ) // NewPprofServer creates a server for handling pprof func NewPprofServer(readTimeout, writeTimeout time.Duration) *http.Server { mux := http.NewServeMux() mux.HandleFunc("/debug/pprof/", pprof.Index) mux.HandleFunc("/debug/pprof/{action}", pprof.Index) mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) return &http.Server{ Addr: ":6060", ReadTimeout: readTimeout, WriteTimeout: writeTimeout, Handler: mux, } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/server/prometheus.go000066400000000000000000000017561470602636300267610ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package server import ( "net/http" "time" "github.com/prometheus/client_golang/prometheus/promhttp" ) // NewPrometheusServer creates a server for serving prometheus metrics func NewPrometheusServer(readTimeout, writeTimeout time.Duration) *http.Server { return &http.Server{ Addr: ":2112", ReadTimeout: readTimeout, WriteTimeout: writeTimeout, Handler: promhttp.Handler(), } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/server/restapi.go000066400000000000000000000027721470602636300262340ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package server import ( "time" "github.com/go-openapi/loads" "github.com/sigstore/timestamp-authority/pkg/api" "github.com/sigstore/timestamp-authority/pkg/generated/restapi" "github.com/sigstore/timestamp-authority/pkg/generated/restapi/operations" "github.com/sigstore/timestamp-authority/pkg/internal/cmdparams" ) // NewRestAPIServer creates a server for serving the rest API TSA service func NewRestAPIServer(host string, port int, scheme []string, httpReadOnly bool, readTimeout, writeTimeout time.Duration) *restapi.Server { doc, _ := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON) server := restapi.NewServer(operations.NewTimestampServerAPI(doc)) server.Host = host server.Port = port server.EnabledListeners = scheme server.ReadTimeout = readTimeout server.WriteTimeout = writeTimeout cmdparams.IsHTTPPingOnly = httpReadOnly api.ConfigureAPI() server.ConfigureAPI() return server } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/000077500000000000000000000000001470602636300242075ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/file.go000066400000000000000000000035071470602636300254620ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signer import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "fmt" "github.com/sigstore/sigstore/pkg/signature" "go.step.sm/crypto/pemutil" ) // File returns a file-based signer and verifier, used for local testing type File struct { crypto.Signer } func NewFileSigner(keyPath, keyPass string, hash crypto.Hash) (*File, error) { opaqueKey, err := pemutil.Read(keyPath, pemutil.WithPassword([]byte(keyPass))) if err != nil { return nil, fmt.Errorf("file: provide a valid signer, %s is not valid: %w", keyPath, err) } // Cannot use signature.LoadSignerVerifier because the SignerVerifier interface does not extend crypto.Signer switch pk := opaqueKey.(type) { case *rsa.PrivateKey: signer, err := signature.LoadRSAPKCS1v15SignerVerifier(pk, hash) if err != nil { return nil, err } return &File{signer}, nil case *ecdsa.PrivateKey: signer, err := signature.LoadECDSASignerVerifier(pk, hash) if err != nil { return nil, err } return &File{signer}, nil case ed25519.PrivateKey: signer, err := signature.LoadED25519SignerVerifier(pk) if err != nil { return nil, err } return &File{signer}, nil default: return nil, fmt.Errorf("unsupported private key type, must be RSA, ECDSA, or ED25519") } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/file_test.go000066400000000000000000000047731470602636300265270ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signer import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "encoding/pem" "os" "path/filepath" "testing" "go.step.sm/crypto/pemutil" ) func TestNewFileSigner(t *testing.T) { td := t.TempDir() password := "password1!" _, ed25519Key, _ := ed25519.GenerateKey(rand.Reader) pemED25519, _ := pemutil.Serialize(ed25519Key, pemutil.WithPassword([]byte(password))) ed25519KeyFile := filepath.Join(td, "ed25519-key.pem") if err := os.WriteFile(ed25519KeyFile, pem.EncodeToMemory(pemED25519), 0644); err != nil { t.Fatal(err) } ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) pemECDSA, _ := pemutil.Serialize(ecdsaKey, pemutil.WithPassword([]byte(password))) ecdsaKeyFile := filepath.Join(td, "ecdsa-key.pem") if err := os.WriteFile(ecdsaKeyFile, pem.EncodeToMemory(pemECDSA), 0644); err != nil { t.Fatal(err) } rsaKey, _ := rsa.GenerateKey(rand.Reader, 4096) pemRSA, _ := pemutil.Serialize(rsaKey, pemutil.WithPassword([]byte(password))) rsaKeyFile := filepath.Join(td, "rsa-key.pem") if err := os.WriteFile(rsaKeyFile, pem.EncodeToMemory(pemRSA), 0644); err != nil { t.Fatal(err) } tests := []struct { name string keyPath string keyPass string wantErr bool }{ { name: "valid ECDSA", keyPath: ecdsaKeyFile, keyPass: password, wantErr: false, }, { name: "valid RSA", keyPath: rsaKeyFile, keyPass: password, wantErr: false, }, { name: "valid ed25519", keyPath: ed25519KeyFile, keyPass: password, wantErr: false, }, { name: "invalid password", keyPath: ecdsaKeyFile, keyPass: "123", wantErr: true, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tc := tc _, err := NewFileSigner(tc.keyPath, tc.keyPass, crypto.SHA256) if tc.wantErr != (err != nil) { t.Errorf("NewFileSigner() expected %t, got err %s", tc.wantErr, err) } }) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/memory.go000066400000000000000000000113431470602636300260500ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signer import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "fmt" "time" "github.com/pkg/errors" "github.com/sigstore/sigstore/pkg/cryptoutils" tsx509 "github.com/sigstore/timestamp-authority/pkg/x509" ) // NewTimestampingCertWithChain generates an in-memory certificate chain. func NewTimestampingCertWithChain(signer crypto.Signer) ([]*x509.Certificate, error) { now := time.Now() // generate root rootPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, fmt.Errorf("generating in-memory root key") } sn, err := cryptoutils.GenerateSerialNumber() if err != nil { return nil, fmt.Errorf("generating root serial number: %w", err) } rootCA := &x509.Certificate{ SerialNumber: sn, Subject: pkix.Name{ CommonName: "Test TSA Root", Organization: []string{"local"}, }, NotBefore: now.Add(-5 * time.Minute), NotAfter: now.AddDate(10, 0, 0), IsCA: true, BasicConstraintsValid: true, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, } rootCACertDER, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, rootPriv.Public(), rootPriv) if err != nil { return nil, fmt.Errorf("creating self-signed root CA: %w", err) } rootCACert, err := x509.ParseCertificate(rootCACertDER) if err != nil { return nil, fmt.Errorf("parsing root CA certificate: %w", err) } // generate subordinate sn, err = cryptoutils.GenerateSerialNumber() if err != nil { return nil, fmt.Errorf("generating subordinate serial number: %w", err) } subPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, fmt.Errorf("generating in-memory subordinate key") } subCA := &x509.Certificate{ SerialNumber: sn, Subject: pkix.Name{ CommonName: "Test TSA Intermediate", Organization: []string{"local"}, }, NotBefore: now.Add(-5 * time.Minute), NotAfter: now.AddDate(10, 0, 0), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping}, BasicConstraintsValid: true, IsCA: true, } subCACertDER, err := x509.CreateCertificate(rand.Reader, subCA, rootCACert, subPriv.Public(), rootPriv) if err != nil { return nil, fmt.Errorf("creating self-signed subordinate CA: %w", err) } subCACert, err := x509.ParseCertificate(subCACertDER) if err != nil { return nil, fmt.Errorf("parsing subordinate CA certificate: %w", err) } // generate leaf sn, err = cryptoutils.GenerateSerialNumber() if err != nil { return nil, fmt.Errorf("generating leaf serial number: %w", err) } timestampExt, err := asn1.Marshal([]asn1.ObjectIdentifier{tsx509.EKUTimestampingOID}) if err != nil { return nil, err } skid, err := cryptoutils.SKID(signer.Public()) if err != nil { return nil, err } cert := &x509.Certificate{ SerialNumber: sn, Subject: pkix.Name{ CommonName: "Test TSA Timestamping", Organization: []string{"local"}, }, SubjectKeyId: skid, NotBefore: now.Add(-3 * time.Minute), NotAfter: now.AddDate(9, 0, 0), IsCA: false, KeyUsage: x509.KeyUsageDigitalSignature, // set EKU to x509.ExtKeyUsageTimeStamping but with a critical bit ExtraExtensions: []pkix.Extension{ { Id: tsx509.EKUOID, Critical: true, Value: timestampExt, }, }, } certDER, err := x509.CreateCertificate(rand.Reader, cert, subCACert, signer.Public(), subPriv) if err != nil { return nil, errors.Wrap(err, "creating tsa certificate") } tsaCert, err := x509.ParseCertificate(certDER) if err != nil { return nil, err } // Verify and return the certificate chain root := x509.NewCertPool() root.AddCert(rootCACert) intermediate := x509.NewCertPool() intermediate.AddCert(subCACert) verifyOptions := x509.VerifyOptions{ Roots: root, Intermediates: intermediate, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping}, } if _, err = tsaCert.Verify(verifyOptions); err != nil { return nil, err } return []*x509.Certificate{tsaCert, subCACert, rootCACert}, nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/memory_test.go000066400000000000000000000040711470602636300271070ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signer import ( "bytes" "context" "crypto" "crypto/rand" "crypto/sha256" "testing" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" "github.com/sigstore/timestamp-authority/pkg/x509" ) func TestNewTimestampingCertWithChain(t *testing.T) { ctx := context.Background() signer, err := NewCryptoSigner(ctx, crypto.Hash(0), "memory", "", "", "", "", "", "") if err != nil { t.Fatalf("new signer: %v", err) } payload := []byte("payload") h := sha256.Sum256(payload) sig, err := signer.Sign(rand.Reader, h[:], nil) if err != nil { t.Fatalf("signing payload: %v", err) } // create and verify the certificate chain certChain, err := NewTimestampingCertWithChain(signer) if err != nil { t.Fatalf("generating timestamping cert: %v", err) } if len(certChain) != 3 { t.Fatalf("expected 3 certificates in chain, got %d", len(certChain)) } // verify that certificate can verify signature pkCert := certChain[0].PublicKey verifier, err := signature.LoadVerifier(pkCert, crypto.SHA256) if err != nil { t.Fatalf("initializing verifier: %v", err) } if err := verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(payload), options.WithContext(ctx)); err != nil { t.Fatalf("failed to verify signature: %v", err) } // verify that VerifyCertChain will successfully verify the chain if err := x509.VerifyCertChain(certChain, signer); err != nil { t.Fatalf("failed to verify certificate chain: %v", err) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/signer.go000066400000000000000000000046551470602636300260370ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signer import ( "context" "crypto" "crypto/elliptic" "crypto/rand" "fmt" "strings" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/kms" // Register the provider-specific plugins _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" _ "github.com/sigstore/sigstore/pkg/signature/kms/azure" _ "github.com/sigstore/sigstore/pkg/signature/kms/gcp" _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) const KMSScheme = "kms" const TinkScheme = "tink" const MemoryScheme = "memory" const FileScheme = "file" func NewCryptoSigner(ctx context.Context, hash crypto.Hash, signer, kmsKey, tinkKmsKey, tinkKeysetPath, hcVaultToken, fileSignerPath, fileSignerPasswd string) (crypto.Signer, error) { switch signer { case MemoryScheme: sv, _, err := signature.NewECDSASignerVerifier(elliptic.P256(), rand.Reader, crypto.SHA256) return sv, err case FileScheme: return NewFileSigner(fileSignerPath, fileSignerPasswd, hash) case KMSScheme: signer, err := kms.Get(ctx, kmsKey, hash) // hash is ignored for all KMS providers except Hashivault if err != nil { return nil, err } s, _, err := signer.CryptoSigner(ctx, func(_ error) {}) return s, err case TinkScheme: primaryKey, err := GetPrimaryKey(ctx, tinkKmsKey, hcVaultToken) if err != nil { return nil, err } return NewTinkSigner(ctx, tinkKeysetPath, primaryKey) default: return nil, fmt.Errorf("unsupported signer type: %s", signer) } } func HashToAlg(signerHashAlg string) (crypto.Hash, error) { lowercaseAlg := strings.ToLower(signerHashAlg) var hash crypto.Hash switch lowercaseAlg { case "sha256": hash = crypto.SHA256 case "sha384": hash = crypto.SHA384 case "sha512": hash = crypto.SHA512 default: return crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %s", lowercaseAlg) } return hash, nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/tink.go000066400000000000000000000161201470602636300255030ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package 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" ) // 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) { f, err := os.Open(filepath.Clean(tinkKeysetPath)) if err != nil { return nil, err } defer f.Close() kh, err := keyset.Read(keyset.NewJSONReader(f), primaryKey) if err != nil { return nil, err } signer, err := KeyHandleToSigner(kh) if err != nil { return nil, err } return signer, nil } // GetPrimaryKey returns a Tink AEAD encryption key from KMS // Supports GCP, AWS, and Vault func GetPrimaryKey(ctx context.Context, kmsKey, hcVaultToken string) (tink.AEAD, error) { switch { case strings.HasPrefix(kmsKey, "gcp-kms://"): gcpClient, err := gcpkms.NewClientWithOptions(ctx, kmsKey) if err != nil { return nil, err } registry.RegisterKMSClient(gcpClient) return gcpClient.GetAEAD(kmsKey) case strings.HasPrefix(kmsKey, "aws-kms://"): awsClient, err := awskms.NewClient(kmsKey) if err != nil { return nil, err } registry.RegisterKMSClient(awsClient) return awsClient.GetAEAD(kmsKey) case strings.HasPrefix(kmsKey, "hcvault://"): hcVaultClient, err := hcvault.NewClient(kmsKey, nil, hcVaultToken) if err != nil { return nil, err } registry.RegisterKMSClient(hcVaultClient) return hcVaultClient.GetAEAD(kmsKey) default: 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 } golang-github-sigstore-timestamp-authority-1.2.3/pkg/signer/tink_test.go000066400000000000000000000132621470602636300265460ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package 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" ) 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 { t.Fatalf("error creating AEAD key handle: %v", err) } a, err := aead.New(aeskh) if err != nil { t.Fatalf("error creating AEAD key: %v", err) } kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) if err != nil { t.Fatalf("error creating ECDSA key handle: %v", err) } khsigner, err := KeyHandleToSigner(kh) if err != nil { t.Fatalf("error converting ECDSA key handle to signer: %v", err) } dir := t.TempDir() keysetPath := filepath.Join(dir, "keyset.json.enc") f, err := os.Create(keysetPath) if err != nil { t.Fatalf("error creating file: %v", err) } defer f.Close() jsonWriter := keyset.NewJSONWriter(f) if err := kh.Write(jsonWriter, a); err != nil { t.Fatalf("error writing enc keyset: %v", err) } signer, err := NewTinkSigner(context.TODO(), keysetPath, a) if err != nil { t.Fatalf("unexpected error creating Tink signer: %v", err) } // Expect signer and key handle's public keys match if err := cryptoutils.EqualKeys(signer.Public(), khsigner.Public()); err != nil { t.Fatalf("keys of signer and key handle do not match: %v", err) } // Failure: Unable to decrypt keyset aeskh1, err := keyset.NewHandle(aead.AES256GCMKeyTemplate()) if err != nil { t.Fatalf("error creating AEAD key handle: %v", err) } a1, err := aead.New(aeskh1) if err != nil { t.Fatalf("error creating AEAD key: %v", err) } _, err = NewTinkSigner(context.TODO(), 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) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/tests/000077500000000000000000000000001470602636300240625ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/tests/api_test.go000066400000000000000000000313121470602636300262210ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tests import ( "bytes" "crypto" "crypto/sha256" "crypto/x509/pkix" "encoding/asn1" "encoding/json" "io" "math/big" "strings" "testing" "time" ts "github.com/digitorus/timestamp" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/timestamp-authority/pkg/api" "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/go-openapi/runtime" ) // TestSigner encapsulates a public key for verification type TestSigner struct { pubKey crypto.PublicKey } func (s TestSigner) Public() crypto.PublicKey { return s.pubKey } // unused func (s TestSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) (signature []byte, err error) { return nil, nil } func TestGetTimestampCertChain(t *testing.T) { url := createServer(t) c, err := client.GetTimestampClient(url) if err != nil { t.Fatalf("unexpected error creating client: %v", err) } chain, err := c.Timestamp.GetTimestampCertChain(nil) if err != nil { t.Fatalf("unexpected error getting timestamp chain: %v", err) } certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(chain.Payload)) if err != nil { t.Fatalf("unexpected error unmarshalling cert chain: %v", err) } signer := TestSigner{pubKey: certs[0].PublicKey} if err := x509.VerifyCertChain(certs, signer); err != nil { t.Fatalf("unexpected error verifying cert chain: %v", err) } } type timestampTestCase struct { name string reqMediaType string reqBytes []byte nonce *big.Int includeCerts bool policyOID asn1.ObjectIdentifier hash crypto.Hash } func TestGetTimestampResponse(t *testing.T) { testArtifact := "blobblobblobblobblobblobblobblobblob" testNonce := big.NewInt(1234) includeCerts := true hashFunc := crypto.SHA256 hashName := "sha256" opts := ts.RequestOptions{ Nonce: testNonce, Certificates: includeCerts, TSAPolicyOID: nil, Hash: hashFunc, } tests := []timestampTestCase{ { name: "Timestamp Query Request", reqMediaType: client.TimestampQueryMediaType, reqBytes: buildTimestampQueryReq(t, []byte(testArtifact), opts), nonce: testNonce, includeCerts: includeCerts, hash: hashFunc, }, { name: "JSON Request", reqMediaType: client.JSONMediaType, reqBytes: buildJSONReq(t, []byte(testArtifact), hashFunc, hashName, includeCerts, testNonce, ""), nonce: testNonce, includeCerts: includeCerts, hash: hashFunc, }, } for _, tc := range tests { url := createServer(t) c, err := client.GetTimestampClient(url, client.WithContentType(tc.reqMediaType)) if err != nil { t.Fatalf("test '%s': unexpected error creating client: %v", tc.name, err) } params := timestamp.NewGetTimestampResponseParams() params.SetTimeout(10 * time.Second) params.Request = io.NopCloser(bytes.NewReader(tc.reqBytes)) var respBytes bytes.Buffer clientOption := func(op *runtime.ClientOperation) { op.ConsumesMediaTypes = []string{tc.reqMediaType} } _, err = c.Timestamp.GetTimestampResponse(params, &respBytes, clientOption) if err != nil { t.Fatalf("test '%s': unexpected error getting timestamp response: %v", tc.name, err) } tsr, err := ts.ParseResponse(respBytes.Bytes()) if err != nil { t.Fatalf("test '%s': unexpected error parsing response: %v", tc.name, err) } // 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) } // check nonce if tsr.Nonce.Cmp(tc.nonce) != 0 { t.Fatalf("test '%s': expected nonce %d, got %d", tc.name, tc.nonce, tsr.Nonce) } // check hash and hashed message if tsr.HashAlgorithm != tc.hash { t.Fatalf("test '%s': unexpected hash algorithm", tc.name) } hashedMessage := sha256.Sum256([]byte(testArtifact)) if !bytes.Equal(tsr.HashedMessage, hashedMessage[:]) { t.Fatalf("test '%s': expected hashed messages to be equal: %v %v", tc.name, tsr.HashedMessage, hashedMessage) } // check time and accuracy if tsr.Time.After(time.Now()) { t.Fatalf("test '%s': expected time to be set to a previous time", tc.name) } duration, _ := time.ParseDuration("1s") if tsr.Accuracy != duration { t.Fatalf("test '%s': expected 1s accuracy, got %v", tc.name, tsr.Accuracy) } // check serial number if tsr.SerialNumber.Cmp(big.NewInt(0)) == 0 { t.Fatalf("test '%s': expected serial number, got 0", tc.name) } // check ordering and qualified defaults if tsr.Qualified { t.Fatalf("test '%s': tsr should not be qualified", tc.name) } if tsr.Ordering { t.Fatalf("test '%s': tsr should not be ordered", tc.name) } // check policy OID default if !tsr.Policy.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2}) { t.Fatalf("test '%s': unexpected policy ID", tc.name) } // check for no extensions if len(tsr.Extensions) != 0 { t.Fatalf("test '%s': expected 0 extensions, got %d", tc.name, len(tsr.Extensions)) } } } func TestGetTimestampResponseWithExtsAndOID(t *testing.T) { testArtifact := "blob" testNonce := big.NewInt(1234) testPolicyOID := asn1.ObjectIdentifier{1, 2, 3, 4, 5} oidStr := "1.2.3.4.5" includeCerts := true hashFunc := crypto.SHA256 hashName := "sha256" opts := ts.RequestOptions{ Nonce: testNonce, TSAPolicyOID: testPolicyOID, Hash: crypto.SHA256, } tests := []timestampTestCase{ { name: "Timestamp Query Request", reqMediaType: client.TimestampQueryMediaType, reqBytes: buildTimestampQueryReq(t, []byte(testArtifact), opts), nonce: testNonce, policyOID: testPolicyOID, }, { name: "JSON Request", reqMediaType: client.JSONMediaType, reqBytes: buildJSONReq(t, []byte(testArtifact), hashFunc, hashName, includeCerts, testNonce, oidStr), nonce: testNonce, policyOID: testPolicyOID, }, } for _, tc := range tests { url := createServer(t) c, err := client.GetTimestampClient(url, client.WithContentType(tc.reqMediaType)) if err != nil { t.Fatalf("test '%s': unexpected error creating client: %v", tc.name, err) } // populate additional request parameters for extensions and OID - atypical request structure var req *ts.Request if tc.reqMediaType == client.TimestampQueryMediaType { req, err = ts.ParseRequest(tc.reqBytes) if err != nil { t.Fatalf("test '%s': unexpected error parsing request: %v", tc.name, err) } } else { req, _, err = api.ParseJSONRequest(tc.reqBytes) if err != nil { t.Fatalf("test '%s': unexpected error parsing request: %v", tc.name, err) } } req.ExtraExtensions = []pkix.Extension{{Id: asn1.ObjectIdentifier{1, 2, 3, 4}, Value: []byte{1, 2, 3, 4}}} fakePolicyOID := asn1.ObjectIdentifier{1, 2, 3, 4, 5} req.TSAPolicyOID = fakePolicyOID tsq, err := req.Marshal() if err != nil { t.Fatalf("test '%s': unexpected error creating request: %v", tc.name, err) } params := timestamp.NewGetTimestampResponseParams() params.SetTimeout(10 * time.Second) params.Request = io.NopCloser(bytes.NewReader(tsq)) var respBytes bytes.Buffer clientOption := func(op *runtime.ClientOperation) { op.ConsumesMediaTypes = []string{client.TimestampQueryMediaType} } _, err = c.Timestamp.GetTimestampResponse(params, &respBytes, clientOption) if err != nil { t.Fatalf("test '%s': unexpected error getting timestamp response: %v", tc.name, err) } tsr, err := ts.ParseResponse(respBytes.Bytes()) if err != nil { t.Fatalf("test '%s': unexpected error parsing response: %v", tc.name, err) } // check policy OID if !tsr.Policy.Equal(fakePolicyOID) { t.Fatalf("test '%s': unexpected policy ID", tc.name) } // check extension is present if len(tsr.Extensions) != 1 { t.Fatalf("test '%s': expected 1 extension, got %d", tc.name, len(tsr.Extensions)) } } } func TestGetTimestampResponseWithNoCertificateOrNonce(t *testing.T) { testArtifact := "blob" includeCerts := false hashFunc := crypto.SHA256 hashName := "sha256" oidStr := "1.2.3.4" opts := ts.RequestOptions{ Certificates: includeCerts, Hash: crypto.SHA256, } tests := []timestampTestCase{ { name: "Timestamp Query Request", reqMediaType: client.TimestampQueryMediaType, reqBytes: buildTimestampQueryReq(t, []byte(testArtifact), opts), }, { name: "JSON Request", reqMediaType: client.JSONMediaType, reqBytes: buildJSONReq(t, []byte(testArtifact), hashFunc, hashName, includeCerts, nil, oidStr), }, } for _, tc := range tests { url := createServer(t) c, err := client.GetTimestampClient(url, client.WithContentType(tc.reqMediaType)) if err != nil { t.Fatalf("test '%s': unexpected error creating client: %v", tc.name, err) } params := timestamp.NewGetTimestampResponseParams() params.SetTimeout(10 * time.Second) params.Request = io.NopCloser(bytes.NewReader(tc.reqBytes)) var respBytes bytes.Buffer clientOption := func(op *runtime.ClientOperation) { op.ConsumesMediaTypes = []string{tc.reqMediaType} } _, err = c.Timestamp.GetTimestampResponse(params, &respBytes, clientOption) if err != nil { t.Fatalf("test '%s': unexpected error getting timestamp response: %v", tc.name, err) } tsr, err := ts.ParseResponse(respBytes.Bytes()) if err != nil { t.Fatalf("test '%s': unexpected error parsing response: %v", tc.name, err) } // check certificate fields if len(tsr.Certificates) != 0 { t.Fatalf("test '%s': expected 0 certificates, got %d", tc.name, len(tsr.Certificates)) } if tsr.AddTSACertificate { t.Fatalf("test '%s': expected no TSA certificate", tc.name) } // check nonce if tsr.Nonce != nil { t.Fatalf("test '%s': expected no nonce, got %d", tc.name, tsr.Nonce) } } } func TestUnsupportedHashAlgorithm(t *testing.T) { testArtifact := "blob" hashFunc := crypto.SHA1 hashName := "sha1" opts := ts.RequestOptions{ Hash: crypto.SHA1, } tests := []timestampTestCase{ { name: "Timestamp Query Request", reqMediaType: client.TimestampQueryMediaType, reqBytes: buildTimestampQueryReq(t, []byte(testArtifact), opts), }, { name: "JSON Request", reqMediaType: client.JSONMediaType, reqBytes: buildJSONReq(t, []byte(testArtifact), hashFunc, hashName, false, nil, "1.2.3.4"), }, } for _, tc := range tests { url := createServer(t) c, err := client.GetTimestampClient(url, client.WithContentType(tc.reqMediaType)) if err != nil { t.Fatalf("test '%s': unexpected error creating client: %v", tc.name, err) } params := timestamp.NewGetTimestampResponseParams() params.SetTimeout(10 * time.Second) params.Request = io.NopCloser(bytes.NewReader(tc.reqBytes)) var respBytes bytes.Buffer clientOption := func(op *runtime.ClientOperation) { op.ConsumesMediaTypes = []string{tc.reqMediaType} } _, err = c.Timestamp.GetTimestampResponse(params, &respBytes, clientOption) if err == nil { t.Fatalf("test '%s': expected error to occur while parsing request", tc.name) } if !strings.Contains(err.Error(), api.WeakHashAlgorithmTimestampRequest) { t.Fatalf("test '%s': error message should contain message about weak hash algorithm: %v", tc.name, err) } } } func TestInvalidJSONArtifactHashNotBase64Encoded(t *testing.T) { jsonReq := api.JSONRequest{ HashAlgorithm: "sha256", ArtifactHash: "not*base64*encoded", } marshalled, err := json.Marshal(jsonReq) if err != nil { t.Fatalf("failed to marshal request") } url := createServer(t) c, err := client.GetTimestampClient(url, client.WithContentType(client.JSONMediaType)) if err != nil { t.Fatalf("unexpected error creating client: %v", err) } params := timestamp.NewGetTimestampResponseParams() params.SetTimeout(10 * time.Second) params.Request = io.NopCloser(bytes.NewReader(marshalled)) var respBytes bytes.Buffer clientOption := func(op *runtime.ClientOperation) { op.ConsumesMediaTypes = []string{client.JSONMediaType} } _, err = c.Timestamp.GetTimestampResponse(params, &respBytes, clientOption) if err == nil { t.Fatalf("expected error to occur while parsing request") } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/tests/build_test_data.go000066400000000000000000000037161470602636300275470ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tests import ( "bytes" "crypto" "encoding/base64" "encoding/json" "math/big" "testing" "github.com/digitorus/timestamp" "github.com/sigstore/timestamp-authority/pkg/api" ) func createBase64EncodedArtifactHash(artifact []byte, hash crypto.Hash) (string, error) { h := hash.New() h.Write(artifact) artifactHash := h.Sum(nil) return base64.StdEncoding.EncodeToString(artifactHash), nil } func buildJSONReq(t *testing.T, artifact []byte, digestHash crypto.Hash, hashName string, includeCerts bool, nonce *big.Int, oidStr string) []byte { encodedHash, err := createBase64EncodedArtifactHash(artifact, digestHash) if err != nil { t.Fatalf("failed to marshal request") } jsonReq := api.JSONRequest{ Certificates: includeCerts, HashAlgorithm: hashName, ArtifactHash: encodedHash, Nonce: nonce, TSAPolicyOID: oidStr, } marshalled, err := json.Marshal(jsonReq) if err != nil { t.Fatalf("failed to marshal request") } return marshalled } func buildTimestampQueryReq(t *testing.T, artifact []byte, opts timestamp.RequestOptions) []byte { tsq, err := timestamp.CreateRequest(bytes.NewReader(artifact), ×tamp.RequestOptions{ Hash: opts.Hash, Certificates: opts.Certificates, Nonce: opts.Nonce, TSAPolicyOID: opts.TSAPolicyOID, }) if err != nil { t.Fatalf("unexpected error creating request: %v", err) } return tsq } golang-github-sigstore-timestamp-authority-1.2.3/pkg/tests/cli_test.go000066400000000000000000000340211470602636300262170ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tests import ( "bytes" "crypto" "encoding/asn1" "encoding/json" "errors" "io" "math/big" "os" "os/exec" "path/filepath" "strings" "testing" ts "github.com/digitorus/timestamp" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/timestamp-authority/pkg/client" "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp" ) const ( cli = "../../bin/timestamp-cli" ) func TestInspect(t *testing.T) { serverURL := createServer(t) tsrPath := getTimestamp(t, serverURL, "blob", big.NewInt(0), nil, true) // It should create timestamp successfully. out := runCli(t, "inspect", "--timestamp", tsrPath, "--format", "json") // test that output can be parsed as a timestamp resp := struct { TimestampResponse ts.Timestamp }{} err := json.Unmarshal([]byte(out), &resp) if err != nil { t.Errorf("failed to parse CLI response to a timestamp: %v", err) } } func TestTimestamp(t *testing.T) { restapiURL := createServer(t) tsrPath := filepath.Join(t.TempDir(), "response.tsr") artifactPath := makeArtifact(t, "blob") // It should create timestamp successfully. out := runCli(t, "--timestamp_server", restapiURL, "timestamp", "--artifact", artifactPath, "--hash", "sha256", "--out", tsrPath) outputContains(t, out, "Artifact timestamped at") if _, err := os.Stat(tsrPath); errors.Is(err, os.ErrNotExist) { t.Errorf("expected TSR file does not exist at path %s", tsrPath) } } func TestVerify_CertificateChainFlag(t *testing.T) { restapiURL := createServer(t) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) // this is the common name for the in-memory leaf certificate, copied // from pkg/signer/memory.go commonName := "Test TSA Timestamping" nonce := big.NewInt(456) policyOID := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} tsrContainsCerts := true tsrPath := getTimestamp(t, restapiURL, artifactContent, nonce, policyOID, tsrContainsCerts) // write the cert chain to a PEM file pemFiles := writeCertChainToPEMFiles(t, restapiURL) // It should verify timestamp successfully. out := runCli(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--certificate-chain", pemFiles.certChainPath, "--nonce", nonce.String(), "--oid", policyOID.String(), "--common-name", commonName) outputContains(t, out, "Successfully verified timestamp") } func TestVerify_RootAndIntermediateCertificateFlags(t *testing.T) { restapiURL := createServer(t) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) // this is the common name for the in-memory leaf certificate, copied // from pkg/signer/memory.go commonName := "Test TSA Timestamping" nonce := big.NewInt(456) policyOID := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} tsrContainsCerts := true tsrPath := getTimestamp(t, restapiURL, artifactContent, nonce, policyOID, tsrContainsCerts) // write the cert chain to a PEM file pemFiles := writeCertChainToPEMFiles(t, restapiURL) // It should verify timestamp successfully. out := runCli(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--root-certificates", pemFiles.rootCertsPath, "--intermediate-certificates", pemFiles.intermediateCertsPath, "--nonce", nonce.String(), "--oid", policyOID.String(), "--common-name", commonName) outputContains(t, out, "Successfully verified timestamp") } func TestVerify_AllCertFlagsIncluded(t *testing.T) { restapiURL := createServer(t) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) // this is the common name for the in-memory leaf certificate, copied // from pkg/signer/memory.go commonName := "Test TSA Timestamping" nonce := big.NewInt(456) policyOID := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} tsrContainsCerts := true tsrPath := getTimestamp(t, restapiURL, artifactContent, nonce, policyOID, tsrContainsCerts) // write the cert chain to a PEM file pemFiles := writeCertChainToPEMFiles(t, restapiURL) // It should fail to verify. out := runCliErr(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--certificate-chain", pemFiles.certChainPath, "--root-certificates", pemFiles.rootCertsPath, "--intermediate-certificates", pemFiles.intermediateCertsPath, "--nonce", nonce.String(), "--oid", policyOID.String(), "--common-name", commonName) outputContains(t, out, "the verify command must be called with either only the --certificate-chain flag or with the --root-certificates and --intermediate-certificates flags") } func TestVerify_NoCertFlagsIncluded(t *testing.T) { restapiURL := createServer(t) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) // this is the common name for the in-memory leaf certificate, copied // from pkg/signer/memory.go commonName := "Test TSA Timestamping" nonce := big.NewInt(456) policyOID := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} tsrContainsCerts := true tsrPath := getTimestamp(t, restapiURL, artifactContent, nonce, policyOID, tsrContainsCerts) // It should fail to verify. out := runCliErr(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--nonce", nonce.String(), "--oid", policyOID.String(), "--common-name", commonName) outputContains(t, out, "the verify command must be called with either only the --certificate-chain flag or with the --root-certificates and --intermediate-certificates flags") } func TestVerify_PassLeafCertificate(t *testing.T) { restapiURL := createServer(t) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) // this is the common name for the in-memory leaf certificate, copied // from pkg/signer/memory.go commonName := "Test TSA Timestamping" nonce := big.NewInt(456) policyOID := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} tsrContainsCerts := false tsrPath := getTimestamp(t, restapiURL, artifactContent, nonce, policyOID, tsrContainsCerts) // write the cert chain to a PEM file pemFiles := writeCertChainToPEMFiles(t, restapiURL) // It should verify timestamp successfully. out := runCli(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--certificate-chain", pemFiles.certChainPath, "--nonce", nonce.String(), "--oid", policyOID.String(), "--common-name", commonName, "--certificate", pemFiles.leafCertPath) outputContains(t, out, "Successfully verified timestamp") } func TestVerify_InvalidTSR(t *testing.T) { restapiURL := createServer(t) pemFiles := writeCertChainToPEMFiles(t, restapiURL) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) // Create invalid pem invalidTSR := filepath.Join(t.TempDir(), "response.tsr") if err := os.WriteFile(invalidTSR, []byte("invalid TSR"), 0600); err != nil { t.Fatal(err) } // It should return a message that the PEM is not valid out := runCliErr(t, "--timestamp_server", restapiURL, "verify", "--timestamp", invalidTSR, "--artifact", artifactPath, "--certificate-chain", pemFiles.certChainPath) outputContains(t, out, "error parsing response into Timestamp") } func TestVerify_InvalidPEM(t *testing.T) { restapiURL := createServer(t) artifactContent := "blob" artifactPath := makeArtifact(t, artifactContent) tsrPath := getTimestamp(t, restapiURL, artifactContent, big.NewInt(0), nil, true) // Create invalid pem invalidPEMPath := filepath.Join(t.TempDir(), "invalid_pem_path") if err := os.WriteFile(invalidPEMPath, []byte("invalid PEM"), 0600); err != nil { t.Fatal(err) } // It should return a message that the PEM is not valid out := runCliErr(t, "--timestamp_server", restapiURL, "verify", "--timestamp", tsrPath, "--artifact", artifactPath, "--certificate-chain", invalidPEMPath) outputContains(t, out, "failed to parse intermediate and root certs from PEM file") } func runCliErr(t *testing.T, arg ...string) string { t.Helper() // use a blank config file to ensure no collision if os.Getenv("TSATMPDIR") != "" { arg = append(arg, "--config="+os.Getenv("TSATMPDIR")+".timestamp-server.yaml") } cmd := exec.Command(cli, arg...) b, err := cmd.CombinedOutput() if err == nil { t.Log(string(b)) t.Fatalf("expected error, got %s", string(b)) } return string(b) } func runCli(t *testing.T, arg ...string) string { t.Helper() // use a blank config file to ensure no collision if os.Getenv("TSATMPDIR") != "" { arg = append(arg, "--config="+os.Getenv("TSATMPDIR")+".timestamp-server.yaml") } return run(t, "", cli, arg...) } func run(t *testing.T, stdin, cmd string, arg ...string) string { t.Helper() c := exec.Command(cmd, arg...) if stdin != "" { c.Stdin = strings.NewReader(stdin) } if os.Getenv("TSATMPDIR") != "" { // ensure that we use a clean state.json file for each run c.Env = append(c.Env, "HOME="+os.Getenv("TSATMPDIR")) } b, err := c.CombinedOutput() if err != nil { t.Log(string(b)) t.Fatal(err) } return string(b) } func outputContains(t *testing.T, output, sub string) { t.Helper() if !strings.Contains(output, sub) { t.Errorf("Expected [%s] in response, got %s", sub, output) } } func getTimestamp(t *testing.T, url string, artifactContent string, nonce *big.Int, policyOID asn1.ObjectIdentifier, tsrContainsCerts bool) string { c, err := client.GetTimestampClient(url, client.WithUserAgent("test user agent"), client.WithContentType(client.TimestampQueryMediaType)) if err != nil { t.Fatalf("unexpected error creating client: %v", err) } tsNonce := big.NewInt(1234) if nonce != nil { tsNonce = nonce } tsPolicyOID := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2} if policyOID != nil { tsPolicyOID = policyOID } tsq, err := ts.CreateRequest(strings.NewReader(artifactContent), &ts.RequestOptions{ Hash: crypto.SHA256, Certificates: tsrContainsCerts, Nonce: tsNonce, TSAPolicyOID: tsPolicyOID, }) if err != nil { t.Fatalf("unexpected error creating request: %v", err) } params := timestamp.NewGetTimestampResponseParams() params.Request = io.NopCloser(bytes.NewReader(tsq)) var respBytes bytes.Buffer _, err = c.Timestamp.GetTimestampResponse(params, &respBytes) if err != nil { t.Fatalf("unexpected error getting timestamp chain: %v", err) } path := filepath.Join(t.TempDir(), "response.tsr") if err := os.WriteFile(path, respBytes.Bytes(), 0600); err != nil { t.Fatalf("unexpected error while writing timestamp to file: %v", err) } return path } type certChainPEMFiles struct { leafCertPath string intermediateCertsPath string rootCertsPath string certChainPath string } // getCertChainPEM returns the path of a pem file containing // the leaf certificate and the path of a pem file containing the // root and intermediate certificates. Used to verify a signed timestamp func writeCertChainToPEMFiles(t *testing.T, restapiURL string) certChainPEMFiles { c, err := client.GetTimestampClient(restapiURL) if err != nil { t.Fatalf("unexpected error creating client: %v", err) } chain, err := c.Timestamp.GetTimestampCertChain(nil) if err != nil { t.Fatalf("unexpected error getting timestamp chain: %v", err) } // create PEM file containing intermediate and root certificates certChainPath := filepath.Join(t.TempDir(), "ts_certchain.pem") file, err := os.Create(certChainPath) if err != nil { t.Fatal(err) } defer file.Close() // Remove the non-CA certificate from the chain certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(chain.Payload)) if err != nil { t.Fatalf("unexpected error unmarshalling cert chain: %v", err) } caCertsPEM, err := cryptoutils.MarshalCertificatesToPEM(certs[1:]) if err != nil { t.Fatalf("unexpected error marshalling cert chain: %v", err) } reader := bytes.NewReader(caCertsPEM) file.ReadFrom(reader) // create intermediates certificate PEM file intermediateCertsPath := filepath.Join(t.TempDir(), "ts_intermediates.pem") file, err = os.Create(intermediateCertsPath) if err != nil { t.Fatal(err) } defer file.Close() lastCertIndex := len(certs) - 1 intermediatesPEM, err := cryptoutils.MarshalCertificatesToPEM(certs[1:lastCertIndex]) if err != nil { t.Fatalf("unexpected error marshalling intermediate certificates: %v", err) } reader = bytes.NewReader(intermediatesPEM) file.ReadFrom(reader) // create roots certificate PEM file rootCertsPath := filepath.Join(t.TempDir(), "ts_roots.pem") file, err = os.Create(rootCertsPath) if err != nil { t.Fatal(err) } defer file.Close() rootsPEM, err := cryptoutils.MarshalCertificatesToPEM(certs[lastCertIndex:]) if err != nil { t.Fatalf("unexpected error marshalling root certificates: %v", err) } reader = bytes.NewReader(rootsPEM) file.ReadFrom(reader) // create PEM file containing the leaf certificate leafCertPath := filepath.Join(t.TempDir(), "ts_leafcert.pem") file, err = os.Create(leafCertPath) if err != nil { t.Fatal(err) } defer file.Close() leafCertPEM, err := cryptoutils.MarshalCertificatesToPEM(certs[0:1]) if err != nil { t.Fatalf("unexpected error marshalling leaf cert: %v", err) } reader = bytes.NewReader(leafCertPEM) file.ReadFrom(reader) return certChainPEMFiles{ leafCertPath: leafCertPath, intermediateCertsPath: intermediateCertsPath, rootCertsPath: rootCertsPath, certChainPath: certChainPath, } } // Create a random artifact to sign func makeArtifact(t *testing.T, content string) string { artifactPath := filepath.Join(t.TempDir(), "artifact") if err := os.WriteFile(artifactPath, []byte(content), 0600); err != nil { t.Fatal(err) } return artifactPath } golang-github-sigstore-timestamp-authority-1.2.3/pkg/tests/server.go000066400000000000000000000025111470602636300257160ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package tests import ( "net/http" "net/http/httptest" "testing" "time" "github.com/spf13/viper" "github.com/sigstore/timestamp-authority/pkg/server" ) func createServer(t *testing.T) string { viper.Set("timestamp-signer", "memory") viper.Set("timestamp-signer-hash", "sha256") // unused port apiServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second) server := httptest.NewServer(apiServer.GetHandler()) t.Cleanup(server.Close) // verify the server's health response, err := http.Get(server.URL + "/ping") if err != nil || response.StatusCode != 200 { t.Fatalf("unexpected error starting up server - status code: %d, err: %v", response.StatusCode, err) } return server.URL } golang-github-sigstore-timestamp-authority-1.2.3/pkg/verification/000077500000000000000000000000001470602636300254025ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/verification/verify.go000066400000000000000000000222531470602636300272410ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package verification import ( "bytes" "crypto/x509" "encoding/asn1" "fmt" "hash" "io" "math/big" "github.com/digitorus/pkcs7" "github.com/digitorus/timestamp" "github.com/pkg/errors" ) var ( // EKUOID is the Extended Key Usage OID, per RFC 5280 EKUOID = asn1.ObjectIdentifier{2, 5, 29, 37} ) // VerifyOpts contains verification options for a RFC3161 timestamp type VerifyOpts struct { // OID verifies that the TSR's OID has an expected value. Optional, used when // an alternative OID was passed with a request to the TSA OID asn1.ObjectIdentifier // TSACertificate verifies that the TSR uses the TSACertificate as expected. Optional if the TSR contains the TSA certificate TSACertificate *x509.Certificate // Intermediates verifies the TSR's certificate. Optional, used for chain building Intermediates []*x509.Certificate // Roots is the set of trusted root certificates that verifies the TSR's certificate Roots []*x509.Certificate // Nonce verifies that the TSR contains the expected nonce. Optional, used when // an optional nonce was passed with a request to the TSA Nonce *big.Int // CommonName verifies that the TSR certificate subject's Common Name matches the expected value. Optional CommonName string } // Verify the TSR's certificate identifier matches a provided TSA certificate func verifyESSCertID(tsaCert *x509.Certificate, opts VerifyOpts) error { if opts.TSACertificate == nil { return nil } if !bytes.Equal(opts.TSACertificate.RawIssuer, tsaCert.RawIssuer) { return fmt.Errorf("TSR cert issuer does not match provided TSA cert issuer") } if opts.TSACertificate.SerialNumber.Cmp(tsaCert.SerialNumber) != 0 { return fmt.Errorf("TSR cert serial number does not match provided TSA cert serial number") } return nil } // Verify the leaf certificate's subject Common Name matches a provided Common Name func verifySubjectCommonName(cert *x509.Certificate, opts VerifyOpts) error { if opts.CommonName == "" { return nil } if cert.Subject.CommonName != opts.CommonName { return fmt.Errorf("the certificate's subject Common Name %s does not match the provided Common Name %s", cert.Subject.CommonName, opts.CommonName) } return nil } // If embedded in the TSR, verify the TSR's leaf certificate matches a provided TSA certificate func verifyEmbeddedLeafCert(tsaCert *x509.Certificate, opts VerifyOpts) error { if opts.TSACertificate != nil && !opts.TSACertificate.Equal(tsaCert) { return fmt.Errorf("certificate embedded in the TSR does not match the provided TSA certificate") } return nil } // Verify the leaf's EKU is set to critical, per RFC 3161 2.3 func verifyLeafCertCriticalEKU(cert *x509.Certificate) error { var criticalEKU bool for _, ext := range cert.Extensions { if ext.Id.Equal(EKUOID) { criticalEKU = ext.Critical break } } if !criticalEKU { return errors.New("certificate must set EKU to critical") } return nil } func verifyLeafCert(ts timestamp.Timestamp, opts VerifyOpts) error { if len(ts.Certificates) == 0 && opts.TSACertificate == nil { return fmt.Errorf("leaf certificate must be present the in TSR or as a verify option") } errMsg := "failed to verify TSA certificate" var leafCert *x509.Certificate if len(ts.Certificates) != 0 { leafCert = ts.Certificates[0] err := verifyEmbeddedLeafCert(leafCert, opts) if err != nil { return fmt.Errorf("%s: %w", errMsg, err) } } else { leafCert = opts.TSACertificate } err := verifyLeafCertCriticalEKU(leafCert) if err != nil { return fmt.Errorf("%s: %w", errMsg, err) } err = verifyESSCertID(leafCert, opts) if err != nil { return fmt.Errorf("%s: %w", errMsg, err) } err = verifySubjectCommonName(leafCert, opts) if err != nil { return fmt.Errorf("%s: %w", errMsg, err) } // verifies that the leaf certificate and any intermediate certificates // have EKU set to only time stamping usage err = verifyLeafAndIntermediatesTimestampingEKU(leafCert, opts) if err != nil { return fmt.Errorf("failed to verify EKU on leaf certificate: %w", err) } return nil } func verifyExtendedKeyUsage(cert *x509.Certificate) error { certEKULen := len(cert.ExtKeyUsage) if certEKULen != 1 { return fmt.Errorf("certificate has %d extended key usages, expected only one", certEKULen) } if cert.ExtKeyUsage[0] != x509.ExtKeyUsageTimeStamping { return fmt.Errorf("leaf certificate EKU is not set to TimeStamping as required") } return nil } // Verify the leaf and intermediate certificates (called "EKU chaining") all // have the extended key usage set to only time stamping usage func verifyLeafAndIntermediatesTimestampingEKU(leafCert *x509.Certificate, opts VerifyOpts) error { err := verifyExtendedKeyUsage(leafCert) if err != nil { return fmt.Errorf("failed to verify EKU on leaf certificate: %w", err) } for _, cert := range opts.Intermediates { err := verifyExtendedKeyUsage(cert) if err != nil { return fmt.Errorf("failed to verify EKU on intermediate certificate: %w", err) } } return nil } // Verify the OID of the TSR matches an expected OID func verifyOID(oid []int, opts VerifyOpts) error { if opts.OID == nil { return nil } responseOID := opts.OID if len(oid) != len(responseOID) { return fmt.Errorf("OID lengths do not match") } for i, v := range oid { if v != responseOID[i] { return fmt.Errorf("OID content does not match") } } return nil } // Verify the nonce - Mostly important for when the response is first returned func verifyNonce(requestNonce *big.Int, opts VerifyOpts) error { if opts.Nonce == nil { return nil } if opts.Nonce.Cmp(requestNonce) != 0 { return fmt.Errorf("incoming nonce %d does not match TSR nonce %d", requestNonce, opts.Nonce) } return nil } // VerifyTimestampResponse the timestamp response using a timestamp certificate chain. func VerifyTimestampResponse(tsrBytes []byte, artifact io.Reader, opts VerifyOpts) (*timestamp.Timestamp, error) { // Verify the status of the TSR does not contain an error // handled by the timestamp.ParseResponse function ts, err := timestamp.ParseResponse(tsrBytes) if err != nil { pe := timestamp.ParseError("") if errors.As(err, &pe) { return nil, fmt.Errorf("timestamp response is not valid: %w", err) } return nil, fmt.Errorf("error parsing response into Timestamp: %w", err) } // verify the timestamp response signature using the provided certificate pool if err = verifyTSRWithChain(ts, opts); err != nil { return nil, err } if err = verifyNonce(ts.Nonce, opts); err != nil { return nil, err } if err = verifyOID(ts.Policy, opts); err != nil { return nil, err } if err = verifyLeafCert(*ts, opts); err != nil { return nil, err } // verify the hash in the timestamp response matches the artifact hash if err = verifyHashedMessages(ts.HashAlgorithm.New(), ts.HashedMessage, artifact); err != nil { return nil, err } // if the parsed timestamp is verified, return the timestamp return ts, nil } func verifyTSRWithChain(ts *timestamp.Timestamp, opts VerifyOpts) error { p7Message, err := pkcs7.Parse(ts.RawToken) if err != nil { return fmt.Errorf("error parsing hashed message: %w", err) } if len(opts.Roots) == 0 { return fmt.Errorf("no root certificates provided for verifying the certificate chain") } rootCertPool := x509.NewCertPool() for _, cert := range opts.Roots { rootCertPool.AddCert(cert) } intermediateCertPool := x509.NewCertPool() for _, cert := range opts.Intermediates { intermediateCertPool.AddCert(cert) } x509Opts := x509.VerifyOptions{ Roots: rootCertPool, Intermediates: intermediateCertPool, } // if the PCKS7 object does not have any certificates set in the // Certificates field, the VerifyWithChain method will because it will be // unable to find a leaf certificate associated with a signer. Since the // leaf certificate issuer and serial number information is already part of // the PKCS7 object, adding the leaf certificate to the Certificates field // will allow verification to pass if p7Message.Certificates == nil && opts.TSACertificate != nil { p7Message.Certificates = []*x509.Certificate{opts.TSACertificate} } err = p7Message.VerifyWithOpts(x509Opts) if err != nil { return fmt.Errorf("error while verifying with chain: %w", err) } return nil } // Verify that the TSR's hashed message matches the digest of the artifact to be timestamped func verifyHashedMessages(hashAlg hash.Hash, hashedMessage []byte, artifactReader io.Reader) error { h := hashAlg if _, err := io.Copy(h, artifactReader); err != nil { return fmt.Errorf("failed to create hash %w", err) } localHashedMsg := h.Sum(nil) if !bytes.Equal(localHashedMsg, hashedMessage) { return fmt.Errorf("hashed messages don't match") } return nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/verification/verify_request.go000066400000000000000000000017641470602636300310150ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package verification import ( "crypto" "github.com/digitorus/timestamp" "github.com/pkg/errors" ) var ErrWeakHashAlg = errors.New("weak hash algorithm: must be SHA-256, SHA-384, or SHA-512") 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 { return ErrWeakHashAlg } return nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/verification/verify_request_test.go000066400000000000000000000022001470602636300320360ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package verification import ( "crypto" "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) } } tsReq.HashAlgorithm = crypto.SHA1 if err := VerifyRequest(tsReq); err != ErrWeakHashAlg { t.Fatalf("expected error with weak hash algorithm, got %v", err) } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/verification/verify_test.go000066400000000000000000000441751470602636300303070ustar00rootroot00000000000000// // Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package verification import ( "bytes" "crypto" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/json" "fmt" "io" "math/big" "strings" "testing" "time" "github.com/digitorus/timestamp" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/timestamp-authority/pkg/client/mock" tsatimestamp "github.com/sigstore/timestamp-authority/pkg/generated/client/timestamp" "github.com/sigstore/timestamp-authority/pkg/signer" ) func TestVerifyArtifactHashedMessages(t *testing.T) { c, err := mock.NewTSAClient(mock.TSAClientOptions{Time: time.Now()}) if err != nil { t.Fatalf("unexpected error creating client: %v", err) } type test struct { message string forceError bool expectedErrorMessage string } tests := []test{ { message: "valid local artifact", }, { message: "nonexistant local artifact", }, { message: "valid local artifact with hash algorithm", }, { message: "valid oid", }, { message: "MIIEbjADAgEAMIIEZQYJKoZIhvcNAQcCoIIEVjCCBFICAQExDTALBglghkgBZQMEAgEwgdQGCyqGSIb3DQEJEAEEoIHEBIHBMIG+AgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgN94hMnpq0onyUi7r1zJHNiLT1/spX8MU2GBN9AdMe6wCFQDS6RL1iVlmlkwJzmpS2EH0cuX8sxgTMjAyMjExMDMxNzQyNDIrMDEwMDADAgEBAhRKnQszZjzcgJkpE8LCbmbF0s1jPaA0pDIwMDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIFRpbWVzdGFtcGluZ6CCAckwggHFMIIBaqADAgECAhRHCu9dHKS97mFo1cH5neJubRibujAKBggqhkjOPQQDAjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQGA1UEAxMNVGVzdCBUU0EgUm9vdDAeFw0yMjExMDMxMTUzMThaFw0zMTExMDMxMTU2MThaMDAxDjAMBgNVBAoTBWxvY2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATo3W6NQrpx5D8z5IvgD2DlAgoJMF4KPY9Pj4UfFhfOq029ryszXp3460Z7N+x86bDvyjVrHaeiPnl1HO9Q52zso2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFHSIhDdTGIsodML/iUOhx7hgo/K7MB8GA1UdIwQYMBaAFBoZYijuouZCvKDtBd0eCyaU2HWoMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMCA0kAMEYCIQCmPVr5kwYe4Jg9PGO6apgfzSrKAtESgNHpAbE3iIvJhQIhAJIGNxshJcC8LXHRrVWM77no3d3GguSvR01OAPZwE2pqMYIBmDCCAZQCAQEwQDAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQGA1UEAxMNVGVzdCBUU0EgUm9vdAIURwrvXRykve5haNXB+Z3ibm0Ym7owCwYJYIZIAWUDBAIBoIHqMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjIxMTAzMTY0MjQyWjAvBgkqhkiG9w0BCQQxIgQgrKbkOizzGoAudPhAnW5Qny788Kcd++VQwPrCMhg4MTEwfQYLKoZIhvcNAQkQAi8xbjBsMGowaAQgXqxJD0nAgg6en9P1bRrU7+6tzxOMn3YThreg7uR6T7EwRDAspCowKDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QCFEcK710cpL3uYWjVwfmd4m5tGJu6MAoGCCqGSM49BAMCBEcwRQIgQkc2BxMjnUMzqBDYzUiw10LoCIZ9Zmp1E0Hl6E+9mzwCIQDp2lD826Du5Ss4pNG/TksDknTUJfKvrLc2ex+x+W3VHg==", }, { expectedErrorMessage: "hashed messages don't match", forceError: true, }, } for _, tc := range tests { tsq, err := timestamp.CreateRequest(strings.NewReader(tc.message), ×tamp.RequestOptions{ Hash: crypto.SHA256, Certificates: true, }) if err != nil { t.Fatalf("unexpected error creating request: %v", err) } chain, err := c.Timestamp.GetTimestampCertChain(nil) if err != nil { t.Fatalf("unexpected error getting timestamp chain: %v", err) } params := tsatimestamp.NewGetTimestampResponseParams() params.SetTimeout(5 * time.Second) params.Request = io.NopCloser(bytes.NewReader(tsq)) var respBytes bytes.Buffer _, err = c.Timestamp.GetTimestampResponse(params, &respBytes) if err != nil { t.Fatalf("unexpected error getting timestamp response: %v", err) } certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(chain.Payload)) if err != nil { t.Fatal("unexpected error while parsing test certificates from PEM file") } if len(certs) != 3 { t.Fatalf("expected three certificates (one leaf, one intermediate, and one root), received %d", len(certs)) } opts := VerifyOpts{ Intermediates: certs[1:2], Roots: certs[2:], } ts, err := VerifyTimestampResponse(respBytes.Bytes(), strings.NewReader(tc.message), opts) if err != nil { t.Errorf("VerifyTimestampResponse failed to verify the timestamp: %v", err) } if ts == nil { t.Error("VerifyTimestampResponse did not return the parsed timestamp as expected") } if tc.forceError { // Force hashed message error mismatch msg := tc.message + "XXX" ts, err := VerifyTimestampResponse(respBytes.Bytes(), strings.NewReader(msg), opts) if err == nil { t.Error("expected error message when verifying the timestamp response") } if err != nil && err.Error() != tc.expectedErrorMessage { t.Errorf("expected error message when verifying the timestamp response: %s got %s", tc.expectedErrorMessage, err.Error()) } if ts != nil { t.Errorf("expected VerifyTimestampResponse to return a nil Timestamp object") } } } } func TestVerifyNonce(t *testing.T) { type test struct { nonceStr string expectVerifySuccess bool } tests := []test{ { nonceStr: "312432523523431424141", expectVerifySuccess: true, }, { nonceStr: "9874325235234314241230", expectVerifySuccess: false, }, } for _, tc := range tests { optsBigIntStr := "312432523523431424141" optsNonce, ok := new(big.Int).SetString(optsBigIntStr, 10) if !ok { t.Fatalf("unexpected failure to create big int from string: %s", optsBigIntStr) } opts := VerifyOpts{ Nonce: optsNonce, } providedNonce, ok := new(big.Int).SetString(tc.nonceStr, 10) if !ok { t.Fatalf("unexpected failure to create big int from string: %s", tc.nonceStr) } err := verifyNonce(providedNonce, opts) if tc.expectVerifySuccess && err != nil { t.Errorf("expected verification to fail \n provided nonce %s should not match opts nonce %s", tc.nonceStr, optsBigIntStr) } if !tc.expectVerifySuccess && err == nil { t.Errorf("expected verification to pass \n provided nonce %s should match opts nonce %s", tc.nonceStr, optsBigIntStr) } } } func TestVerifyLeafCert(t *testing.T) { type test struct { useOptsCert bool useTSCert bool expectVerifySuccess bool } tests := []test{ { useOptsCert: false, useTSCert: false, expectVerifySuccess: false, }, { useOptsCert: true, useTSCert: false, expectVerifySuccess: true, }, { useOptsCert: false, useTSCert: true, expectVerifySuccess: true, }, { useOptsCert: true, useTSCert: true, expectVerifySuccess: true, }, } for _, tc := range tests { criticalExtension := pkix.Extension{ Id: EKUOID, Critical: true, } sampleCert := &x509.Certificate{ Raw: []byte("abc123"), RawIssuer: []byte("abc123"), SerialNumber: big.NewInt(int64(123)), Extensions: []pkix.Extension{criticalExtension}, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping}, Subject: pkix.Name{ CommonName: "TSA-Service", }, } opts := VerifyOpts{} ts := timestamp.Timestamp{} if tc.useOptsCert { opts.TSACertificate = sampleCert opts.CommonName = sampleCert.Subject.CommonName } if tc.useTSCert { 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 && !tc.expectVerifySuccess { t.Fatal("expected error not to be nil") } } } func TestVerifyEmbeddedLeafCert(t *testing.T) { type test struct { optsCert *x509.Certificate providedCert *x509.Certificate expectVerifySuccess bool } tests := []test{ { optsCert: nil, providedCert: &x509.Certificate{ Raw: []byte("abc123"), }, expectVerifySuccess: true, }, { optsCert: &x509.Certificate{ Raw: []byte("abc123"), }, providedCert: &x509.Certificate{ Raw: []byte("abc123"), }, expectVerifySuccess: true, }, { optsCert: &x509.Certificate{ Raw: []byte("abc123"), }, providedCert: &x509.Certificate{ Raw: []byte("def456"), }, expectVerifySuccess: false, }, } for _, tc := range tests { opts := VerifyOpts{ TSACertificate: tc.optsCert, } err := verifyEmbeddedLeafCert(tc.providedCert, opts) if err == nil && !tc.expectVerifySuccess { t.Errorf("expected verification to fail: provided cert unexpectedly matches opts cert") } if err != nil && tc.expectVerifySuccess { t.Errorf("expected verification to pass: provided cert does not match opts cert") } } } func TestVerifySubjectCommonName(t *testing.T) { type test struct { optsCommonName string providedCommonName string expectVerifySuccess bool } tests := []test{ { optsCommonName: "Sigstore TSA", providedCommonName: "Sigstore TSA", expectVerifySuccess: true, }, { optsCommonName: "Sigstore TSA", providedCommonName: "SomeOtherStore", expectVerifySuccess: false, }, } for _, tc := range tests { opts := VerifyOpts{ CommonName: tc.optsCommonName, } cert := x509.Certificate{ Subject: pkix.Name{ CommonName: tc.providedCommonName, Organization: []string{"Sigstore"}, }, } err := verifySubjectCommonName(&cert, opts) if err != nil && tc.expectVerifySuccess { t.Errorf("expected verification to pass \n provided common name %s should match opts common name %s", tc.providedCommonName, tc.optsCommonName) } if err == nil && !tc.expectVerifySuccess { t.Errorf("expected verification to fail \n provided common name %s should not match opts common name %s", tc.providedCommonName, tc.optsCommonName) } } } func TestVerifyESSCertID(t *testing.T) { type test struct { optsIssuer pkix.Name optsSerialNumber string providedIssuer pkix.Name providedSerialNumber string expectVerifySuccess bool } tests := []test{ { optsIssuer: pkix.Name{ CommonName: "Sigstore CA", Organization: []string{"Sigstore"}, }, optsSerialNumber: "312432523523431424141", providedIssuer: pkix.Name{ CommonName: "Sigstore CA", Organization: []string{"Sigstore"}, }, providedSerialNumber: "312432523523431424141", expectVerifySuccess: true, }, { optsIssuer: pkix.Name{ CommonName: "Sigstore CA", Organization: []string{"Sigstore"}, }, optsSerialNumber: "312432523523431424141", providedIssuer: pkix.Name{ CommonName: "Sigstore CA", Organization: []string{"Sigstore"}, }, providedSerialNumber: "4567523523431424141", expectVerifySuccess: false, }, { optsIssuer: pkix.Name{ CommonName: "Sigstore CA", Organization: []string{"Sigstore"}, }, optsSerialNumber: "312432523523431424141", providedIssuer: pkix.Name{ CommonName: "Another CA", Organization: []string{"Sigstore"}, }, providedSerialNumber: "312432523523431424141", expectVerifySuccess: false, }, } for _, tc := range tests { optsSerialNumber, ok := new(big.Int).SetString(tc.optsSerialNumber, 10) if !ok { t.Fatalf("unexpected failure to create big int from string: %s", tc.optsSerialNumber) } optsRawIssuer, err := json.Marshal(tc.optsIssuer) if err != nil { t.Fatalf("unexpected failure while marshalling issuer object") } opts := VerifyOpts{ TSACertificate: &x509.Certificate{ Issuer: tc.optsIssuer, RawIssuer: optsRawIssuer, SerialNumber: optsSerialNumber, }, } providedSerialNumber, ok := new(big.Int).SetString(tc.providedSerialNumber, 10) if !ok { t.Fatalf("unexpected failure to create big int from string: %s", tc.providedSerialNumber) } providedRawIssuer, err := json.Marshal(tc.providedIssuer) if err != nil { t.Fatalf("unexpected failure while marshalling issuer object") } cert := x509.Certificate{ Issuer: tc.providedIssuer, RawIssuer: providedRawIssuer, SerialNumber: providedSerialNumber, } err = verifyESSCertID(&cert, opts) if err != nil && tc.expectVerifySuccess { t.Errorf("expected verifcation to pass: %s", err.Error()) } if err == nil && !tc.expectVerifySuccess { t.Errorf("expected verifcation to fail") } } } func TestVerifyExtendedKeyUsage(t *testing.T) { type test struct { eku []x509.ExtKeyUsage expectVerifySuccess bool } tests := []test{ { eku: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping}, expectVerifySuccess: true, }, { eku: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping, x509.ExtKeyUsageIPSECTunnel}, expectVerifySuccess: false, }, { eku: []x509.ExtKeyUsage{x509.ExtKeyUsageIPSECTunnel}, expectVerifySuccess: false, }, } for _, tc := range tests { cert := x509.Certificate{ ExtKeyUsage: tc.eku, } err := verifyExtendedKeyUsage(&cert) if err != nil && tc.expectVerifySuccess { t.Errorf("expected verifyExtendedKeyUsage to return nil error") } if err == nil && !tc.expectVerifySuccess { t.Errorf("expected verification to fail") } } } func createCertChainAndSigner() ([]*x509.Certificate, *signature.ECDSASignerVerifier, error) { sv, _, err := signature.NewECDSASignerVerifier(elliptic.P256(), rand.Reader, crypto.SHA256) if err != nil { return nil, nil, fmt.Errorf("expected NewECDSASignerVerifier to return a signer verifier: %v", err) } certChain, err := signer.NewTimestampingCertWithChain(sv) if err != nil { return nil, nil, fmt.Errorf("expected NewTimestampingCertWithChain to return a certificate chain: %v", err) } if len(certChain) != 3 { return nil, nil, fmt.Errorf("expected the certificate chain to have three certificates: %v", err) } return certChain, sv, nil } func createSignedTimestamp(certChain []*x509.Certificate, sv *signature.ECDSASignerVerifier, tsHasCerts bool) (*timestamp.Timestamp, error) { tsq, err := timestamp.CreateRequest(strings.NewReader("TestRequest"), ×tamp.RequestOptions{ Hash: crypto.SHA256, Certificates: tsHasCerts, }) if err != nil { return nil, fmt.Errorf("unexpectedly failed to create timestamp request: %v", err) } req, err := timestamp.ParseRequest([]byte(tsq)) if err != nil { return nil, fmt.Errorf("unexpectedly failed to parse timestamp request: %v", err) } tsTemplate := timestamp.Timestamp{ HashAlgorithm: req.HashAlgorithm, HashedMessage: req.HashedMessage, Time: time.Now(), Policy: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 2}, Ordering: false, Qualified: false, AddTSACertificate: req.Certificates, ExtraExtensions: req.Extensions, } resp, err := tsTemplate.CreateResponseWithOpts(certChain[0], sv, crypto.SHA256) if err != nil { return nil, fmt.Errorf("unexpectedly failed to create timestamp response: %v", err) } ts, err := timestamp.ParseResponse(resp) if err != nil { return nil, fmt.Errorf("unexpectedly failed to parse timestamp response: %v", err) } return ts, nil } func TestVerifyTSRWithChain(t *testing.T) { certChain, sv, err := createCertChainAndSigner() if err != nil { t.Errorf("failed to create certificate chain: %v", err) } tsWithCerts, err := createSignedTimestamp(certChain, sv, true) if err != nil { t.Errorf("failed to create signed certificate: %v", err) } tsWithoutCerts, err := createSignedTimestamp(certChain, sv, false) if err != nil { t.Errorf("failed to create signed certificate: %v", err) } // get certificates leaf := certChain[0] intermediate := certChain[1] root := certChain[2] // invalidate the intermediate certificate var invalidIntermediate = *certChain[1] invalidIntermediate.RawIssuer = nil invalidIntermediate.Issuer = pkix.Name{} type test struct { name string ts *timestamp.Timestamp opts VerifyOpts expectVerifySuccess bool } tests := []test{ { name: "Verification is successful with included leaf certificate in timestamp", ts: tsWithCerts, opts: VerifyOpts{ Roots: []*x509.Certificate{root}, Intermediates: []*x509.Certificate{intermediate}, }, expectVerifySuccess: true, }, { name: "Verification fails due to invalid intermediate certificate", ts: tsWithCerts, opts: VerifyOpts{ Roots: []*x509.Certificate{root}, Intermediates: []*x509.Certificate{&invalidIntermediate}, }, expectVerifySuccess: false, }, { name: "Verification fails due to missing intermediate certificate", ts: tsWithCerts, opts: VerifyOpts{ Roots: []*x509.Certificate{root}, }, expectVerifySuccess: false, }, { name: "Verification fails due to missing root certificate", ts: tsWithCerts, opts: VerifyOpts{ Intermediates: []*x509.Certificate{intermediate}, }, expectVerifySuccess: false, }, { name: "Verification fails due to missing root and intermediate certificates", ts: tsWithCerts, opts: VerifyOpts{}, expectVerifySuccess: false, }, { name: "Verification fails due to missing leaf certificate", ts: tsWithoutCerts, opts: VerifyOpts{ Roots: []*x509.Certificate{root}, Intermediates: []*x509.Certificate{intermediate}, }, expectVerifySuccess: false, }, { name: "Verification is successful with out of band leaf certificate", ts: tsWithoutCerts, opts: VerifyOpts{ Roots: []*x509.Certificate{root}, Intermediates: []*x509.Certificate{intermediate}, TSACertificate: leaf, }, expectVerifySuccess: true, }, } for _, tc := range tests { err = verifyTSRWithChain(tc.ts, tc.opts) if tc.expectVerifySuccess && err != nil { t.Errorf("test '%s' unexpectedly failed \nExpected verifyTSRWithChain to successfully verify certificate chain, err: %v", tc.name, err) } else if !tc.expectVerifySuccess && err == nil { t.Errorf("testg '%s' unexpectedly passed \nExpected verifyTSRWithChain to fail verification", tc.name) } } } golang-github-sigstore-timestamp-authority-1.2.3/pkg/x509/000077500000000000000000000000001470602636300234255ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/x509/testutils/000077500000000000000000000000001470602636300254655ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/pkg/x509/testutils/cert_test_utils.go000066400000000000000000000103531470602636300312320ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testutils import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "math/big" "time" ) /* To use: rootCert, rootKey, _ := GenerateRootCa() subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) leafCert, _, _ := GenerateLeafCert(subCert, subKey) roots := x509.NewCertPool() subs := x509.NewCertPool() roots.AddCert(rootCert) subs.AddCert(subCert) opts := x509.VerifyOptions{ Roots: roots, Intermediates: subs, KeyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageTimeStamping, }, } _, err := leafCert.Verify(opts) */ func createCertificate(template *x509.Certificate, parent *x509.Certificate, pub interface{}, priv crypto.Signer) (*x509.Certificate, error) { certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv) if err != nil { return nil, err } cert, err := x509.ParseCertificate(certBytes) if err != nil { return nil, err } return cert, nil } func GenerateRootCa() (*x509.Certificate, *ecdsa.PrivateKey, error) { rootTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "Test TSA Timestamping Root", Organization: []string{"local"}, }, NotBefore: time.Now().Add(-10 * time.Minute), NotAfter: time.Now().Add(5 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(rootTemplate, rootTemplate, &priv.PublicKey, priv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateSubordinateCa(rootTemplate *x509.Certificate, rootPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { subTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "Test TSA Timestamping Intermediate", Organization: []string{"local"}, }, NotBefore: time.Now().Add(-9 * time.Minute), NotAfter: time.Now().Add(2 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping}, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(subTemplate, rootTemplate, &priv.PublicKey, rootPriv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateLeafCert(parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { timestampExt, err := asn1.Marshal([]asn1.ObjectIdentifier{{1, 3, 6, 1, 5, 5, 7, 3, 8}}) if err != nil { return nil, nil, err } certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "Test TSA Timestamping Leaf", Organization: []string{"local"}, }, NotBefore: time.Now().Add(-1 * time.Minute), NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, IsCA: false, // set EKU to x509.ExtKeyUsageTimeStamping but with a critical bit ExtraExtensions: []pkix.Extension{ { Id: asn1.ObjectIdentifier{2, 5, 29, 37}, Critical: true, Value: timestampExt, }, }, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(certTemplate, parentTemplate, &priv.PublicKey, parentPriv) if err != nil { return nil, nil, err } return cert, priv, nil } golang-github-sigstore-timestamp-authority-1.2.3/pkg/x509/x509.go000066400000000000000000000065271470602636300244730ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package x509 import ( "crypto" "crypto/x509" "encoding/asn1" "errors" "github.com/sigstore/sigstore/pkg/cryptoutils" ) var ( // EKUOID is the Extended Key Usage OID, per RFC 5280 EKUOID = asn1.ObjectIdentifier{2, 5, 29, 37} EKUTimestampingOID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} ) // VerifyCertChain verifies that the certificate chain is valid for issuing // timestamping certificates. The chain should start with a leaf certificate, // followed by any number of intermediates, and end with the root certificate. func VerifyCertChain(certs []*x509.Certificate, signer crypto.Signer) error { // Chain must contain at least one CA certificate and a leaf certificate if len(certs) < 2 { return errors.New("certificate chain must contain at least two certificates") } roots := x509.NewCertPool() roots.AddCert(certs[len(certs)-1]) intermediates := x509.NewCertPool() if len(certs) > 2 { for _, intermediate := range certs[1 : len(certs)-1] { intermediates.AddCert(intermediate) } } // Verify the certificate chain opts := x509.VerifyOptions{ Roots: roots, Intermediates: intermediates, KeyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageTimeStamping, }, } if _, err := certs[0].Verify(opts); err != nil { return err } // Verify that all certificates but the leaf are CA certificates for _, c := range certs[1:] { if !c.IsCA { return errors.New("certificate is not a CA certificate") } } // Verify leaf has only a single EKU for timestamping, per RFC 3161 2.3 // This should be enforced by Verify already leafEKU := certs[0].ExtKeyUsage if len(leafEKU) != 1 { return errors.New("certificate should only contain one EKU") } // Verify leaf's EKU is set to critical, per RFC 3161 2.3 var criticalEKU bool for _, ext := range certs[0].Extensions { if ext.Id.Equal(EKUOID) { criticalEKU = ext.Critical } } if !criticalEKU { return errors.New("certificate must set EKU to critical") } // If the chain contains intermediates, verify that the extended key // usage includes the extended key usage timestamping for EKU chaining if len(certs) > 2 { for _, c := range certs[1 : len(certs)-1] { var hasExtKeyUsageTimeStamping bool for _, extKeyUsage := range c.ExtKeyUsage { if extKeyUsage == x509.ExtKeyUsageTimeStamping { hasExtKeyUsageTimeStamping = true break } } if !hasExtKeyUsageTimeStamping { return errors.New(`certificate must have extended key usage timestamping set to sign timestamping certificates`) } } } // Verify the signer's public key matches the leaf certificate if err := cryptoutils.EqualKeys(certs[0].PublicKey, signer.Public()); err != nil { return err } // Verify the key's strength return cryptoutils.ValidatePubKey(signer.Public()) } golang-github-sigstore-timestamp-authority-1.2.3/pkg/x509/x509_test.go000066400000000000000000000037341470602636300255270ustar00rootroot00000000000000// Copyright 2022 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package x509 import ( "crypto/x509" "strings" "testing" "github.com/sigstore/timestamp-authority/pkg/x509/testutils" ) func TestVerifyCertChain(t *testing.T) { // success with leaf, intermediate, and root rootCert, rootKey, _ := testutils.GenerateRootCa() subCert, subKey, _ := testutils.GenerateSubordinateCa(rootCert, rootKey) leafCert, leafKey, _ := testutils.GenerateLeafCert(subCert, subKey) if err := VerifyCertChain([]*x509.Certificate{leafCert, subCert, rootCert}, leafKey); err != nil { t.Fatalf("unexpected failure verifying certificate chain: %v", err) } // success with leaf and root leafFromRootCert, leafFromRootKey, _ := testutils.GenerateLeafCert(rootCert, rootKey) if err := VerifyCertChain([]*x509.Certificate{leafFromRootCert, rootCert}, leafFromRootKey); err != nil { t.Fatalf("unexpected failure verifying certificate chain: %v", err) } // failure: not enough certificates if err := VerifyCertChain([]*x509.Certificate{leafCert}, leafKey); err == nil || !strings.Contains(err.Error(), "must contain at least two") { t.Fatalf("expected failure verifying certificate chain: %v", err) } // failure: mismatched public key if err := VerifyCertChain([]*x509.Certificate{leafCert, subCert, rootCert}, leafFromRootKey); err == nil || !strings.Contains(err.Error(), "public keys are not equal") { t.Fatalf("expected failure verifying certificate chain: %v", err) } } golang-github-sigstore-timestamp-authority-1.2.3/release/000077500000000000000000000000001470602636300235575ustar00rootroot00000000000000golang-github-sigstore-timestamp-authority-1.2.3/release/README.md000066400000000000000000000030621470602636300250370ustar00rootroot00000000000000# Release This directory contain the files and scripts to run a timestamp release. # Cutting a timestamp Release 1. Release notes: Create a PR to update and review release notes in [CHANGELOG.md](../CHANGELOG.md). - Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes. You can get a list of pull requests since the last release by substituting in the date of the last release and running: ``` git log --pretty="* %s" --after="YYYY-MM-DD" ``` and a list of authors by running: ``` git log --pretty="* %an" --after="YYYY-MM-DD" | sort -u ``` 1. Merge the CHANGELOG.md pull request 1. Sync your repository's main branch and tag the repository ```shell $ export RELEASE_TAG= $ git tag -s ${RELEASE_TAG} -m "${RELEASE_TAG}" $ git push upstream ${RELEASE_TAG} ``` Note that `upstream` should be the upstream Sigstore repository. You may have to change this if you've configured remotes. Add the Sigstore repository as `upstream` with the following: ```shell $ git remote add upstream git@github.com:sigstore/timestamp-authority.git ``` 1. This will trigger a GitHub Workflow that will build the binaries and the images. 1. Go to [releases](https://github.com/sigstore/timestamp-authority/releases) and edit the draft release. The tag should be selected automatically. Edit the release notes, copying in the changelog. Click "Publish Release". 1. Send an announcement email to `sigstore-dev@googlegroups.com` mailing list 1. Post on the `#general` Slack channel golang-github-sigstore-timestamp-authority-1.2.3/release/ko-sign-release-images.sh000077500000000000000000000030331470602636300303450ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright 2022 The Sigstore Authors # # Licensed under the Apache License, Version 2.0 (the "License""; # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -o errexit set -o nounset set -o pipefail : "${GIT_HASH:?Environment variable empty or not defined.}" : "${GIT_VERSION:?Environment variable empty or not defined.}" if [[ ! -f timestampServerImagerefs ]]; then echo "timestampServerImagerefs not found" exit 1 fi if [[ ! -f timestampCLIImagerefs ]]; then echo "timestampCLIImagerefs not found" exit 1 fi echo "Signing images with Keyless..." readarray -t server_images < <(cat timestampServerImagerefs || true) cosign sign --yes -a GIT_HASH="${GIT_HASH}" -a GIT_VERSION="${GIT_VERSION}" "${server_images[@]}" cosign verify --certificate-identity-regexp ".*" --certificate-oidc-issuer-regexp ".*" "${server_images[@]}" readarray -t cli_images < <(cat timestampCLIImagerefs || true) cosign sign --yes -a GIT_HASH="${GIT_HASH}" -a GIT_VERSION="${GIT_VERSION}" "${cli_images[@]}" cosign verify --certificate-identity-regexp ".*" --certificate-oidc-issuer-regexp ".*" "${cli_images[@]}" golang-github-sigstore-timestamp-authority-1.2.3/release/ldflags.sh000077500000000000000000000031201470602636300255260ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright 2022 The Sigstore Authors # # Licensed under the Apache License, Version 2.0 (the "License""; # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -o errexit set -o nounset set -o pipefail # Output LDFlAGS for a given environment. LDFLAGS are applied to all go binary # builds. # # Args: env function ldflags() { local GIT_VERSION=$(git describe --tags --always --dirty) local GIT_COMMIT=$(git rev-parse HEAD) local GIT_TREESTATE="clean" if [[ $(git diff --stat) != '' ]]; then GIT_TREESTATE="dirty" fi local DATE_FMT="+%Y-%m-%dT%H:%M:%SZ" local BUILD_DATE=$(date "$DATE_FMT") local SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) if [ $SOURCE_DATE_EPOCH ] then local BUILD_DATE=$(date -u -d "@$SOURCE_DATE_EPOCH" "$DATE_FMT" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" "$DATE_FMT" 2>/dev/null || date -u "$DATE_FMT") fi echo "-buildid= -X sigs.k8s.io/release-utils/version.gitVersion=$GIT_VERSION \ -X sigs.k8s.io/release-utils/version.gitCommit=$GIT_COMMIT \ -X sigs.k8s.io/release-utils/version.gitTreeState=$GIT_TREESTATE \ -X sigs.k8s.io/release-utils/version.buildDate=$BUILD_DATE" } golang-github-sigstore-timestamp-authority-1.2.3/release/release.mk000066400000000000000000000003321470602636300255260ustar00rootroot00000000000000########################### # sign section ########################### .PHONY: sign-container-release sign-container-release: ko GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ./release/ko-sign-release-images.sh