pax_global_header00006660000000000000000000000064146371355100014517gustar00rootroot0000000000000052 comment=5d4e11eb0b9a1b20075d87a5acda9f2cec34ca69 sigstore-1.8.6/000077500000000000000000000000001463713551000133725ustar00rootroot00000000000000sigstore-1.8.6/.gitattributes000066400000000000000000000000451463713551000162640ustar00rootroot00000000000000/pkg/generated/** linguist-generated sigstore-1.8.6/.github/000077500000000000000000000000001463713551000147325ustar00rootroot00000000000000sigstore-1.8.6/.github/dependabot.yml000066400000000000000000000040631463713551000175650ustar00rootroot00000000000000--- version: 2 updates: - package-ecosystem: gomod directory: "/" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" # hack/tools/go.mod - package-ecosystem: gomod directory: "./hack/tools" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" # test/fuzz/go.mod - package-ecosystem: gomod directory: "./test/fuzz" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" # pkg/signature/kms/aws/go.mod - package-ecosystem: gomod directory: "./pkg/signature/kms/aws" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" # pkg/signature/kms/azure/go.mod - package-ecosystem: gomod directory: "./pkg/signature/kms/azure" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" # pkg/signature/kms/gcp/go.mod - package-ecosystem: gomod directory: "./pkg/signature/kms/gcp" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" # pkg/signature/kms/hashivault/go.mod - package-ecosystem: gomod directory: "./pkg/signature/kms/hashivault" schedule: interval: "weekly" open-pull-requests-limit: 10 groups: all: update-types: - "minor" - "patch" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" groups: all: update-types: - "minor" - "patch" - package-ecosystem: "docker" directory: "/test/e2e" schedule: interval: "weekly" groups: all: update-types: - "minor" - "patch" sigstore-1.8.6/.github/workflows/000077500000000000000000000000001463713551000167675ustar00rootroot00000000000000sigstore-1.8.6/.github/workflows/codeql.yml000066400000000000000000000033311463713551000207610ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: CodeQL on: push: branches: [ main ] pull_request: # The branches below must be a subset of the branches above branches: [ main ] permissions: contents: read security-events: write jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: [ 'go' ] steps: - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version-file: go.mod check-latest: true # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@99c9897648dded3fe63d6f328c46089dd57735ca # v2.17.0 with: languages: ${{ matrix.language }} build-mode: manual - name: build run: make pkg - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@99c9897648dded3fe63d6f328c46089dd57735ca # v2.17.0 with: category: "/language:${{ matrix.language }}" sigstore-1.8.6/.github/workflows/depsreview.yml000066400000000000000000000017201463713551000216670ustar00rootroot00000000000000# # 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@72eb03d02c7872a771aacd928f3123ac62ad6d3a # 4.3.3 sigstore-1.8.6/.github/workflows/e2e_test.yml000066400000000000000000000035121463713551000212250ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: test on: push: branches: [ main ] pull_request: branches: [ main ] permissions: contents: read jobs: e2e_test: name: e2e integration tests runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version-file: go.mod check-latest: true - name: Cache Modules uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - name: Pull chrome (from ubuntu repository) run: | wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add - sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' sudo apt update && sudo apt install -y google-chrome-stable - name: Docker Build working-directory: ./test/e2e run: docker-compose build - name: Integration test run: make test-e2e sigstore-1.8.6/.github/workflows/fuzzing.yml000066400000000000000000000014301463713551000212040ustar00rootroot00000000000000name: CIFuzz on: push: branches: - main permissions: contents: read jobs: Fuzzing: runs-on: ubuntu-latest steps: - name: Build Fuzzers id: build uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: "sigstore" dry-run: false - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: "sigstore" fuzz-seconds: 600 dry-run: false - name: Upload Crash uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: failure() && steps.build.outcome == 'success' with: name: artifacts path: ./out/artifacts sigstore-1.8.6/.github/workflows/scorecard.yml000066400000000000000000000020171463713551000214570ustar00rootroot00000000000000name: Scorecard supply-chain security on: # (Optional) For Branch-Protection check. Only the default branch is supported. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection # branch_protection_rule: # To guarantee Maintained check is occasionally updated. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained schedule: - cron: '36 0 * * 0' push: branches: ["main"] # Declare default permissions as none. permissions: {} jobs: analysis: name: Scorecard analysis permissions: # Needed to upload the results to code-scanning dashboard. security-events: write # Needed to publish results and get a badge (see publish_results below). id-token: write uses: sigstore/community/.github/workflows/reusable-scorecard.yml@main # (Optional) Disable publish results: # with: # publish_results: false # (Optional) Enable Branch-Protection check: # secrets: # scorecard_token: ${{ secrets.SCORECARD_TOKEN }} sigstore-1.8.6/.github/workflows/sync-module-tags.yaml000066400000000000000000000022601463713551000230460ustar00rootroot00000000000000on: push: tags: ['v*'] permissions: contents: write # When a repository has multiple Go modules, in order to version the non-root # modules, the repo must have a tag named like '/'. This # workflow responds to pushes of tags named like "vXXX" by also tagging # / accordingly, for all sub-Go-modules. # # For example, when tagging v2.3.4, this workflow will tag the same commit with # pkg/signature/kms/aws/v2.3.4, so that the kms/aws module is also tagged # v2.3.4. jobs: sync-tags: runs-on: ubuntu-latest strategy: matrix: module: - pkg/signature/kms/aws - pkg/signature/kms/azure - pkg/signature/kms/gcp - pkg/signature/kms/hashivault steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - run: | tag="${{ matrix.module }}/${{ github.ref_name }}" echo tagging "${tag}" git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" git tag -a "${tag}" -m "syncing module ${{ matrix.module }} @ ${{ github.ref_name }}" git push origin "${tag}" sigstore-1.8.6/.github/workflows/test.yml000066400000000000000000000036161463713551000204770ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: test permissions: contents: read on: push: branches: [ main ] pull_request: branches: [ main ] jobs: unit_test: name: unit tests runs-on: ubuntu-latest strategy: matrix: go-version: - 1.22.x steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: ${{ matrix.go-version }} check-latest: true - name: Cache Modules uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - run: | for submodule in \ . \ pkg/signature/kms/aws \ pkg/signature/kms/azure \ pkg/signature/kms/gcp \ pkg/signature/kms/hashivault; do pushd $submodule go mod tidy go build -v ./... go test -v ./... popd done - name: Ensure no files were modified as a result of the build run: git update-index --refresh && git diff-index --quiet HEAD -- || git diff --exit-code sigstore-1.8.6/.github/workflows/verify.yml000066400000000000000000000037271463713551000210270ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: verify on: push: branches: [ main ] pull_request: branches: [ main ] env: GO_VERSION: '1.21' permissions: contents: read jobs: license-check: name: license boilerplate check runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: ${{ env.GO_VERSION }} check-latest: true - name: Install addlicense run: go install github.com/google/addlicense@v1.0.0 - name: Check license headers run: | set -e addlicense -l apache -c 'The Sigstore Authors' -v * git diff --exit-code golangci: permissions: contents: read # for actions/checkout to fetch code pull-requests: read # for golangci/golangci-lint-action to fetch pull requests name: lint checks runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: ${{ env.GO_VERSION }} check-latest: true - name: golangci-lint uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 timeout-minutes: 5 with: version: v1.57 sigstore-1.8.6/.gitignore000066400000000000000000000000641463713551000153620ustar00rootroot00000000000000.DS_Store .idea/* sigstore *fuzz.zip bin* .vscode/* sigstore-1.8.6/.golangci.yml000066400000000000000000000024721463713551000157630ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. linters: enable: - asciicheck - errcheck - errorlint - forcetypeassert - gofmt - gofumpt - goimports - gosec - gocritic - importas - prealloc - revive - misspell - stylecheck - tparallel - unconvert - unparam - unused - whitespace output: uniq-by-line: false issues: include: # revive `package-comments` and `exported` rules. - EXC0012 - EXC0013 - EXC0014 - EXC0015 exclude-rules: - path: _test\.go linters: - errcheck - gosec - path: pkg/tuf linters: - revive max-issues-per-linter: 0 max-same-issues: 0 linters-settings: gofumpt: extra-rules: true run: issues-exit-code: 1 timeout: 10m sigstore-1.8.6/CODEOWNERS000066400000000000000000000002631463713551000147660ustar00rootroot00000000000000@sigstore/sigstore-codeowners # The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order): # bobcallaway # dekkagaijin # dlorenc # lukehinds sigstore-1.8.6/CODE_OF_CONDUCT.md000066400000000000000000000062161463713551000161760ustar00rootroot00000000000000# 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/sigstore-1.8.6/COPYRIGHT.txt000066400000000000000000000010631463713551000155030ustar00rootroot00000000000000 Copyright 2021 The Sigstore Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. sigstore-1.8.6/LICENSE000066400000000000000000000261361463713551000144070ustar00rootroot00000000000000 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. sigstore-1.8.6/Makefile000066400000000000000000000055541463713551000150430ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. .PHONY: all pkg test test-e2e clean lint fuzz help all: pkg fuzz TOOLS_DIR := hack/tools TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin) FUZZ_DIR := ./test/fuzz INTEGRATION_TEST_DIR := ./test/e2e GO-FUZZ-BUILD := $(TOOLS_BIN_DIR)/go-fuzz-build GOLANGCI_LINT_DIR = $(shell pwd)/bin GOLANGCI_LINT_BIN = $(GOLANGCI_LINT_DIR)/golangci-lint LDFLAGS ?= GO_MOD_DIRS = . ./pkg/signature/kms/aws ./pkg/signature/kms/azure ./pkg/signature/kms/gcp ./pkg/signature/kms/hashivault golangci-lint: rm -f $(GOLANGCI_LINT_BIN) || : set -e ;\ GOBIN=$(GOLANGCI_LINT_DIR) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.53.2 ;\ lint: golangci-lint ## Run golangci-lint $(GOLANGCI_LINT_BIN) run -v --new-from-rev=HEAD~ ./... pkg: ## Build pkg set -o xtrace; \ for dir in $(GO_MOD_DIRS) ; do \ cd $$dir && CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" ./... && cd - >/dev/null; \ done test: ## Run Tests for all Go modules. set -o xtrace; \ for dir in $(GO_MOD_DIRS) ; do \ cd $$dir && go test ./... && cd - >/dev/null; \ done tidy: ## Run go mod tidy all Go modules. set -o xtrace; \ for dir in $(GO_MOD_DIRS) ; do \ cd $$dir && go mod tidy && cd - >/dev/null; \ done test-e2e: ## Run E2E Tests cd $(INTEGRATION_TEST_DIR); ./e2e-test.sh fuzz: $(GO-FUZZ-BUILD) ## Run Fuzz tests cd $(FUZZ_DIR);$(GO-FUZZ-BUILD) -o pem-fuzz.zip ./pem cd $(FUZZ_DIR);$(GO-FUZZ-BUILD) -o signature-fuzz.zip ./signature cd $(FUZZ_DIR);$(GO-FUZZ-BUILD) -o fuzz-fuzz.zip . cd $(FUZZ_DIR);$(GO-FUZZ-BUILD) -o dsse-fuzz.zip ./dsse clean: ## Clean workspace rm -rf sigstore rm -f $(FUZZ_DIR)/*fuzz.zip rm -rf $(TOOLS_BIN_DIR) ## -------------------------------------- ## Tooling Binaries ## -------------------------------------- $(GO-FUZZ-BUILD): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR);go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/go-fuzz-build github.com/dvyukov/go-fuzz/go-fuzz-build ################## # help ################## help: ## Display this help @awk \ -v "col=${COLOR}" -v "nocol=${NOCOLOR}" \ ' \ BEGIN { \ FS = ":.*##" ; \ printf "\nUsage:\n make %s%s\n", col, nocol \ } \ /^[a-zA-Z_-]+:.*?##/ { \ printf " %s%-15s%s %s\n", col, $$1, nocol, $$2 \ } \ /^##@/ { \ printf "\n%s%s%s\n", col, substr($$0, 5), nocol \ } \ ' $(MAKEFILE_LIST) sigstore-1.8.6/POLICY.md000066400000000000000000000144101463713551000147130ustar00rootroot00000000000000# Cryptographic Algorithms / KMS Policy sigstore/sigstore contains interfaces to provide signing and verification options with in-memory and cloud-provider KMS keys. This document specifies the currently supported signing and hashing algorithms and KMS providers, along with criteria for proposing new algorithms and providers. ## Signing algorithms Sigstore supports the following signing algorithms: * RSA, with key sizes: * 2048 * 3072 * 4096 * ECDSA, with curves: * NIST P-224 (secp224r1) * NIST P-256 (secp256r1, prime256v1) * NIST P-384 (secp384r1) * NIST P-521 (secp521r1) * Ed25519 Sigstore supports both the RSA-PKCS#1v1.5 and RSA-PSS signature schemes, and will only support well-known schemes implemented by the Golang crypto package. Sigstore will not support non-standard RSA key sizes. Sigstore will only support well-known ECDSA curves implemented by the Golang crypto package. ### Post-quantum signing algorithms Post-quantum (PQ) computing will require new signing algorithms, as modern signing algorithms that depend on the difficulty of the integer factorization problem and discrete logarithm problem will be easily broken by quantum computing. Sigstore does not yet have a stance on which PQ signing algorithms will be supported. NIST is [currently selecting](https://csrc.nist.gov/Projects/post-quantum-cryptography/selected-algorithms-2022) a set of recommended signing algorithms. We present some high-level thoughts on the top candidates and existing hash-based schemes: * LMS/XMSS - Hash-based signature schemes that are quick to produce and verify with a small public key size, but larger in signature size. NIST selected these two algorithms for hash-based signature schemes in 2020 ([SP 800.208](https://csrc.nist.gov/pubs/sp/800/208/final)). LMS/XMSS have a significant drawback in that these signatures are stateful. Signing key reuse over a given amount breaks the security of LMS/XMSS. These signing algorithms could work well for Sigstore's usage of ephemeral keys, since a key should only be used once for a signing event. However, these would not work for: * Self-managed keys that may be reused, unless the signer keeps track of usage * CAs (Fulcio) that sign certificates or transparency logs (Rekor) that sign log checkpoints, unless the services keep track of usage. For Sigstore, service key rotation is currently a manual process involving a TUF root signing event, so we are unable to automatically rotate service key material. * TUF metadata itself, which is signed, unless the metadata keys are rotated out before being reused too frequently. * SPHINCS+ - Hash-based signature scheme that is quick to verify with a small public key size, but with a very large signature size and is very slow to verify. Note that this scheme is stateless, so reuse is not a concern. Neither of the drawbacks are a significant concern in code signing, although storage costs would increase for transparency log operators. Code signing can be slow, because it's a one-time process that can be automated. * CRYSTALS-Dilithium - Lattice-based signature scheme with fast signing and verification, but larger public key and signature sizes. Dilithium offers good tradeoffs between signing/verification time and public key/signature sizes, though the larger key and signature sizes will increase storage costs for transparency log operators. * Falcon - Lattice-based signature scheme with fast verification, with larger public key and signature sizes, but smaller than Dilithium, and slower signing than Dilithium. Like Dilithium, Falcon offers good tradeoffs between signing/verification time and public key/signature sizes. However, Falcon is likely to be a complex implementation and there are some concerns around its use of floating point operations. This is not an exhaustive list, and this list may be updated as candidates are removed or if new signing algorithms are designed. We recommend reading Cloudflare's [scheme comparison](https://blog.cloudflare.com/sizing-up-post-quantum-signatures/) and [a deep dive into signing](https://blog.cloudflare.com/post-quantum-signatures/) to learn more. We will add support for PQ signing algorithms once the Golang crypto package adopts these signing algorithms. We will accept PRs with experimental support for NIST candidates once well-known and vetted Golang libraries are created for PQ signing. We will not accept PRs for PQ signing algorithms based on C implementations with a Go shim, though we encourage experimentation on forks and welcome any feedback on recommended algorithms in a GitHub discussion. ## Hashing algorithms Sigstore supports the following hashing algorithms: * SHA256 * SHA384 * SHA512 Supported but discouraged algorithms include: * SHA1 - SHA1 is allowed only in limited cases for compatibility with certain file types that require SHA1. * SHA224 Sigstore will add support for SHA3 once the SHA3 implementation is moved from Golang's x/crypto package to its standard crypto package. ## KMS providers Sigstore currently supports the following KMS providers: * Amazon Web Services * Google Cloud Platform * Hashicorp Vault * Microsoft Azure PRs for new providers will only be accepted if the following conditions are met: * Maintainers of Sigstore are familiar with the provider and able to debug issues with the provider and with end-to-end tests. * There is significant community interest in the KMS provider. * The provider is well-maintained with regular contributions (if open source) and releases should be frequent. The license must be compatible with the Apache 2.0 license. * The provider has not had significant security and/or privacy vulnerabilities. Sigstore reserves the right to remove support for a provider if it is shown to not take security and/or privacy seriously. * The PR contains sufficient unit and end-to-end tests. Please file an issue before starting implementation of the KMS provider to confirm that the provider meets these requirements. We encourage maintaining a private fork of sigstore/sigstore and Cosign if you wish to support a provider that does not meet these requirements. Sigstore's roadmap for future client updates includes a porcelain-and-plumbing model. One goal will be to add plugin support such that users could bring their own signing and verification modules without requiring a fork of Cosign. sigstore-1.8.6/README.md000066400000000000000000000025721463713551000146570ustar00rootroot00000000000000# sigstore framework [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/sigstore.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:sigstore) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5716/badge)](https://bestpractices.coreinfrastructure.org/projects/5716) sigstore/sigstore contains common [Sigstore](https://www.sigstore.dev/) code: that is, code shared by infrastructure (e.g., [Fulcio](https://github.com/sigstore/fulcio) and [Rekor](https://github.com/sigstore/rekor)) and Go language clients (e.g., [Cosign](https://github.com/sigstore/cosign) and [Gitsign](https://github.com/sigstore/gitsign)). This library currently provides: * A signing interface (support for ecdsa, ed25519, rsa, DSSE (in-toto)) * OpenID Connect fulcio client code The following KMS systems are available: * AWS Key Management Service * Azure Key Vault * HashiCorp Vault * Google Cloud Platform Key Management Service For example code, look at the relevant test code for each main code file. ## Fuzzing The fuzzing tests are within https://github.com/sigstore/sigstore/tree/main/test/fuzz ## Security Should you discover any security issues, please refer to sigstores [security process](https://github.com/sigstore/.github/blob/main/SECURITY.md) For container signing, you want [cosign](https://github.com/sigstore/cosign) sigstore-1.8.6/codecov.yml000066400000000000000000000011761463713551000155440ustar00rootroot00000000000000# 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 sigstore-1.8.6/docs/000077500000000000000000000000001463713551000143225ustar00rootroot00000000000000sigstore-1.8.6/docs/oid-info.md000066400000000000000000000022601463713551000163500ustar00rootroot00000000000000# Sigstore OID information ## Description Sigstore maintains its own Private Enterprise Number (57264) with the Internet Assigned Numbers Authority to help identify and organize additional metadata in code signing certificates issued by Fulcio instances. This document aims to provide a simple directory of values in use with an explanation of their meaning. ## Directory Note that all values begin from the root OID 1.3.6.1.4.1.57264 (registered by Sigstore)[http://oid-info.com/get/1.3.6.1.4.1.57264]. When adding additional OIDs under the root, please update the above link with the child OID. | OID | Name | Details | | ------------------- | ------------------- | ------------------------------------------------------------- | | 1.3.6.1.4.1.57264.1 | Fulcio | https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md | | 1.3.6.1.4.1.57264.2 | Timestamp Authority | https://github.com/sigstore/timestamp-authority/blob/main/docs/tsa-policy.md#52-identification | | 1.3.6.1.4.1.57264.3 | Rekor | https://github.com/sigstore/rekor | sigstore-1.8.6/go.mod000066400000000000000000000027321463713551000145040ustar00rootroot00000000000000module github.com/sigstore/sigstore go 1.22.0 require ( github.com/coreos/go-oidc/v3 v3.10.0 github.com/go-jose/go-jose/v3 v3.0.3 github.com/go-rod/rod v0.116.1 github.com/go-test/deep v1.1.1 github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.19.2 github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/secure-systems-lab/go-securesystemslib v0.8.0 github.com/segmentio/ksuid v1.0.4 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/stretchr/testify v1.9.0 github.com/theupdateframework/go-tuf v0.7.0 golang.org/x/crypto v0.24.0 golang.org/x/oauth2 v0.21.0 golang.org/x/term v0.21.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/ysmood/fetchup v0.2.3 // indirect github.com/ysmood/goob v0.4.0 // indirect github.com/ysmood/got v0.40.0 // indirect github.com/ysmood/gson v0.7.3 // indirect github.com/ysmood/leakless v0.8.0 // indirect golang.org/x/sys v0.21.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) sigstore-1.8.6/go.sum000066400000000000000000000531561463713551000145370ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-rod/rod v0.116.1 h1:BDMZY3qm/14SmvHBV7DoFUhXeJ2MbUYgumQ88b+v2WE= github.com/go-rod/rod v0.116.1/go.mod h1:3Ash9fYwznqz9S1uLQgQRStur4fCXjoxxGW+ym6TYjU= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/protobuf v1.2.0/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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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.5/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.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= 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/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 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/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= 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/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= github.com/ysmood/gop v0.2.0 h1:+tFrG0TWPxT6p9ZaZs+VY+opCvHU8/3Fk6BaNv6kqKg= github.com/ysmood/gop v0.2.0/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk= github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY= github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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/sys v0.0.0-20180909124046-d0be0721c37e/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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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.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.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.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.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= 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.6/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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= 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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/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= sigstore-1.8.6/hack/000077500000000000000000000000001463713551000143005ustar00rootroot00000000000000sigstore-1.8.6/hack/tools/000077500000000000000000000000001463713551000154405ustar00rootroot00000000000000sigstore-1.8.6/hack/tools/go.mod000066400000000000000000000020111463713551000165400ustar00rootroot00000000000000module github.com/sigstore/sigstore/hack/tools go 1.21 require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20211123104302-8fea106b46e2 github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1 ) require ( github.com/containerd/stargz-snapshotter/estargz v0.10.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/google/go-containerregistry v0.7.0 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/vbatts/tar-split v0.11.2 // indirect golang.org/x/mod v0.5.1 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.1.0 // indirect golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) require ( github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect github.com/stephens2424/writerset v1.0.2 // indirect ) sigstore-1.8.6/hack/tools/go.sum000066400000000000000000004010361463713551000165770ustar00rootroot00000000000000bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20211123104302-8fea106b46e2 h1:ZsXCKWs2ZsvKzvc8HnGZg1QYg57N93qX4cb/SGhap8U= github.com/AdaLogics/go-fuzz-headers v0.0.0-20211123104302-8fea106b46e2/go.mod h1:qoZ1l1qQI1pAOwl9634GFAN4Z4cADOGCYOw3u9QAitw= github.com/AdamKorcz/go-fuzz-headers v0.0.0-20210312213058-32f4d319f0d2/go.mod h1:VPevheIvXETHZT/ddjwarP3POR5p/cnH9Hy5yoFnQjc= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apex/log v1.4.0/go.mod h1:UMNC4vQNC7hb5gyr47r18ylK1n34rV7GO+gb0wpXvcE= github.com/apex/logs v0.0.7/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= 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/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/stargz-snapshotter/estargz v0.10.0 h1:glqzafvxBBAMo+x2w2sdDjUDZeTqqLJmqZPY05qehCU= github.com/containerd/stargz-snapshotter/estargz v0.10.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v20.10.10+incompatible h1:kcbwdgWbrBOH8QwQzaJmyriHwF7XIl4HT1qh0HTRys4= github.com/docker/cli v20.10.10+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM= github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1 h1:YQOLTC8zvFaNSEuMexG0i7pY26bOksnQFsSJfGclo54= github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 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/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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.4.1/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.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/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.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.7.0 h1:u0onUUOcyoCDHEiJoyR1R1gx5er1+r06V5DBhUU5ndk= github.com/google/go-containerregistry v0.7.0/go.mod h1:2zaoelrL0d08gGbpdP3LqyUuBmhWbpD6IOe2s9nLS2k= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 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/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/umoci v0.4.7/go.mod h1:lgJ4bnwJezsN1o/5d7t/xdRPvmf8TvBko5kKYJsYvgo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rootless-containers/proto v0.1.0/go.mod h1:vgkUFZbQd0gcE/K/ZwtE4MYjZPu0UNHLXIQxhyqAFh8= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stephens2424/writerset v1.0.2 h1:znRLgU6g8RS5euYRcy004XeE4W+Tu44kALzy7ghPif8= github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vbatts/go-mtree v0.5.0/go.mod h1:7JbaNHyBMng+RP8C3Q4E+4Ca8JnGQA2R/MB+jb4tSOk= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211111162719-482062a4217b/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/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/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.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigstore-1.8.6/hack/tools/tools.go000066400000000000000000000016521463713551000171330ustar00rootroot00000000000000//go:build tools // +build tools // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This package imports things required by build scripts, to force `go mod` to see them as dependencies package tools import ( _ "github.com/AdaLogics/go-fuzz-headers" _ "github.com/dvyukov/go-fuzz/go-fuzz" _ "github.com/dvyukov/go-fuzz/go-fuzz-build" _ "github.com/dvyukov/go-fuzz/go-fuzz-dep" ) sigstore-1.8.6/pkg/000077500000000000000000000000001463713551000141535ustar00rootroot00000000000000sigstore-1.8.6/pkg/cryptoutils/000077500000000000000000000000001463713551000165545ustar00rootroot00000000000000sigstore-1.8.6/pkg/cryptoutils/certificate.go000066400000000000000000000124201463713551000213640ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package cryptoutils implements support for working with encoded certificates, public keys, and private keys package cryptoutils import ( "bytes" "crypto/rand" "crypto/x509" "encoding/pem" "errors" "fmt" "io" "math/big" "time" ) const ( // CertificatePEMType is the string "CERTIFICATE" to be used during PEM encoding and decoding CertificatePEMType PEMType = "CERTIFICATE" ) // MarshalCertificateToPEM converts the provided X509 certificate into PEM format func MarshalCertificateToPEM(cert *x509.Certificate) ([]byte, error) { if cert == nil { return nil, errors.New("nil certificate provided") } return PEMEncode(CertificatePEMType, cert.Raw), nil } // MarshalCertificatesToPEM converts the provided X509 certificates into PEM format func MarshalCertificatesToPEM(certs []*x509.Certificate) ([]byte, error) { buf := bytes.Buffer{} for _, cert := range certs { pemBytes, err := MarshalCertificateToPEM(cert) if err != nil { return nil, err } _, _ = buf.Write(pemBytes) } return buf.Bytes(), nil } // UnmarshalCertificatesFromPEM extracts one or more X509 certificates from the provided // byte slice, which is assumed to be in PEM-encoded format. func UnmarshalCertificatesFromPEM(pemBytes []byte) ([]*x509.Certificate, error) { result := []*x509.Certificate{} remaining := pemBytes remaining = bytes.TrimSpace(remaining) for len(remaining) > 0 { var certDer *pem.Block certDer, remaining = pem.Decode(remaining) if certDer == nil { return nil, errors.New("error during PEM decoding") } cert, err := x509.ParseCertificate(certDer.Bytes) if err != nil { return nil, err } result = append(result, cert) } return result, nil } // UnmarshalCertificatesFromPEMLimited extracts one or more X509 certificates from the provided // byte slice, which is assumed to be in PEM-encoded format. Fails after a specified // number of iterations. A reasonable limit is 10 iterations. func UnmarshalCertificatesFromPEMLimited(pemBytes []byte, iterations int) ([]*x509.Certificate, error) { result := []*x509.Certificate{} remaining := pemBytes remaining = bytes.TrimSpace(remaining) count := 0 for len(remaining) > 0 { if count == iterations { return nil, errors.New("too many certificates specified in PEM block") } var certDer *pem.Block certDer, remaining = pem.Decode(remaining) if certDer == nil { return nil, errors.New("error during PEM decoding") } cert, err := x509.ParseCertificate(certDer.Bytes) if err != nil { return nil, err } result = append(result, cert) count++ } return result, nil } // LoadCertificatesFromPEM extracts one or more X509 certificates from the provided // io.Reader. func LoadCertificatesFromPEM(pem io.Reader) ([]*x509.Certificate, error) { fileBytes, err := io.ReadAll(pem) if err != nil { return nil, err } return UnmarshalCertificatesFromPEM(fileBytes) } func formatTime(t time.Time) string { return t.UTC().Format(time.RFC3339) } // CheckExpiration verifies that epoch is during the validity period of // the certificate provided. // // It returns nil if issueTime < epoch < expirationTime, and error otherwise. func CheckExpiration(cert *x509.Certificate, epoch time.Time) error { if cert == nil { return errors.New("certificate is nil") } if cert.NotAfter.Before(epoch) { return fmt.Errorf("certificate expiration time %s is before %s", formatTime(cert.NotAfter), formatTime(epoch)) } if cert.NotBefore.After(epoch) { return fmt.Errorf("certificate issued time %s is before %s", formatTime(cert.NotBefore), formatTime(epoch)) } return nil } // ParseCSR parses a PKCS#10 PEM-encoded CSR. func ParseCSR(csr []byte) (*x509.CertificateRequest, error) { derBlock, _ := pem.Decode(csr) if derBlock == nil || derBlock.Bytes == nil { return nil, errors.New("no CSR found while decoding") } correctType := false acceptedHeaders := []string{"CERTIFICATE REQUEST", "NEW CERTIFICATE REQUEST"} for _, v := range acceptedHeaders { if derBlock.Type == v { correctType = true } } if !correctType { return nil, fmt.Errorf("DER type %v is not of any type %v for CSR", derBlock.Type, acceptedHeaders) } return x509.ParseCertificateRequest(derBlock.Bytes) } // GenerateSerialNumber creates a compliant serial number as per RFC 5280 4.1.2.2. // Serial numbers must be positive, and can be no longer than 20 bytes. // The serial number is generated with 159 bits, so that the first bit will always // be 0, resulting in a positive serial number. func GenerateSerialNumber() (*big.Int, error) { // Pick a random number from 0 to 2^159. serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil)) if err != nil { return nil, errors.New("error generating serial number") } return serial, nil } sigstore-1.8.6/pkg/cryptoutils/certificate_test.go000066400000000000000000000513541463713551000224340ustar00rootroot00000000000000// Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "errors" "math/big" "strings" "testing" "time" "github.com/google/go-cmp/cmp" ) const ( cert1PEM = `-----BEGIN CERTIFICATE----- MIICyTCCAlCgAwIBAgITYZXhosLz4+Q/XCUwBySVDmU2jTAKBggqhkjOPQQDAzAq MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx MDMwOTA0NDYwOVoXDTIxMDMwOTA1MDYwMlowOjEbMBkGA1UECgwSbG9yZW5jLmRA Z21haWwuY29tMRswGQYDVQQDDBJsb3JlbmMuZEBnbWFpbC5jb20wdjAQBgcqhkjO PQIBBgUrgQQAIgNiAARIA8thgk3Zext2UWP1aBE1uoIAqetevPiEDuGKtSUPYxBv AhzrwhDTbHrj6vMQCBNE7o4AfewyJAZf6CKbee8WIakPfAjRSTQjjnZBzKvSHn4K u8SByXjFN0rde8qDqo+jggEmMIIBIjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww CgYIKwYBBQUHAwMwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUQeDktDb9QFrYxF8H xBXkAHQmvqwwHwYDVR0jBBgwFoAUyMUdAEGaJCkyUSTrDa5K7UoG0+wwgY0GCCsG AQUFBwEBBIGAMH4wfAYIKwYBBQUHMAKGcGh0dHA6Ly9wcml2YXRlY2EtY29udGVu dC02MDNmZTdlNy0wMDAwLTIyMjctYmY3NS1mNGY1ZTgwZDI5NTQuc3RvcmFnZS5n b29nbGVhcGlzLmNvbS9jYTM2YTFlOTYyNDJiOWZjYjE0Ni9jYS5jcnQwHQYDVR0R BBYwFIESbG9yZW5jLmRAZ21haWwuY29tMAoGCCqGSM49BAMDA2cAMGQCMAgjOcjN P3w/xB8bi/hKXJ9RdNH/DMADiusGtd1d/xxyFVj1xYosQ7y1G6y84VDBvQIwMfQG 8Tp8zsxDg5Oz4qUBZ/AKmkPJHhgmiHftwbb5I1S+1xdhzJtJ8Eg0M00/nqok -----END CERTIFICATE----- ` cert2PEM = `-----BEGIN CERTIFICATE----- MIICyzCCAlGgAwIBAgIUAMtHjhf/mTVArZNaNcBC1UDyDa0wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTAzMDkwNDQ3MTFaFw0yMTAzMDkwNTA3MDNaMDoxGzAZBgNVBAoMEmxvcmVuYy5k QGdtYWlsLmNvbTEbMBkGA1UEAwwSbG9yZW5jLmRAZ21haWwuY29tMHYwEAYHKoZI zj0CAQYFK4EEACIDYgAERYBuXY15kRDrwW6kpfwbp/5DmrnGnaZLvUwG1QVGV4g7 /dqNNoXpOU0TstLFSsawgc5YvcgKOw52EGBg5Fi9kUslF1M6bsAarMSTeZl7pzHb sh8B8+U/jn2HZtfCzalvo4IBJjCCASIwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM MAoGCCsGAQUFBwMDMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFK2qQ8zm+0Yz5KM8 6ybuUZPrAVX7MB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMIGNBggr BgEFBQcBAQSBgDB+MHwGCCsGAQUFBzAChnBodHRwOi8vcHJpdmF0ZWNhLWNvbnRl bnQtNjAzZmU3ZTctMDAwMC0yMjI3LWJmNzUtZjRmNWU4MGQyOTU0LnN0b3JhZ2Uu Z29vZ2xlYXBpcy5jb20vY2EzNmExZTk2MjQyYjlmY2IxNDYvY2EuY3J0MB0GA1Ud EQQWMBSBEmxvcmVuYy5kQGdtYWlsLmNvbTAKBggqhkjOPQQDAwNoADBlAjA6Nk0l eD2ey2UnPUcH6gklWo2szEobbv+uEKPYFzZ8fQn3v7nIdz8p3oSajT2oxFMCMQCQ zisxAae2OlC3p3RbPuobGVvKI6EYmfnohdvD5OgZPRskNhGAiR2e3MDQuuexbAw= -----END CERTIFICATE----- ` somethingElsePEM = `-----BEGIN OTHER THING----- MIICyjCCAlGgAwIBAgIUAJ7YnfKI0PIi90IkP1ZGVt1hbswwCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTAzMDkwNDQ4MDJaFw0yMTAzMDkwNTA3NTVaMDoxGzAZBgNVBAoMEmxvcmVuYy5k QGdtYWlsLmNvbTEbMBkGA1UEAwwSbG9yZW5jLmRAZ21haWwuY29tMHYwEAYHKoZI zj0CAQYFK4EEACIDYgAEPFq3DlRqPtYRM2XF7eKw4pZFCIo3i1mBTFNzQRL/GufH G+bQuF9D9qDWwD2sFLDauzTbaIUvpxEdu0ab0rYi0x1sV/RLyZhc7KmpFxGuPEkr agrlBGDUnxXkUj53NGLCo4IBJjCCASIwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM MAoGCCsGAQUFBwMDMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOYy000hj60o55n3 yX/sE3Kbk65NMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMIGNBggr BgEFBQcBAQSBgDB+MHwGCCsGAQUFBzAChnBodHRwOi8vcHJpdmF0ZWNhLWNvbnRl bnQtNjAzZmU3ZTctMDAwMC0yMjI3LWJmNzUtZjRmNWU4MGQyOTU0LnN0b3JhZ2Uu Z29vZ2xlYXBpcy5jb20vY2EzNmExZTk2MjQyYjlmY2IxNDYvY2EuY3J0MB0GA1Ud EQQWMBSBEmxvcmVuYy5kQGdtYWlsLmNvbTAKBggqhkjOPQQDAwNnADBkAjAYFQVj 6qsh4cQ05NDOOCBrIdwtaYuiQHCy6y/+0ujrJG8prwc7zx+mFsL0Fsd9g/QCMGZq vn2snyjRWmm8kGr62QR0T6TKIElf07EmdrAglZodYXcHhv0b0JUmdTnn30vRDQ== -----BEGIN OTHER THING----- ` ) var ( // `x509.Certificate.Equal` only compares `Raw` fields. cert1 = &x509.Certificate{ Raw: []byte{0x30, 0x82, 0x2, 0xc9, 0x30, 0x82, 0x2, 0x50, 0xa0, 0x3, 0x2, 0x1, 0x2, 0x2, 0x13, 0x61, 0x95, 0xe1, 0xa2, 0xc2, 0xf3, 0xe3, 0xe4, 0x3f, 0x5c, 0x25, 0x30, 0x7, 0x24, 0x95, 0xe, 0x65, 0x36, 0x8d, 0x30, 0xa, 0x6, 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x4, 0x3, 0x3, 0x30, 0x2a, 0x31, 0x15, 0x30, 0x13, 0x6, 0x3, 0x55, 0x4, 0xa, 0x13, 0xc, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x31, 0x11, 0x30, 0xf, 0x6, 0x3, 0x55, 0x4, 0x3, 0x13, 0x8, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x30, 0x1e, 0x17, 0xd, 0x32, 0x31, 0x30, 0x33, 0x30, 0x39, 0x30, 0x34, 0x34, 0x36, 0x30, 0x39, 0x5a, 0x17, 0xd, 0x32, 0x31, 0x30, 0x33, 0x30, 0x39, 0x30, 0x35, 0x30, 0x36, 0x30, 0x32, 0x5a, 0x30, 0x3a, 0x31, 0x1b, 0x30, 0x19, 0x6, 0x3, 0x55, 0x4, 0xa, 0xc, 0x12, 0x6c, 0x6f, 0x72, 0x65, 0x6e, 0x63, 0x2e, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x1b, 0x30, 0x19, 0x6, 0x3, 0x55, 0x4, 0x3, 0xc, 0x12, 0x6c, 0x6f, 0x72, 0x65, 0x6e, 0x63, 0x2e, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x76, 0x30, 0x10, 0x6, 0x7, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x2, 0x1, 0x6, 0x5, 0x2b, 0x81, 0x4, 0x0, 0x22, 0x3, 0x62, 0x0, 0x4, 0x48, 0x3, 0xcb, 0x61, 0x82, 0x4d, 0xd9, 0x7b, 0x1b, 0x76, 0x51, 0x63, 0xf5, 0x68, 0x11, 0x35, 0xba, 0x82, 0x0, 0xa9, 0xeb, 0x5e, 0xbc, 0xf8, 0x84, 0xe, 0xe1, 0x8a, 0xb5, 0x25, 0xf, 0x63, 0x10, 0x6f, 0x2, 0x1c, 0xeb, 0xc2, 0x10, 0xd3, 0x6c, 0x7a, 0xe3, 0xea, 0xf3, 0x10, 0x8, 0x13, 0x44, 0xee, 0x8e, 0x0, 0x7d, 0xec, 0x32, 0x24, 0x6, 0x5f, 0xe8, 0x22, 0x9b, 0x79, 0xef, 0x16, 0x21, 0xa9, 0xf, 0x7c, 0x8, 0xd1, 0x49, 0x34, 0x23, 0x8e, 0x76, 0x41, 0xcc, 0xab, 0xd2, 0x1e, 0x7e, 0xa, 0xbb, 0xc4, 0x81, 0xc9, 0x78, 0xc5, 0x37, 0x4a, 0xdd, 0x7b, 0xca, 0x83, 0xaa, 0x8f, 0xa3, 0x82, 0x1, 0x26, 0x30, 0x82, 0x1, 0x22, 0x30, 0xe, 0x6, 0x3, 0x55, 0x1d, 0xf, 0x1, 0x1, 0xff, 0x4, 0x4, 0x3, 0x2, 0x7, 0x80, 0x30, 0x13, 0x6, 0x3, 0x55, 0x1d, 0x25, 0x4, 0xc, 0x30, 0xa, 0x6, 0x8, 0x2b, 0x6, 0x1, 0x5, 0x5, 0x7, 0x3, 0x3, 0x30, 0xc, 0x6, 0x3, 0x55, 0x1d, 0x13, 0x1, 0x1, 0xff, 0x4, 0x2, 0x30, 0x0, 0x30, 0x1d, 0x6, 0x3, 0x55, 0x1d, 0xe, 0x4, 0x16, 0x4, 0x14, 0x41, 0xe0, 0xe4, 0xb4, 0x36, 0xfd, 0x40, 0x5a, 0xd8, 0xc4, 0x5f, 0x7, 0xc4, 0x15, 0xe4, 0x0, 0x74, 0x26, 0xbe, 0xac, 0x30, 0x1f, 0x6, 0x3, 0x55, 0x1d, 0x23, 0x4, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc8, 0xc5, 0x1d, 0x0, 0x41, 0x9a, 0x24, 0x29, 0x32, 0x51, 0x24, 0xeb, 0xd, 0xae, 0x4a, 0xed, 0x4a, 0x6, 0xd3, 0xec, 0x30, 0x81, 0x8d, 0x6, 0x8, 0x2b, 0x6, 0x1, 0x5, 0x5, 0x7, 0x1, 0x1, 0x4, 0x81, 0x80, 0x30, 0x7e, 0x30, 0x7c, 0x6, 0x8, 0x2b, 0x6, 0x1, 0x5, 0x5, 0x7, 0x30, 0x2, 0x86, 0x70, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x63, 0x61, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x36, 0x30, 0x33, 0x66, 0x65, 0x37, 0x65, 0x37, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x32, 0x32, 0x32, 0x37, 0x2d, 0x62, 0x66, 0x37, 0x35, 0x2d, 0x66, 0x34, 0x66, 0x35, 0x65, 0x38, 0x30, 0x64, 0x32, 0x39, 0x35, 0x34, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x33, 0x36, 0x61, 0x31, 0x65, 0x39, 0x36, 0x32, 0x34, 0x32, 0x62, 0x39, 0x66, 0x63, 0x62, 0x31, 0x34, 0x36, 0x2f, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x1d, 0x6, 0x3, 0x55, 0x1d, 0x11, 0x4, 0x16, 0x30, 0x14, 0x81, 0x12, 0x6c, 0x6f, 0x72, 0x65, 0x6e, 0x63, 0x2e, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0xa, 0x6, 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x4, 0x3, 0x3, 0x3, 0x67, 0x0, 0x30, 0x64, 0x2, 0x30, 0x8, 0x23, 0x39, 0xc8, 0xcd, 0x3f, 0x7c, 0x3f, 0xc4, 0x1f, 0x1b, 0x8b, 0xf8, 0x4a, 0x5c, 0x9f, 0x51, 0x74, 0xd1, 0xff, 0xc, 0xc0, 0x3, 0x8a, 0xeb, 0x6, 0xb5, 0xdd, 0x5d, 0xff, 0x1c, 0x72, 0x15, 0x58, 0xf5, 0xc5, 0x8a, 0x2c, 0x43, 0xbc, 0xb5, 0x1b, 0xac, 0xbc, 0xe1, 0x50, 0xc1, 0xbd, 0x2, 0x30, 0x31, 0xf4, 0x6, 0xf1, 0x3a, 0x7c, 0xce, 0xcc, 0x43, 0x83, 0x93, 0xb3, 0xe2, 0xa5, 0x1, 0x67, 0xf0, 0xa, 0x9a, 0x43, 0xc9, 0x1e, 0x18, 0x26, 0x88, 0x77, 0xed, 0xc1, 0xb6, 0xf9, 0x23, 0x54, 0xbe, 0xd7, 0x17, 0x61, 0xcc, 0x9b, 0x49, 0xf0, 0x48, 0x34, 0x33, 0x4d, 0x3f, 0x9e, 0xaa, 0x24}, } cert2 = &x509.Certificate{ Raw: []byte{0x30, 0x82, 0x2, 0xcb, 0x30, 0x82, 0x2, 0x51, 0xa0, 0x3, 0x2, 0x1, 0x2, 0x2, 0x14, 0x0, 0xcb, 0x47, 0x8e, 0x17, 0xff, 0x99, 0x35, 0x40, 0xad, 0x93, 0x5a, 0x35, 0xc0, 0x42, 0xd5, 0x40, 0xf2, 0xd, 0xad, 0x30, 0xa, 0x6, 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x4, 0x3, 0x3, 0x30, 0x2a, 0x31, 0x15, 0x30, 0x13, 0x6, 0x3, 0x55, 0x4, 0xa, 0x13, 0xc, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x31, 0x11, 0x30, 0xf, 0x6, 0x3, 0x55, 0x4, 0x3, 0x13, 0x8, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x30, 0x1e, 0x17, 0xd, 0x32, 0x31, 0x30, 0x33, 0x30, 0x39, 0x30, 0x34, 0x34, 0x37, 0x31, 0x31, 0x5a, 0x17, 0xd, 0x32, 0x31, 0x30, 0x33, 0x30, 0x39, 0x30, 0x35, 0x30, 0x37, 0x30, 0x33, 0x5a, 0x30, 0x3a, 0x31, 0x1b, 0x30, 0x19, 0x6, 0x3, 0x55, 0x4, 0xa, 0xc, 0x12, 0x6c, 0x6f, 0x72, 0x65, 0x6e, 0x63, 0x2e, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x1b, 0x30, 0x19, 0x6, 0x3, 0x55, 0x4, 0x3, 0xc, 0x12, 0x6c, 0x6f, 0x72, 0x65, 0x6e, 0x63, 0x2e, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x76, 0x30, 0x10, 0x6, 0x7, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x2, 0x1, 0x6, 0x5, 0x2b, 0x81, 0x4, 0x0, 0x22, 0x3, 0x62, 0x0, 0x4, 0x45, 0x80, 0x6e, 0x5d, 0x8d, 0x79, 0x91, 0x10, 0xeb, 0xc1, 0x6e, 0xa4, 0xa5, 0xfc, 0x1b, 0xa7, 0xfe, 0x43, 0x9a, 0xb9, 0xc6, 0x9d, 0xa6, 0x4b, 0xbd, 0x4c, 0x6, 0xd5, 0x5, 0x46, 0x57, 0x88, 0x3b, 0xfd, 0xda, 0x8d, 0x36, 0x85, 0xe9, 0x39, 0x4d, 0x13, 0xb2, 0xd2, 0xc5, 0x4a, 0xc6, 0xb0, 0x81, 0xce, 0x58, 0xbd, 0xc8, 0xa, 0x3b, 0xe, 0x76, 0x10, 0x60, 0x60, 0xe4, 0x58, 0xbd, 0x91, 0x4b, 0x25, 0x17, 0x53, 0x3a, 0x6e, 0xc0, 0x1a, 0xac, 0xc4, 0x93, 0x79, 0x99, 0x7b, 0xa7, 0x31, 0xdb, 0xb2, 0x1f, 0x1, 0xf3, 0xe5, 0x3f, 0x8e, 0x7d, 0x87, 0x66, 0xd7, 0xc2, 0xcd, 0xa9, 0x6f, 0xa3, 0x82, 0x1, 0x26, 0x30, 0x82, 0x1, 0x22, 0x30, 0xe, 0x6, 0x3, 0x55, 0x1d, 0xf, 0x1, 0x1, 0xff, 0x4, 0x4, 0x3, 0x2, 0x7, 0x80, 0x30, 0x13, 0x6, 0x3, 0x55, 0x1d, 0x25, 0x4, 0xc, 0x30, 0xa, 0x6, 0x8, 0x2b, 0x6, 0x1, 0x5, 0x5, 0x7, 0x3, 0x3, 0x30, 0xc, 0x6, 0x3, 0x55, 0x1d, 0x13, 0x1, 0x1, 0xff, 0x4, 0x2, 0x30, 0x0, 0x30, 0x1d, 0x6, 0x3, 0x55, 0x1d, 0xe, 0x4, 0x16, 0x4, 0x14, 0xad, 0xaa, 0x43, 0xcc, 0xe6, 0xfb, 0x46, 0x33, 0xe4, 0xa3, 0x3c, 0xeb, 0x26, 0xee, 0x51, 0x93, 0xeb, 0x1, 0x55, 0xfb, 0x30, 0x1f, 0x6, 0x3, 0x55, 0x1d, 0x23, 0x4, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc8, 0xc5, 0x1d, 0x0, 0x41, 0x9a, 0x24, 0x29, 0x32, 0x51, 0x24, 0xeb, 0xd, 0xae, 0x4a, 0xed, 0x4a, 0x6, 0xd3, 0xec, 0x30, 0x81, 0x8d, 0x6, 0x8, 0x2b, 0x6, 0x1, 0x5, 0x5, 0x7, 0x1, 0x1, 0x4, 0x81, 0x80, 0x30, 0x7e, 0x30, 0x7c, 0x6, 0x8, 0x2b, 0x6, 0x1, 0x5, 0x5, 0x7, 0x30, 0x2, 0x86, 0x70, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x63, 0x61, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x36, 0x30, 0x33, 0x66, 0x65, 0x37, 0x65, 0x37, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x32, 0x32, 0x32, 0x37, 0x2d, 0x62, 0x66, 0x37, 0x35, 0x2d, 0x66, 0x34, 0x66, 0x35, 0x65, 0x38, 0x30, 0x64, 0x32, 0x39, 0x35, 0x34, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x33, 0x36, 0x61, 0x31, 0x65, 0x39, 0x36, 0x32, 0x34, 0x32, 0x62, 0x39, 0x66, 0x63, 0x62, 0x31, 0x34, 0x36, 0x2f, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x1d, 0x6, 0x3, 0x55, 0x1d, 0x11, 0x4, 0x16, 0x30, 0x14, 0x81, 0x12, 0x6c, 0x6f, 0x72, 0x65, 0x6e, 0x63, 0x2e, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0xa, 0x6, 0x8, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x4, 0x3, 0x3, 0x3, 0x68, 0x0, 0x30, 0x65, 0x2, 0x30, 0x3a, 0x36, 0x4d, 0x25, 0x78, 0x3d, 0x9e, 0xcb, 0x65, 0x27, 0x3d, 0x47, 0x7, 0xea, 0x9, 0x25, 0x5a, 0x8d, 0xac, 0xcc, 0x4a, 0x1b, 0x6e, 0xff, 0xae, 0x10, 0xa3, 0xd8, 0x17, 0x36, 0x7c, 0x7d, 0x9, 0xf7, 0xbf, 0xb9, 0xc8, 0x77, 0x3f, 0x29, 0xde, 0x84, 0x9a, 0x8d, 0x3d, 0xa8, 0xc4, 0x53, 0x2, 0x31, 0x0, 0x90, 0xce, 0x2b, 0x31, 0x1, 0xa7, 0xb6, 0x3a, 0x50, 0xb7, 0xa7, 0x74, 0x5b, 0x3e, 0xea, 0x1b, 0x19, 0x5b, 0xca, 0x23, 0xa1, 0x18, 0x99, 0xf9, 0xe8, 0x85, 0xdb, 0xc3, 0xe4, 0xe8, 0x19, 0x3d, 0x1b, 0x24, 0x36, 0x11, 0x80, 0x89, 0x1d, 0x9e, 0xdc, 0xc0, 0xd0, 0xba, 0xe7, 0xb1, 0x6c, 0xc}, } ) func assertCertsEqual(t *testing.T, wanted, got []*x509.Certificate) { t.Helper() if len(wanted) != len(got) { t.Errorf("got %d certs, wanted %d", len(got), len(wanted)) } for i, cert := range wanted { if d := cmp.Diff(cert, got[i]); d != "" { t.Errorf("wanted[%d] != got[%d] (-want +got): %s", i, i, d) } } } func TestCertificatesFromPEM(t *testing.T) { testCases := []struct { name string pemBytes []byte expected []*x509.Certificate expectErr bool }{ { name: "one cert", pemBytes: []byte(cert1PEM), expected: []*x509.Certificate{cert1}, }, { name: "one cert with trailing newline", pemBytes: append([]byte(cert1PEM), '\n'), expected: []*x509.Certificate{cert1}, }, { name: "two certs", pemBytes: []byte(cert1PEM + cert2PEM), expected: []*x509.Certificate{cert1, cert2}, }, { name: "two certs with newline between and after certificates", pemBytes: []byte(cert1PEM + "\n" + cert2PEM + "\n"), expected: []*x509.Certificate{cert1, cert2}, }, { name: "one cert and one unknown PEM", pemBytes: []byte(cert1PEM + somethingElsePEM), expectErr: true, }, { name: "unknown PEM", pemBytes: []byte(somethingElsePEM), expectErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Run("Unmarshal", func(t *testing.T) { got, err := UnmarshalCertificatesFromPEM(tc.pemBytes) if err != nil { if !tc.expectErr { t.Fatalf("UnmarshalCertificatesFromPEM() returned unexpected error: %v", err) } } else if tc.expectErr { t.Fatalf("UnmarshalCertificatesFromPEM() should have returned an error, got: %v", got) } assertCertsEqual(t, tc.expected, got) }) t.Run("UnmarshalLimited", func(t *testing.T) { got, err := UnmarshalCertificatesFromPEMLimited(tc.pemBytes, 10 /*iterations*/) if err != nil { if !tc.expectErr { t.Fatalf("UnmarshalCertificatesFromPEM() returned unexpected error: %v", err) } } else if tc.expectErr { t.Fatalf("UnmarshalCertificatesFromPEM() should have returned an error, got: %v", got) } assertCertsEqual(t, tc.expected, got) }) t.Run("Load", func(t *testing.T) { got, err := LoadCertificatesFromPEM(bytes.NewReader(tc.pemBytes)) if err != nil { if !tc.expectErr { t.Fatalf("LoadCertificatesFromPEM() returned unexpected error: %v", err) } } else if tc.expectErr { t.Fatalf("LoadCertificatesFromPEM() should have returned an error, got: %v", got) } assertCertsEqual(t, tc.expected, got) }) }) } } func TestUnmarshalCertificatesFromPEMLimited(t *testing.T) { var pemCerts []byte iterations := 10 for i := 0; i < iterations; i++ { pemCerts = append(pemCerts, []byte(cert1PEM)...) } certs, err := UnmarshalCertificatesFromPEMLimited(pemCerts, iterations) if err != nil { t.Fatalf("expected no error, got %v", err) } if len(certs) != iterations { t.Fatalf("unexpected number of certificates, expected %d, got %d", iterations, len(certs)) } // append one more certificate to cause a failure pemCerts = append(pemCerts, []byte(cert1PEM)...) _, err = UnmarshalCertificatesFromPEMLimited(pemCerts, iterations) if err == nil || err.Error() != "too many certificates specified in PEM block" { t.Fatalf("expected error with too many certificates, got %v", err) } } func TestMarshalCertificateToPEM(t *testing.T) { testCases := []struct { name string cert *x509.Certificate expected []byte expectErr bool }{ { name: "cert1", cert: cert1, expected: []byte(cert1PEM), }, { name: "cert2", cert: cert2, expected: []byte(cert2PEM), }, { name: "nil", cert: nil, expectErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { got, err := MarshalCertificateToPEM(tc.cert) if err != nil { if !tc.expectErr { t.Fatalf("MarshalCertificateToPEM() returned unexpected error: %v", err) } } else if tc.expectErr { t.Fatalf("MarshalCertificateToPEM() should have returned an error, got: %v", got) } if d := cmp.Diff(tc.expected, got); d != "" { t.Errorf("MarshalCertificateToPEM() returned unexpected PEM (-want +got): %s", d) } }) } } func TestMarshalCertificatesToPEM(t *testing.T) { testCases := []struct { name string certs []*x509.Certificate expected []byte expectErr bool }{ { name: "one cert", certs: []*x509.Certificate{cert1}, expected: []byte(cert1PEM), }, { name: "two certs", certs: []*x509.Certificate{cert1, cert2}, expected: []byte(cert1PEM + cert2PEM), }, { name: "nil cert", certs: []*x509.Certificate{cert1, nil}, expectErr: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { got, err := MarshalCertificatesToPEM(tc.certs) if err != nil { if !tc.expectErr { t.Fatalf("MarshalCertificatesToPEM() returned unexpected error: %v", err) } } else if tc.expectErr { t.Fatalf("MarshalCertificatesToPEM() should have returned an error, got: %v", got) } if d := cmp.Diff(tc.expected, got); d != "" { t.Errorf("MarshalCertificatesToPEM() returned unexpected PEM (-want +got): %s", d) } }) } } func errorsEqual(a, b error) bool { if errors.Is(a, b) { // both are nil return true } return a != nil && b != nil && a.Error() == b.Error() } func TestCheckExpiration(t *testing.T) { testCases := []struct { name string cert *x509.Certificate epoch time.Time expected error }{ { name: "valid", cert: &x509.Certificate{ NotAfter: time.Unix(4444, 0), NotBefore: time.Unix(2222, 0), }, epoch: time.Unix(3333, 0), expected: nil, }, { name: "expired", cert: &x509.Certificate{ NotAfter: time.Unix(4444, 0), NotBefore: time.Unix(2222, 0), }, epoch: time.Unix(5555, 0), expected: errors.New("certificate expiration time 1970-01-01T01:14:04Z is before 1970-01-01T01:32:35Z"), }, { name: "not valid yet", cert: &x509.Certificate{ NotAfter: time.Unix(4444, 0), NotBefore: time.Unix(2222, 0), }, epoch: time.Unix(1111, 0), expected: errors.New("certificate issued time 1970-01-01T00:37:02Z is before 1970-01-01T00:18:31Z"), }, { name: "nil", cert: nil, expected: errors.New("certificate is nil"), }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { if err := CheckExpiration(tc.cert, tc.epoch); !errorsEqual(err, tc.expected) { t.Errorf("CheckExpiration() should have returned: %v, got: %v", tc.expected, err) } }) } } func TestParseCSR(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } csrTmpl := &x509.CertificateRequest{Subject: pkix.Name{CommonName: "test"}} derCSR, err := x509.CreateCertificateRequest(rand.Reader, csrTmpl, priv) if err != nil { t.Fatal(err) } // success with type CERTIFICATE REQUEST pemCSR := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: derCSR, }) parsedCSR, err := ParseCSR(pemCSR) if err != nil { t.Fatal(err) } if parsedCSR.Subject.CommonName != "test" { t.Fatalf("unexpected CSR common name") } // success with type NEW CERTIFICATE REQUEST pemCSR = pem.EncodeToMemory(&pem.Block{ Type: "NEW CERTIFICATE REQUEST", Bytes: derCSR, }) parsedCSR, err = ParseCSR(pemCSR) if err != nil { t.Fatal(err) } if parsedCSR.Subject.CommonName != "test" { t.Fatalf("unexpected CSR common name") } // fails with invalid PEM encoded block _, err = ParseCSR([]byte{1, 2, 3}) if err == nil || !strings.Contains(err.Error(), "no CSR found while decoding") { t.Fatalf("expected error parsing invalid CSR, got %v", err) } // fails with invalid DER type pemCSR = pem.EncodeToMemory(&pem.Block{ Type: "BEGIN CERTIFICATE", Bytes: derCSR, }) _, err = ParseCSR(pemCSR) if err == nil || !strings.Contains(err.Error(), "DER type BEGIN CERTIFICATE is not of any type") { t.Fatalf("expected error parsing invalid CSR, got %v", err) } } func TestGenerateSerialNumber(t *testing.T) { serialNumber, err := GenerateSerialNumber() if err != nil { t.Fatalf("unexpected error generating serial number: %v", err) } if serialNumber.Cmp(big.NewInt(0)) == -1 { t.Fatalf("serial number is negative: %v", serialNumber) } if serialNumber.Cmp(big.NewInt(0)) == 0 { t.Fatalf("serial number is 0: %v", serialNumber) } maxSerial := (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil) // Serial number must be less than max serial number. if serialNumber.Cmp(maxSerial) >= 0 { t.Fatalf("serial number is too large: %v", serialNumber) } } sigstore-1.8.6/pkg/cryptoutils/doc.go000066400000000000000000000013051463713551000176470ustar00rootroot00000000000000// // 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 cryptoutils contains utilities related to handling cryptographic materials. package cryptoutils sigstore-1.8.6/pkg/cryptoutils/generic.go000066400000000000000000000017421463713551000205230ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "encoding/pem" ) // PEMType is a specific type for string constants used during PEM encoding and decoding type PEMType string // PEMEncode encodes the specified byte slice in PEM format using the provided type string func PEMEncode(typeStr PEMType, bytes []byte) []byte { return pem.EncodeToMemory(&pem.Block{ Type: string(typeStr), Bytes: bytes, }) } sigstore-1.8.6/pkg/cryptoutils/generic_test.go000066400000000000000000000020721463713551000215570ustar00rootroot00000000000000// Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "testing" "github.com/google/go-cmp/cmp" ) func TestPEMEncode(t *testing.T) { const testPemType PEMType = "ARBITRARY PEM TYPE" expected := []byte(`-----BEGIN ARBITRARY PEM TYPE----- AAECAwQ= -----END ARBITRARY PEM TYPE----- `) b := []byte{0x00, 0x01, 0x02, 0x03, 0x04} pemBytes := PEMEncode(testPemType, b) if d := cmp.Diff(expected, pemBytes); d != "" { t.Errorf("MarshalCertificateToPEM() returned unexpected PEM (-want +got): %s", d) } } sigstore-1.8.6/pkg/cryptoutils/password.go000066400000000000000000000047021463713551000207500ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "errors" "fmt" "io" "os" "golang.org/x/term" ) // PassFunc is a type of function that takes a boolean (representing whether confirmation is desired) and returns the password as read, along with an error if one occurred type PassFunc func(bool) ([]byte, error) // Read is for fuzzing var Read = readPasswordFn // readPasswordFn reads the password from the following sources, in order of preference: // // - COSIGN_PASSWORD environment variable // // - user input from from terminal (if present) // // - provided to stdin from pipe func readPasswordFn() func() ([]byte, error) { if pw, ok := os.LookupEnv("COSIGN_PASSWORD"); ok { return func() ([]byte, error) { return []byte(pw), nil } } if term.IsTerminal(0) { return func() ([]byte, error) { return term.ReadPassword(0) } } // Handle piped in passwords. return func() ([]byte, error) { return io.ReadAll(os.Stdin) } } // StaticPasswordFunc returns a PassFunc which returns the provided password. func StaticPasswordFunc(pw []byte) PassFunc { return func(bool) ([]byte, error) { return pw, nil } } // SkipPassword is a PassFunc that does not interact with a user, but // simply returns nil for both the password result and error struct. func SkipPassword(_ bool) ([]byte, error) { return nil, nil } // GetPasswordFromStdIn gathers the password from stdin with an // optional confirmation step. func GetPasswordFromStdIn(confirm bool) ([]byte, error) { read := Read() fmt.Fprint(os.Stderr, "Enter password for private key: ") pw1, err := read() fmt.Fprintln(os.Stderr) if err != nil { return nil, err } if !confirm { return pw1, nil } fmt.Fprint(os.Stderr, "Enter again: ") pw2, err := read() fmt.Fprintln(os.Stderr) if err != nil { return nil, err } if string(pw1) != string(pw2) { return nil, errors.New("passwords do not match") } return pw1, nil } sigstore-1.8.6/pkg/cryptoutils/privatekey.go000066400000000000000000000120351463713551000212670ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "fmt" "github.com/secure-systems-lab/go-securesystemslib/encrypted" ) const ( // PrivateKeyPEMType is the string "PRIVATE KEY" to be used during PEM encoding and decoding PrivateKeyPEMType PEMType = "PRIVATE KEY" // ECPrivateKeyPEMType is the string "EC PRIVATE KEY" used to parse SEC 1 EC private keys ECPrivateKeyPEMType PEMType = "EC PRIVATE KEY" // PKCS1PrivateKeyPEMType is the string "RSA PRIVATE KEY" used to parse PKCS#1-encoded private keys PKCS1PrivateKeyPEMType PEMType = "RSA PRIVATE KEY" encryptedCosignPrivateKeyPEMType PEMType = "ENCRYPTED COSIGN PRIVATE KEY" // EncryptedSigstorePrivateKeyPEMType is the string "ENCRYPTED SIGSTORE PRIVATE KEY" to be used during PEM encoding and decoding EncryptedSigstorePrivateKeyPEMType PEMType = "ENCRYPTED SIGSTORE PRIVATE KEY" ) func pemEncodeKeyPair(priv crypto.PrivateKey, pub crypto.PublicKey, pf PassFunc) (privPEM, pubPEM []byte, err error) { pubPEM, err = MarshalPublicKeyToPEM(pub) if err != nil { return nil, nil, err } derBytes, err := MarshalPrivateKeyToDER(priv) if err != nil { return nil, nil, err } if pf == nil { return PEMEncode(PrivateKeyPEMType, derBytes), pubPEM, nil } password, err := pf(true) if err != nil { return nil, nil, err } if password == nil { return PEMEncode(PrivateKeyPEMType, derBytes), pubPEM, nil } if derBytes, err = encrypted.Encrypt(derBytes, password); err != nil { return nil, nil, err } return PEMEncode(EncryptedSigstorePrivateKeyPEMType, derBytes), pubPEM, nil } // GeneratePEMEncodedECDSAKeyPair generates an ECDSA keypair, optionally password encrypted using a provided PassFunc, and PEM encoded. func GeneratePEMEncodedECDSAKeyPair(curve elliptic.Curve, pf PassFunc) (privPEM, pubPEM []byte, err error) { priv, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return nil, nil, err } return pemEncodeKeyPair(priv, priv.Public(), pf) } // GeneratePEMEncodedRSAKeyPair generates an RSA keypair, optionally password encrypted using a provided PassFunc, and PEM encoded. func GeneratePEMEncodedRSAKeyPair(keyLengthBits int, pf PassFunc) (privPEM, pubPEM []byte, err error) { priv, err := rsa.GenerateKey(rand.Reader, keyLengthBits) if err != nil { return nil, nil, err } return pemEncodeKeyPair(priv, priv.Public(), pf) } // MarshalPrivateKeyToEncryptedDER marshals the private key and encrypts the DER-encoded value using the specified password function func MarshalPrivateKeyToEncryptedDER(priv crypto.PrivateKey, pf PassFunc) ([]byte, error) { derKey, err := MarshalPrivateKeyToDER(priv) if err != nil { return nil, err } password, err := pf(true) if err != nil { return nil, err } if password == nil { return nil, errors.New("password was nil") } return encrypted.Encrypt(derKey, password) } // UnmarshalPEMToPrivateKey converts a PEM-encoded byte slice into a crypto.PrivateKey func UnmarshalPEMToPrivateKey(pemBytes []byte, pf PassFunc) (crypto.PrivateKey, error) { derBlock, _ := pem.Decode(pemBytes) if derBlock == nil { return nil, errors.New("PEM decoding failed") } switch derBlock.Type { case string(PrivateKeyPEMType): return x509.ParsePKCS8PrivateKey(derBlock.Bytes) case string(PKCS1PrivateKeyPEMType): return x509.ParsePKCS1PrivateKey(derBlock.Bytes) case string(ECPrivateKeyPEMType): return x509.ParseECPrivateKey(derBlock.Bytes) case string(EncryptedSigstorePrivateKeyPEMType), string(encryptedCosignPrivateKeyPEMType): derBytes := derBlock.Bytes if pf != nil { password, err := pf(false) if err != nil { return nil, err } if password != nil { derBytes, err = encrypted.Decrypt(derBytes, password) if err != nil { return nil, err } } } return x509.ParsePKCS8PrivateKey(derBytes) } return nil, fmt.Errorf("unknown private key PEM file type: %v", derBlock.Type) } // MarshalPrivateKeyToDER converts a crypto.PrivateKey into a PKCS8 ASN.1 DER byte slice func MarshalPrivateKeyToDER(priv crypto.PrivateKey) ([]byte, error) { if priv == nil { return nil, errors.New("empty key") } return x509.MarshalPKCS8PrivateKey(priv) } // MarshalPrivateKeyToPEM converts a crypto.PrivateKey into a PKCS#8 PEM-encoded byte slice func MarshalPrivateKeyToPEM(priv crypto.PrivateKey) ([]byte, error) { derBytes, err := MarshalPrivateKeyToDER(priv) if err != nil { return nil, err } return PEMEncode(PrivateKeyPEMType, derBytes), nil } sigstore-1.8.6/pkg/cryptoutils/privatekey_test.go000066400000000000000000000223441463713551000223320ustar00rootroot00000000000000// Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "strings" "testing" "github.com/google/go-cmp/cmp" ) func verifyRSAKeyPEMs(t *testing.T, privPEM, pubPEM []byte, expectedKeyLengthBits int, testPassFunc PassFunc) { t.Helper() if priv, err := UnmarshalPEMToPrivateKey(privPEM, testPassFunc); err != nil { t.Errorf("UnmarshalPEMToPrivateKey returned error: %v", err) } else if rsaPriv, ok := priv.(*rsa.PrivateKey); !ok { t.Errorf("expected unmarshaled key to be of type *rsa.PrivateKey, was %T", priv) } else if rsaPriv.Size() != expectedKeyLengthBits/8 { t.Errorf("private key size was %d, expected %d", rsaPriv.Size(), expectedKeyLengthBits/8) } if pub, err := UnmarshalPEMToPublicKey(pubPEM); err != nil { t.Errorf("UnmarshalPEMToPublicKey returned error: %v", err) } else if rsaPub, ok := pub.(*rsa.PublicKey); !ok { t.Errorf("expected unmarshaled public key to be of type *rsa.PublicKey, was %T", pub) } else if rsaPub.Size() != expectedKeyLengthBits/8 { t.Errorf("public key size was %d, expected %d", rsaPub.Size(), expectedKeyLengthBits/8) } } func TestGeneratePEMEncodedRSAKeyPair(t *testing.T) { t.Parallel() const testKeyBits = 2048 testCases := []struct { name string initialPassFunc PassFunc goodPFs []PassFunc badPFs []PassFunc }{ { name: "encrypted", initialPassFunc: StaticPasswordFunc([]byte("TestGenerateEncryptedRSAKeyPair password")), badPFs: []PassFunc{SkipPassword, nil}, }, { name: "nil pass func", initialPassFunc: nil, goodPFs: []PassFunc{SkipPassword, nil}, }, { name: "SkipPassword func", initialPassFunc: SkipPassword, goodPFs: []PassFunc{SkipPassword, nil}, }, } for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() privPEM, pubPEM, err := GeneratePEMEncodedRSAKeyPair(testKeyBits, tc.initialPassFunc) if err != nil { t.Fatalf("GeneratePEMEncodedRSAKeyPair returned error: %v", err) } for _, badPF := range tc.badPFs { if priv, err := UnmarshalPEMToPrivateKey(privPEM, SkipPassword); err == nil { t.Errorf("UnmarshalPEMToPrivateKey(pf=%v) should have returned error, got: %v", badPF, priv) } } for _, goodPF := range tc.goodPFs { if _, err := UnmarshalPEMToPrivateKey(privPEM, goodPF); err != nil { t.Errorf("UnmarshalPEMToPrivateKey(pf=%v) returned error: %v", goodPF, err) } } verifyRSAKeyPEMs(t, privPEM, pubPEM, testKeyBits, tc.initialPassFunc) }) } } func verifyECDSAKeyPEMs(t *testing.T, privPEM, pubPEM []byte, expectedCurve elliptic.Curve, testPassFunc PassFunc) { t.Helper() if priv, err := UnmarshalPEMToPrivateKey(privPEM, testPassFunc); err != nil { t.Errorf("UnmarshalPEMToPrivateKey returned error: %v", err) } else if ecdsaPriv, ok := priv.(*ecdsa.PrivateKey); !ok { t.Errorf("expected unmarshaled key to be of type *ecdsa.PrivateKey, was %T", priv) } else if ecdsaPriv.Curve != expectedCurve { t.Errorf("expected elliptic curve %v, got %d", expectedCurve, ecdsaPriv.Curve) } if pub, err := UnmarshalPEMToPublicKey(pubPEM); err != nil { t.Errorf("UnmarshalPEMToPublicKey returned error: %v", err) } else if ecdsaPub, ok := pub.(*ecdsa.PublicKey); !ok { t.Errorf("expected unmarshaled key to be of type *ecdsa.PublicKey, was %T", pub) } else if ecdsaPub.Curve != expectedCurve { t.Errorf("expected elliptic curve %v, got %d", expectedCurve, ecdsaPub.Curve) } } func TestGeneratePEMEncodedECDSAKeyPair(t *testing.T) { t.Parallel() testCurve := elliptic.P256() testCases := []struct { name string initialPassFunc PassFunc goodPFs []PassFunc badPFs []PassFunc }{ { name: "encrypted", initialPassFunc: StaticPasswordFunc([]byte("TestGenerateEncryptedRSAKeyPair password")), badPFs: []PassFunc{SkipPassword, nil}, }, { name: "nil pass func", initialPassFunc: nil, goodPFs: []PassFunc{SkipPassword, nil}, }, { name: "SkipPassword func", initialPassFunc: SkipPassword, goodPFs: []PassFunc{SkipPassword, nil}, }, } for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() privPEM, pubPEM, err := GeneratePEMEncodedECDSAKeyPair(testCurve, tc.initialPassFunc) if err != nil { t.Fatalf("GeneratePEMEncodedRSAKeyPair returned error: %v", err) } for _, badPF := range tc.badPFs { if priv, err := UnmarshalPEMToPrivateKey(privPEM, SkipPassword); err == nil { t.Errorf("UnmarshalPEMToPrivateKey(pf=%v) should have returned error, got: %v", badPF, priv) } } for _, goodPF := range tc.goodPFs { if _, err := UnmarshalPEMToPrivateKey(privPEM, goodPF); err != nil { t.Errorf("UnmarshalPEMToPrivateKey(pf=%v) returned error: %v", goodPF, err) } } verifyECDSAKeyPEMs(t, privPEM, pubPEM, testCurve, tc.initialPassFunc) }) } } func verifyPrivateKeyPEMRoundtrip(t *testing.T, pub crypto.PrivateKey) { t.Helper() pemBytes, err := MarshalPrivateKeyToPEM(pub) if err != nil { t.Fatalf("MarshalPrivateKeyToPEM returned error: %v", err) } rtPub, err := UnmarshalPEMToPrivateKey(pemBytes, nil) if err != nil { t.Fatalf("UnmarshalPEMToPrivateKey returned error: %v", err) } if d := cmp.Diff(pub, rtPub); d != "" { t.Errorf("round-tripped public key was malformed (-before +after): %s", d) } } func TestECDSAPrivateKeyPEMRoundtrip(t *testing.T) { t.Parallel() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } verifyPrivateKeyPEMRoundtrip(t, priv) } func TestEd25519PrivateKeyPEMRoundtrip(t *testing.T) { t.Parallel() _, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey failed: %v", err) } verifyPrivateKeyPEMRoundtrip(t, priv) } func TestRSAPrivateKeyPEMRoundtrip(t *testing.T) { t.Parallel() priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } verifyPrivateKeyPEMRoundtrip(t, priv) } func TestUnmarshalPEMToPrivateKey(t *testing.T) { // test PKCS#8 PEM-encoded private keys priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } pkcs8PrivateKey, err := x509.MarshalPKCS8PrivateKey(priv) if err != nil { t.Fatalf("x509.MarshalPKCS8PrivateKey failed: %v", err) } pkcs8PEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "PRIVATE KEY", Bytes: pkcs8PrivateKey, }) k, err := UnmarshalPEMToPrivateKey(pkcs8PEMBlock, nil) if err != nil { t.Fatalf("UnmarshalPEMToPrivateKey for PKCS#8 failed: %v", err) } if !priv.Equal(k) { t.Fatalf("private keys for PKCS#8 are not equal") } // test PKCS#1 PEM-encoded RSA private keys priv, err = rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } rsaPrivKey := x509.MarshalPKCS1PrivateKey(priv) pkcs1PEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "RSA PRIVATE KEY", Bytes: rsaPrivKey, }) k, err = UnmarshalPEMToPrivateKey(pkcs1PEMBlock, nil) if err != nil { t.Fatalf("UnmarshalPEMToPrivateKey for PKCS#1 failed: %v", err) } if !priv.Equal(k) { t.Fatalf("private keys for PKCS1 are not equal") } // test SEC 1 EC private keys ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } ecPrivKey, err := x509.MarshalECPrivateKey(ecdsaKey) if err != nil { t.Fatalf("x509.MarshalECPrivateKey failed: %v", err) } ecPEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "EC PRIVATE KEY", Bytes: ecPrivKey, }) k, err = UnmarshalPEMToPrivateKey(ecPEMBlock, nil) if err != nil { t.Fatalf("UnmarshalPEMToPrivateKey for SEC 1 failed: %v", err) } if !ecdsaKey.Equal(k) { t.Fatalf("private keys for SEC 1 (EC) are not equal") } // test Sigstore formatted private keys privSigstorePEM, _, err := GeneratePEMEncodedECDSAKeyPair(elliptic.P256(), StaticPasswordFunc([]byte("pw"))) if err != nil { t.Fatalf("GeneratePEMEncodedECDSAKeyPair failed: %v", err) } _, err = UnmarshalPEMToPrivateKey(privSigstorePEM, StaticPasswordFunc([]byte("pw"))) if err != nil { t.Fatalf("UnmarshalPEMToPrivateKey for Sigstore encoded key failed: %v", err) } // test other PEM formats return an error invalidPEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: rsaPrivKey, }) _, err = UnmarshalPEMToPrivateKey(invalidPEMBlock, nil) if err == nil || !strings.Contains(err.Error(), "unknown private key PEM file type") { t.Fatalf("expected error unmarshalling invalid PEM block, got: %v", err) } } sigstore-1.8.6/pkg/cryptoutils/publickey.go000066400000000000000000000133551463713551000211010ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "context" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/sha1" // nolint:gosec "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/hex" "encoding/pem" "errors" "fmt" "github.com/letsencrypt/boulder/goodkey" ) const ( // PublicKeyPEMType is the string "PUBLIC KEY" to be used during PEM encoding and decoding PublicKeyPEMType PEMType = "PUBLIC KEY" // PKCS1PublicKeyPEMType is the string "RSA PUBLIC KEY" used to parse PKCS#1-encoded public keys PKCS1PublicKeyPEMType PEMType = "RSA PUBLIC KEY" ) // subjectPublicKeyInfo is used to construct a subject key ID. // https://tools.ietf.org/html/rfc5280#section-4.1.2.7 type subjectPublicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier SubjectPublicKey asn1.BitString } // UnmarshalPEMToPublicKey converts a PEM-encoded byte slice into a crypto.PublicKey func UnmarshalPEMToPublicKey(pemBytes []byte) (crypto.PublicKey, error) { derBytes, _ := pem.Decode(pemBytes) if derBytes == nil { return nil, errors.New("PEM decoding failed") } switch derBytes.Type { case string(PublicKeyPEMType): return x509.ParsePKIXPublicKey(derBytes.Bytes) case string(PKCS1PublicKeyPEMType): return x509.ParsePKCS1PublicKey(derBytes.Bytes) default: return nil, fmt.Errorf("unknown Public key PEM file type: %v. Are you passing the correct public key?", derBytes.Type) } } // MarshalPublicKeyToDER converts a crypto.PublicKey into a PKIX, ASN.1 DER byte slice func MarshalPublicKeyToDER(pub crypto.PublicKey) ([]byte, error) { if pub == nil { return nil, errors.New("empty key") } return x509.MarshalPKIXPublicKey(pub) } // MarshalPublicKeyToPEM converts a crypto.PublicKey into a PEM-encoded byte slice func MarshalPublicKeyToPEM(pub crypto.PublicKey) ([]byte, error) { derBytes, err := MarshalPublicKeyToDER(pub) if err != nil { return nil, err } return PEMEncode(PublicKeyPEMType, derBytes), nil } // SKID generates a 160-bit SHA-1 hash of the value of the BIT STRING // subjectPublicKey (excluding the tag, length, and number of unused bits). // https://tools.ietf.org/html/rfc5280#section-4.2.1.2 func SKID(pub crypto.PublicKey) ([]byte, error) { derPubBytes, err := x509.MarshalPKIXPublicKey(pub) if err != nil { return nil, err } var spki subjectPublicKeyInfo if _, err := asn1.Unmarshal(derPubBytes, &spki); err != nil { return nil, err } skid := sha1.Sum(spki.SubjectPublicKey.Bytes) // nolint:gosec return skid[:], nil } // EqualKeys compares two public keys. Supports RSA, ECDSA and ED25519. // If not equal, the error message contains hex-encoded SHA1 hashes of the DER-encoded keys func EqualKeys(first, second crypto.PublicKey) error { switch pub := first.(type) { case *rsa.PublicKey: if !pub.Equal(second) { return fmt.Errorf(genErrMsg(first, second, "rsa")) } case *ecdsa.PublicKey: if !pub.Equal(second) { return fmt.Errorf(genErrMsg(first, second, "ecdsa")) } case ed25519.PublicKey: if !pub.Equal(second) { return fmt.Errorf(genErrMsg(first, second, "ed25519")) } default: return errors.New("unsupported key type") } return nil } // genErrMsg generates an error message for EqualKeys func genErrMsg(first, second crypto.PublicKey, keyType string) string { msg := fmt.Sprintf("%s public keys are not equal", keyType) // Calculate SKID to include in error message firstSKID, err := SKID(first) if err != nil { return msg } secondSKID, err := SKID(second) if err != nil { return msg } return fmt.Sprintf("%s (%s, %s)", msg, hex.EncodeToString(firstSKID), hex.EncodeToString(secondSKID)) } // ValidatePubKey validates the parameters of an RSA, ECDSA, or ED25519 public key. func ValidatePubKey(pub crypto.PublicKey) error { // goodkey policy enforces: // * RSA // * Size of key: 2048 <= size <= 4096, size % 8 = 0 // * Exponent E = 65537 (Default exponent for OpenSSL and Golang) // * Small primes check for modulus // * Weak keys generated by Infineon hardware (see https://crocs.fi.muni.cz/public/papers/rsa_ccs17) // * Key is easily factored with Fermat's factorization method // * EC // * Public key Q is not the identity element (Ø) // * Public key Q's x and y are within [0, p-1] // * Public key Q is on the curve // * Public key Q's order matches the subgroups (nQ = Ø) allowedKeys := &goodkey.AllowedKeys{ RSA2048: true, RSA3072: true, RSA4096: true, ECDSAP256: true, ECDSAP384: true, ECDSAP521: true, } cfg := &goodkey.Config{ FermatRounds: 100, AllowedKeys: allowedKeys, } p, err := goodkey.NewPolicy(cfg, nil) if err != nil { // Should not occur, only chances to return errors are if fermat rounds // are <0 or when loading blocked/weak keys from disk (not used here) return errors.New("unable to initialize key policy") } switch pk := pub.(type) { case *rsa.PublicKey: // ctx is unused return p.GoodKey(context.Background(), pub) case *ecdsa.PublicKey: // ctx is unused return p.GoodKey(context.Background(), pub) case ed25519.PublicKey: return validateEd25519Key(pk) } return errors.New("unsupported public key type") } // No validations currently, ED25519 supports only one key size. func validateEd25519Key(_ ed25519.PublicKey) error { return nil } sigstore-1.8.6/pkg/cryptoutils/publickey_test.go000066400000000000000000000236671463713551000221470ustar00rootroot00000000000000// Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cryptoutils import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/letsencrypt/boulder/goodkey" ) func verifyPublicKeyPEMRoundtrip(t *testing.T, pub crypto.PublicKey) { t.Helper() pemBytes, err := MarshalPublicKeyToPEM(pub) if err != nil { t.Fatalf("MarshalPublicKeyToPEM returned error: %v", err) } rtPub, err := UnmarshalPEMToPublicKey(pemBytes) if err != nil { t.Fatalf("UnmarshalPEMToPublicKey returned error: %v", err) } if d := cmp.Diff(pub, rtPub); d != "" { t.Errorf("round-tripped public key was malformed (-before +after): %s", d) } } func TestECDSAPublicKeyPEMRoundtrip(t *testing.T) { t.Parallel() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } verifyPublicKeyPEMRoundtrip(t, priv.Public()) } func TestEd25519PublicKeyPEMRoundtrip(t *testing.T) { t.Parallel() pub, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey failed: %v", err) } verifyPublicKeyPEMRoundtrip(t, pub) } func TestRSAPublicKeyPEMRoundtrip(t *testing.T) { t.Parallel() priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } verifyPublicKeyPEMRoundtrip(t, priv.Public()) } func TestSKIDRSA(t *testing.T) { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } skid, err := SKID(priv.Public()) if err != nil { t.Fatalf("SKID failed: %v", err) } // Expect SKID is 160 bits (20 bytes) if len(skid) != 20 { t.Fatalf("SKID failed: %v", skid) } } func TestSKIDECDSA(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } skid, err := SKID(priv.Public()) if err != nil { t.Fatalf("SKID failed: %v", err) } // Expect SKID is 160 bits (20 bytes) if len(skid) != 20 { t.Fatalf("SKID failed: %v", skid) } } func TestSKIDED25519(t *testing.T) { pub, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey failed: %v", err) } skid, err := SKID(pub) if err != nil { t.Fatalf("SKID failed: %v", err) } // Expect SKID is 160 bits (20 bytes) if len(skid) != 20 { t.Fatalf("SKID failed: %v", skid) } } func TestEqualKeys(t *testing.T) { // Test RSA (success and failure) privRsa, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } privRsa2, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } if err := EqualKeys(privRsa.Public(), privRsa.Public()); err != nil { t.Fatalf("unexpected error for rsa equality, got %v", err) } if err := EqualKeys(privRsa.Public(), privRsa2.Public()); err == nil || !strings.Contains(err.Error(), "rsa public keys are not equal") { t.Fatalf("expected error for different rsa keys, got %v", err) } // Test ECDSA (success and failure) privEcdsa, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } privEcdsa2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } if err := EqualKeys(privEcdsa.Public(), privEcdsa.Public()); err != nil { t.Fatalf("unexpected error for ecdsa equality, got %v", err) } if err := EqualKeys(privEcdsa.Public(), privEcdsa2.Public()); err == nil || !strings.Contains(err.Error(), "ecdsa public keys are not equal") { t.Fatalf("expected error for different ecdsa keys, got %v", err) } // Test ED25519 (success and failure) pubEd, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey failed: %v", err) } pubEd2, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey failed: %v", err) } if err := EqualKeys(pubEd, pubEd); err != nil { t.Fatalf("unexpected error for ed25519 equality, got %v", err) } if err := EqualKeys(pubEd, pubEd2); err == nil || !strings.Contains(err.Error(), "ed25519 public keys are not equal") { t.Fatalf("expected error for different ed25519 keys, got %v", err) } // Keys of different type are not equal if err := EqualKeys(privRsa.Public(), pubEd); err == nil || !strings.Contains(err.Error(), "are not equal") { t.Fatalf("expected error for different key types, got %v", err) } // Fails with unexpected key type type PublicKey struct{} if err := EqualKeys(PublicKey{}, PublicKey{}); err == nil || err.Error() != "unsupported key type" { t.Fatalf("expected error for unsupported key type, got %v", err) } } func TestValidatePubKeyUnsupported(t *testing.T) { // Fails with unexpected key type type PublicKey struct{} err := ValidatePubKey(PublicKey{}) if err == nil || err.Error() != "unsupported public key type" { t.Errorf("expected unsupported public key type, got %v", err) } } func TestValidatePubKeyRsa(t *testing.T) { // Validate common RSA key sizes for _, bits := range []int{2048, 3072, 4096} { priv, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } if err := ValidatePubKey(priv.Public()); err != nil { t.Errorf("unexpected error validating public key: %v", err) } } // Fails with small key size priv, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } if err := ValidatePubKey(priv.Public()); err == nil || err.Error() != "key size not supported: 1024" { t.Errorf("expected rsa key size not supported, got %v", err) } // Fails with large key size priv, err = rsa.GenerateKey(rand.Reader, 5000) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } if err := ValidatePubKey(priv.Public()); err == nil || err.Error() != "key size not supported: 5000" { t.Errorf("expected rsa key size not supported, got %v", err) } // Fails with key size that's not a multiple of 8 priv, err = rsa.GenerateKey(rand.Reader, 4095) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } if err := ValidatePubKey(priv.Public()); err == nil || err.Error() != "key size not supported: 4095" { t.Errorf("expected rsa key size not supported, got %v", err) } } type testCurve struct { elliptic.Curve } func (t testCurve) Params() *elliptic.CurveParams { return &elliptic.CurveParams{} } func TestValidatePubKeyEcdsa(t *testing.T) { for _, curve := range []elliptic.Curve{elliptic.P256(), elliptic.P384(), elliptic.P521()} { priv, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } if err := ValidatePubKey(priv.Public()); err != nil { t.Errorf("unexpected error validating public key: %v", err) } // Should fail with negative coordinates priv.X.Neg(priv.X) if err := ValidatePubKey(priv.Public()); err == nil { t.Errorf("expected error when validating public key") } } // Fails with smalller curve priv, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) if err != nil { t.Fatalf("ecdsa.GenerateKey failed: %v", err) } if err := ValidatePubKey(priv.Public()); err == nil || !errors.Is(err, goodkey.ErrBadKey) { t.Errorf("expected unsupported curve, got %v", err) } // Fails with unknown curve err = ValidatePubKey(&ecdsa.PublicKey{ Curve: testCurve{}, }) if err == nil || !errors.Is(err, goodkey.ErrBadKey) { t.Errorf("expected unexpected curve, got %v", err) } } func TestValidatePubKeyEd25519(t *testing.T) { pub, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("ed25519.GenerateKey failed: %v", err) } if err := ValidatePubKey(pub); err != nil { t.Errorf("unexpected error validating public key: %v", err) } // Only success, ED25519 keys do not support customization } func TestUnmarshalPEMToPublicKey(t *testing.T) { // test PKIX PEM-encoded public keys priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } pkixPubKey, err := x509.MarshalPKIXPublicKey(priv.Public()) if err != nil { t.Fatalf("x509.MarshalPKIXPublicKey failed: %v", err) } pkixPEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", Bytes: pkixPubKey, }) k, err := UnmarshalPEMToPublicKey(pkixPEMBlock) if err != nil { t.Fatalf("UnmarshalPEMToPublicKey for PKIX failed: %v", err) } if EqualKeys(priv.Public(), k) != nil { t.Fatalf("public keys for PKIX are not equal") } // test PKCS#1 PEM-encoded RSA public keys priv, err = rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("rsa.GenerateKey failed: %v", err) } rsaPubKey := x509.MarshalPKCS1PublicKey(&priv.PublicKey) pkcs1PEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: rsaPubKey, }) k, err = UnmarshalPEMToPublicKey(pkcs1PEMBlock) if err != nil { t.Fatalf("UnmarshalPEMToPublicKey for PKCS#1 failed: %v", err) } if EqualKeys(priv.Public(), k) != nil { t.Fatalf("public keys for PKCS1 are not equal") } // test other PEM formats return an error invalidPEMBlock := pem.EncodeToMemory(&pem.Block{ Type: "EC PUBLIC KEY", Bytes: rsaPubKey, }) _, err = UnmarshalPEMToPublicKey(invalidPEMBlock) if err == nil || !strings.Contains(err.Error(), "unknown Public key PEM file type") { t.Fatalf("expected error unmarshalling invalid PEM block, got: %v", err) } } sigstore-1.8.6/pkg/cryptoutils/sans.go000066400000000000000000000102271463713551000200510ustar00rootroot00000000000000// 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 cryptoutils import ( "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" ) var ( // OIDOtherName is the OID for the OtherName SAN per RFC 5280 OIDOtherName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 7} // SANOID is the OID for Subject Alternative Name per RFC 5280 SANOID = asn1.ObjectIdentifier{2, 5, 29, 17} ) // OtherName describes a name related to a certificate which is not in one // of the standard name formats. RFC 5280, 4.2.1.6: // // OtherName ::= SEQUENCE { // type-id OBJECT IDENTIFIER, // value [0] EXPLICIT ANY DEFINED BY type-id } // // OtherName for Fulcio-issued certificates only supports UTF-8 strings as values. type OtherName struct { ID asn1.ObjectIdentifier Value string `asn1:"utf8,explicit,tag:0"` } // MarshalOtherNameSAN creates a Subject Alternative Name extension // with an OtherName sequence. RFC 5280, 4.2.1.6: // // SubjectAltName ::= GeneralNames // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // GeneralName ::= CHOICE { // // otherName [0] OtherName, // ... } func MarshalOtherNameSAN(name string, critical bool) (*pkix.Extension, error) { o := OtherName{ ID: OIDOtherName, Value: name, } bytes, err := asn1.MarshalWithParams(o, "tag:0") if err != nil { return nil, err } sans, err := asn1.Marshal([]asn1.RawValue{{FullBytes: bytes}}) if err != nil { return nil, err } return &pkix.Extension{ Id: SANOID, Critical: critical, Value: sans, }, nil } // UnmarshalOtherNameSAN extracts a UTF-8 string from the OtherName // field in the Subject Alternative Name extension. func UnmarshalOtherNameSAN(exts []pkix.Extension) (string, error) { var otherNames []string for _, e := range exts { if !e.Id.Equal(SANOID) { continue } var seq asn1.RawValue rest, err := asn1.Unmarshal(e.Value, &seq) if err != nil { return "", err } else if len(rest) != 0 { return "", fmt.Errorf("trailing data after X.509 extension") } if !seq.IsCompound || seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal { return "", asn1.StructuralError{Msg: "bad SAN sequence"} } rest = seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { return "", err } // skip all GeneralName fields except OtherName if v.Tag != 0 { continue } var other OtherName if _, err := asn1.UnmarshalWithParams(v.FullBytes, &other, "tag:0"); err != nil { return "", fmt.Errorf("could not parse requested OtherName SAN: %w", err) } if !other.ID.Equal(OIDOtherName) { return "", fmt.Errorf("unexpected OID for OtherName, expected %v, got %v", OIDOtherName, other.ID) } otherNames = append(otherNames, other.Value) } } if len(otherNames) == 0 { return "", errors.New("no OtherName found") } if len(otherNames) != 1 { return "", errors.New("expected only one OtherName") } return otherNames[0], nil } // GetSubjectAlternateNames extracts all subject alternative names from // the certificate, including email addresses, DNS, IP addresses, URIs, // and OtherName SANs func GetSubjectAlternateNames(cert *x509.Certificate) []string { sans := []string{} sans = append(sans, cert.DNSNames...) sans = append(sans, cert.EmailAddresses...) for _, ip := range cert.IPAddresses { sans = append(sans, ip.String()) } for _, uri := range cert.URIs { sans = append(sans, uri.String()) } // ignore error if there's no OtherName SAN otherName, _ := UnmarshalOtherNameSAN(cert.Extensions) if len(otherName) > 0 { sans = append(sans, otherName) } return sans } sigstore-1.8.6/pkg/cryptoutils/sans_test.go000066400000000000000000000176431463713551000211210ustar00rootroot00000000000000// 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 cryptoutils import ( "crypto/x509/pkix" "encoding/asn1" "encoding/hex" "net" "net/url" "strings" "testing" "github.com/sigstore/sigstore/test" ) func TestMarshalAndUnmarshalOtherNameSAN(t *testing.T) { otherName := "foo!example.com" critical := true ext, err := MarshalOtherNameSAN(otherName, critical) if err != nil { t.Fatalf("unexpected error for MarshalOtherNameSAN: %v", err) } if ext.Critical != critical { t.Fatalf("expected extension to be critical") } if !ext.Id.Equal(SANOID) { t.Fatalf("expected extension's OID to be SANs OID") } // https://lapo.it/asn1js/#MCGgHwYKKwYBBAGDvzABB6ARDA9mb28hZXhhbXBsZS5jb20 // 30 - Constructed sequence // 21 - length of sequence // A0 - Context-specific (class 2) (bits 8,7) with Constructed bit (bit 6) and 0 tag // 1F - length of context-specific field (OID) // 06 - OID tag // 0A - length of OID // 2B 06 01 04 01 83 BF 30 01 07 - OID // A0 - Context-specific (class 2) with Constructed bit and 0 tag // (needed for EXPLICIT encoding, which wraps field in outer encoding) // 11 - length of context-specific field (string) // 0C - UTF8String tag // 0F - length of string // 66 6F 6F 21 65 78 61 6D 70 6C 65 2E 63 6F 6D - string if hex.EncodeToString(ext.Value) != "3021a01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6d" { t.Fatalf("unexpected ASN.1 encoding") } on, err := UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err != nil { t.Fatalf("unexpected error for UnmarshalOtherNameSAN: %v", err) } if on != otherName { t.Fatalf("unexpected OtherName, expected %s, got %s", otherName, on) } } func TestUnmarshalOtherNameSANFailures(t *testing.T) { var err error // failure: no SANs extension ext := &pkix.Extension{ Id: asn1.ObjectIdentifier{}, Critical: true, Value: []byte{}, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "no OtherName found") { t.Fatalf("expected error finding no OtherName, got %v", err) } // failure: bad sequence ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: []byte{}, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "sequence truncated") { t.Fatalf("expected error with invalid ASN.1, got %v", err) } // failure: extra data after valid sequence b, _ := hex.DecodeString("3021a01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6d" + "30") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "trailing data after X.509 extension") { t.Fatalf("expected error with extra data, got %v", err) } // failure: non-universal class (Change last two bits: 30 = 00110000 => 10110000 -> B0) b, _ = hex.DecodeString("B021a01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "bad SAN sequence") { t.Fatalf("expected error with non-universal class, got %v", err) } // failure: not compound sequence (Change 6th bit: 30 = 00110000 => 00010000 -> 10) b, _ = hex.DecodeString("1021a01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "bad SAN sequence") { t.Fatalf("expected error with non-compound sequence, got %v", err) } // failure: non-sequence tag (Change lower 5 bits: 30 = 00110000 => 00100010 -> 12) b, _ = hex.DecodeString("1221a01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "bad SAN sequence") { t.Fatalf("expected error with non-sequence tag, got %v", err) } // failure: no GeneralName with tag=0 (Change lower 5 bits of first sequence field: 3021a01f -> 3021a11f) b, _ = hex.DecodeString("3021a11f060a2b0601040183bf300108a0110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "no OtherName found") { t.Fatalf("expected error with no GeneralName, got %v", err) } // failure: invalid OtherName (Change tag of UTF8String field to 1: a0110c0f -> a1110c0f) b, _ = hex.DecodeString("3021a01f060a2b0601040183bf300108a1110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "could not parse requested OtherName SAN") { t.Fatalf("expected error with invalid OtherName, got %v", err) } // failure: OtherName has wrong OID (2b0601040183bf300107 -> 2b0601040183bf300108) b, _ = hex.DecodeString("3021a01f060a2b0601040183bf300108a0110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "unexpected OID for OtherName") { t.Fatalf("expected error with wrong OID, got %v", err) } // failure: multiple OtherName fields (Increase sequence size from 0x21 -> 0x42, duplicate OtherName) b, _ = hex.DecodeString("3042a01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6da01f060a2b0601040183bf300107a0110c0f666f6f216578616d706c652e636f6d") ext = &pkix.Extension{ Id: SANOID, Critical: true, Value: b, } _, err = UnmarshalOtherNameSAN([]pkix.Extension{*ext}) if err == nil || !strings.Contains(err.Error(), "expected only one OtherName") { t.Fatalf("expected error with multiple OtherName fields, got %v", err) } } func TestGetSubjectAltnernativeNames(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCa() subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey) // generate with OtherName, which will override other SANs ext, err := MarshalOtherNameSAN("subject-othername", true) if err != nil { t.Fatalf("error marshalling SANs: %v", err) } exts := []pkix.Extension{*ext} leafCert, _, _ := test.GenerateLeafCert("unused", "oidc-issuer", subCert, subKey, exts...) sans := GetSubjectAlternateNames(leafCert) if len(sans) != 1 { t.Fatalf("expected 1 SAN field, got %d", len(sans)) } if sans[0] != "subject-othername" { t.Fatalf("unexpected OtherName SAN value") } // generate with all other SANs leafCert, _, _ = test.GenerateLeafCertWithSubjectAlternateNames([]string{"subject-dns"}, []string{"subject-email"}, []net.IP{{1, 2, 3, 4}}, []*url.URL{{Path: "testURL"}}, "oidc-issuer", subCert, subKey) sans = GetSubjectAlternateNames(leafCert) if len(sans) != 4 { t.Fatalf("expected 1 SAN field, got %d", len(sans)) } if sans[0] != "subject-dns" { t.Fatalf("unexpected DNS SAN value") } if sans[1] != "subject-email" { t.Fatalf("unexpected email SAN value") } if sans[2] != "1.2.3.4" { t.Fatalf("unexpected IP SAN value") } if sans[3] != "testURL" { t.Fatalf("unexpected URL SAN value") } } sigstore-1.8.6/pkg/fulcioroots/000077500000000000000000000000001463713551000165235ustar00rootroot00000000000000sigstore-1.8.6/pkg/fulcioroots/doc.go000066400000000000000000000012771463713551000176260ustar00rootroot00000000000000// // 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 fulcioroots assists with extracting trust root information for Fulcio package fulcioroots sigstore-1.8.6/pkg/fulcioroots/fulcioroots.go000066400000000000000000000072741463713551000214340ustar00rootroot00000000000000// // 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 fulcioroots fetches Fulcio root and intermediate certificates from TUF metadata package fulcioroots import ( "bytes" "context" "crypto/x509" "errors" "fmt" "sync" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/tuf" ) var ( rootsOnce sync.Once roots []*x509.Certificate intermediates []*x509.Certificate singletonRootErr error ) // This is the root in the fulcio project. var fulcioTargetStr = `fulcio.crt.pem` // This is the v1 migrated root. var fulcioV1TargetStr = `fulcio_v1.crt.pem` // This is the untrusted v1 intermediate CA certificate, used or chain building. var fulcioV1IntermediateTargetStr = `fulcio_intermediate_v1.crt.pem` // Get returns the Fulcio root certificate. func Get() (*x509.CertPool, error) { pool := x509.NewCertPool() if err := GetWithCertPool(pool); err != nil { return nil, err } return pool, nil } // GetWithCertPool returns the Fulcio root certificate appended to the given CertPool. func GetWithCertPool(pool *x509.CertPool) error { rootsOnce.Do(func() { roots, intermediates, singletonRootErr = initRoots() if singletonRootErr != nil { return } }) if singletonRootErr != nil { return singletonRootErr } for _, c := range roots { pool.AddCert(c) } return nil } // GetIntermediates returns the Fulcio intermediate certificates. func GetIntermediates() (*x509.CertPool, error) { pool := x509.NewCertPool() if err := GetIntermediatesWithCertPool(pool); err != nil { return nil, err } return pool, nil } // GetIntermediatesWithCertPool returns the Fulcio intermediate certificates appended to the given CertPool. func GetIntermediatesWithCertPool(pool *x509.CertPool) error { rootsOnce.Do(func() { roots, intermediates, singletonRootErr = initRoots() if singletonRootErr != nil { return } }) if singletonRootErr != nil { return singletonRootErr } for _, c := range intermediates { pool.AddCert(c) } return nil } func initRoots() ([]*x509.Certificate, []*x509.Certificate, error) { tufClient, err := tuf.NewFromEnv(context.Background()) if err != nil { return nil, nil, fmt.Errorf("initializing tuf: %w", err) } // Retrieve from the embedded or cached TUF root. If expired, a network // call is made to update the root. targets, err := tufClient.GetTargetsByMeta(tuf.Fulcio, []string{fulcioTargetStr, fulcioV1TargetStr, fulcioV1IntermediateTargetStr}) if err != nil { return nil, nil, fmt.Errorf("error getting targets: %w", err) } if len(targets) == 0 { return nil, nil, errors.New("none of the Fulcio roots have been found") } rootPool := []*x509.Certificate{} intermediatePool := []*x509.Certificate{} for _, t := range targets { certs, err := cryptoutils.UnmarshalCertificatesFromPEM(t.Target) if err != nil { return nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) } for _, cert := range certs { // root certificates are self-signed if bytes.Equal(cert.RawSubject, cert.RawIssuer) { rootPool = append(rootPool, cert) } else { intermediatePool = append(intermediatePool, cert) } } } return rootPool, intermediatePool, nil } sigstore-1.8.6/pkg/oauth/000077500000000000000000000000001463713551000152735ustar00rootroot00000000000000sigstore-1.8.6/pkg/oauth/doc.go000066400000000000000000000012511463713551000163660ustar00rootroot00000000000000// // 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 oauth contains types and utilities related to OAuth2. package oauth sigstore-1.8.6/pkg/oauth/interactive.go000066400000000000000000000501041463713551000201370ustar00rootroot00000000000000// 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 oauth implements OAuth/OIDC support for device and token flows package oauth import ( "bytes" "fmt" "text/template" ) // GetInteractiveSuccessHTML is the page displayed upon success when using a web browser during an interactive Oauth token flow. // The page will close automatically if autoclose is true with the timeout specified. func GetInteractiveSuccessHTML(autoclose bool, timeout int) (string, error) { const successTemplate = ` Sigstore Authentication
sigstore authentication successful!
{{ if .Autoclose -}} {{- else -}}
You may now close this page.
{{- end }}
{{ if .Autoclose -}} {{- end }} ` // Parse the template tmpl, err := template.New("success").Parse(successTemplate) if err != nil { return "", fmt.Errorf("error parsing success template: %w", err) } // Pass autoclose and timeout to the template data := struct { Autoclose bool Timeout int }{ autoclose, timeout, } var htmlPage bytes.Buffer if err := tmpl.Execute(&htmlPage, data); err != nil { return "", fmt.Errorf("error executing template: %w", err) } return htmlPage.String(), nil } const ( // InteractiveSuccessHTML (deprecated) is the page displayed upon success when using a web browser during an interactive Oauth token flow. InteractiveSuccessHTML = ` Sigstore Authentication
sigstore authentication successful!
You may now close this page.
` ) sigstore-1.8.6/pkg/oauth/internal/000077500000000000000000000000001463713551000171075ustar00rootroot00000000000000sigstore-1.8.6/pkg/oauth/internal/doc.go000066400000000000000000000012541463713551000202050ustar00rootroot00000000000000// // 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 internal contains utilities for parsing OAuth2 tokens package internal sigstore-1.8.6/pkg/oauth/internal/token.go000066400000000000000000000115171463713551000205630ustar00rootroot00000000000000// 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 internal includes functions to support OAuth/OIDC package internal import ( "encoding/json" "fmt" "io" "mime" "net/http" "net/url" "strconv" "time" "golang.org/x/oauth2" ) // var for testing var currentTime = time.Now // tokenRespJSON is the struct representing the JSON form of a RFC6749 access token success response. // See: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 type tokenRespJSON struct { AccessToken string `json:"access_token"` TokenType string `json:"token_type"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"` Scope string `json:"scope"` } func parseFormURLEncodedAccessTokenSuccess(body []byte) (token *oauth2.Token, err error) { vals, err := url.ParseQuery(string(body)) if err != nil { return nil, err } token = &oauth2.Token{ AccessToken: vals.Get("access_token"), TokenType: vals.Get("token_type"), RefreshToken: vals.Get("refresh_token"), } ei := vals.Get("expires_in") if ei != "" { expires, err := strconv.Atoi(ei) if err != nil { return nil, fmt.Errorf(`failed to parse "expires_in": %w`, err) } if expires != 0 { token.Expiry = currentTime().Add(time.Duration(expires) * time.Second) } } return token.WithExtra(vals), nil } func parseJSONAccessTokenSuccess(body []byte) (token *oauth2.Token, err error) { var tj tokenRespJSON if err = json.Unmarshal(body, &tj); err != nil { return nil, err } token = &oauth2.Token{ AccessToken: tj.AccessToken, TokenType: tj.TokenType, RefreshToken: tj.RefreshToken, } if tj.ExpiresIn != 0 { token.Expiry = currentTime().Add(time.Duration(tj.ExpiresIn) * time.Second) } raw := map[string]interface{}{} if err = json.Unmarshal(body, &raw); err != nil { return nil, err } return token.WithExtra(raw), nil } func parseAccessTokenSuccess(body []byte, contentType string) (token *oauth2.Token, err error) { if contentType == "application/x-www-form-urlencoded" { return parseFormURLEncodedAccessTokenSuccess(body) } return parseJSONAccessTokenSuccess(body) } // ErrorTokenResponse represents an RFC6749 access token error response. // See: https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 type ErrorTokenResponse struct { Code string `json:"error"` Description string `json:"error_description,omitempty"` URI string `json:"error_uri,omitempty"` } // Error implements `error` func (e *ErrorTokenResponse) Error() string { str, _ := json.Marshal(e) return string(str) } func parseFormURLEncodedAccessTokenError(body []byte) (*ErrorTokenResponse, error) { vals, parseErr := url.ParseQuery(string(body)) if parseErr != nil { return nil, parseErr } return &ErrorTokenResponse{ Code: vals.Get("error"), Description: vals.Get("error_description"), URI: vals.Get("error_uri"), }, nil } func parseJSONAccessTokenError(body []byte) (respErr *ErrorTokenResponse, parseErr error) { var ej ErrorTokenResponse if parseErr = json.Unmarshal(body, &ej); parseErr != nil { return nil, parseErr } return &ej, nil } func parseAccessTokenError(body []byte, contentType string) (respErr *ErrorTokenResponse, parseErr error) { if contentType == "application/x-www-form-urlencoded" { return parseFormURLEncodedAccessTokenError(body) } return parseJSONAccessTokenError(body) } // ParseAccessTokenResponse parses an RFC6749 access token response and returns either an `*oauth2.Token` on success, an `*ErrorTokenResponse` on failure, or any other error if the response cannot be parsed. // See: https://datatracker.ietf.org/doc/html/rfc6749#section-5 func ParseAccessTokenResponse(tokenResp *http.Response) (token *oauth2.Token, err error) { body, err := io.ReadAll(io.LimitReader(tokenResp.Body, 1<<20)) if err != nil { return nil, err } contentType, _, _ := mime.ParseMediaType(tokenResp.Header.Get("Content-Type")) if tokenResp.StatusCode != http.StatusOK { respErr, parseErr := parseAccessTokenError(body, contentType) if parseErr != nil { return nil, parseErr } return nil, respErr } token, err = parseAccessTokenSuccess(body, contentType) if err != nil { return nil, err } if token.AccessToken == "" { return nil, fmt.Errorf(`response did not contain "access_token". Content-Type: %q, Body: %s`, contentType, string(body)) } return token, nil } sigstore-1.8.6/pkg/oauth/internal/token_test.go000066400000000000000000000151721463713551000216230ustar00rootroot00000000000000// 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 internal import ( "bytes" "errors" "fmt" "io" "net/http" "net/url" "reflect" "testing" "time" ) func TestParseAccessTokenSuccessResponse(t *testing.T) { now := currentTime() realCurrentTime := currentTime currentTime = func() time.Time { return now } defer func() { currentTime = realCurrentTime }() testCases := []struct { desc string respContentType string respBody []byte wantAccessToken string wantRefreshToken string wantTokenType string wantExpiry time.Time mustHaveExtras map[string]interface{} wantError error }{ { desc: "json", respContentType: "application/json", respBody: []byte(`{ "access_token": "json access_token", "token_type": "Bearer", "refresh_token": "json refresh_token", "expires_in": 3600, "scope": "foo bar" }`), wantAccessToken: "json access_token", wantRefreshToken: "json refresh_token", wantTokenType: "Bearer", wantExpiry: now.Add(3600 * time.Second), mustHaveExtras: map[string]interface{}{ "scope": "foo bar", }, }, { desc: "json no access_token", respContentType: "application/json", respBody: []byte(`{"token_type":"Bearer","expires_in":3600,"scope":"foo bar"}`), wantError: fmt.Errorf(`response did not contain "access_token". Content-Type: %q, Body: %s`, "application/json", `{"token_type":"Bearer","expires_in":3600,"scope":"foo bar"}`), }, { desc: "bad json", respContentType: "application/json", respBody: []byte(`"token_type":"Bearer","expires_in":3600,"scope":"foo bar"`), wantError: errors.New("invalid character ':' after top-level value"), }, { desc: "x-www-form-urlencoded", respContentType: "application/x-www-form-urlencoded", respBody: []byte(url.Values{ "access_token": []string{"urlencoded access_token"}, "token_type": []string{"MAC"}, "refresh_token": []string{"urlencoded refresh_token"}, "expires_in": []string{"420"}, "scope": []string{"bar baz"}, }.Encode()), wantAccessToken: "urlencoded access_token", wantRefreshToken: "urlencoded refresh_token", wantTokenType: "MAC", wantExpiry: now.Add(420 * time.Second), mustHaveExtras: map[string]interface{}{ "scope": "bar baz", }, }, { desc: "expires_in unparsable", respContentType: "application/x-www-form-urlencoded", respBody: []byte(url.Values{ "access_token": []string{"urlencoded access_token"}, "token_type": []string{"Bearer"}, "expires_in": []string{"unparsable"}, }.Encode()), wantError: errors.New("failed to parse \"expires_in\": strconv.Atoi: parsing \"unparsable\": invalid syntax"), }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { testResp := &http.Response{ StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader(tc.respBody)), } if tc.respContentType != "" { testResp.Header = make(http.Header, 1) testResp.Header.Set("Content-Type", tc.respContentType) } token, err := ParseAccessTokenResponse(testResp) if err == nil && tc.wantError != nil { t.Fatalf("ParseAccessTokenResponse should have returned an error, got %v", token) } if err != nil { if tc.wantError != nil { gotErr := err.Error() wantErr := tc.wantError.Error() if gotErr != wantErr { t.Fatalf("ParseAccessTokenResponse should have returned error %q, got %q", wantErr, gotErr) } return } t.Fatalf("ParseAccessTokenResponse returned error: %v", err) } if token.AccessToken != tc.wantAccessToken { t.Errorf("Wanted AccessToken %q, got %q", tc.wantAccessToken, token.AccessToken) } if token.RefreshToken != tc.wantRefreshToken { t.Errorf("Wanted RefreshToken %q, got %q", tc.wantRefreshToken, token.RefreshToken) } if token.TokenType != tc.wantTokenType { t.Errorf("Wanted TokenType %q, got %q", tc.wantTokenType, token.TokenType) } if token.Expiry != tc.wantExpiry { t.Errorf("Wanted Expiry %v, got %v", tc.wantExpiry, token.Expiry) } for k, v := range tc.mustHaveExtras { gotVal := token.Extra(k) if !reflect.DeepEqual(v, gotVal) { t.Errorf("Wanted Extra(%q)=%v, got %v", k, v, gotVal) } } }) } } func TestParseAccessTokenFailResponse(t *testing.T) { testCases := []struct { desc string respStatusCode int respContentType string respBody []byte wantError error }{ { desc: "json", respStatusCode: http.StatusBadRequest, respContentType: "application/json", respBody: []byte(`{"error":"invalid_request","error_description":"description of error","error_uri":"https://test.example.com/json"}`), wantError: &ErrorTokenResponse{ Code: "invalid_request", Description: "description of error", URI: "https://test.example.com/json", }, }, { desc: "x-www-form-urlencoded", respStatusCode: http.StatusBadRequest, respContentType: "application/x-www-form-urlencoded", respBody: []byte(url.Values{ "error": []string{"invalid_request"}, "error_description": []string{"description of error"}, "error_uri": []string{"https://test.example.com/form-urlencoded"}, }.Encode()), wantError: &ErrorTokenResponse{ Code: "invalid_request", Description: "description of error", URI: "https://test.example.com/form-urlencoded", }, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { testResp := &http.Response{ StatusCode: tc.respStatusCode, Body: io.NopCloser(bytes.NewReader(tc.respBody)), } if tc.respContentType != "" { testResp.Header = make(http.Header, 1) testResp.Header.Set("Content-Type", tc.respContentType) } token, err := ParseAccessTokenResponse(testResp) if err == nil { t.Fatalf("ParseAccessTokenResponse should have failed, got: %v", token) } gotErr := err.Error() wantErr := tc.wantError.Error() if gotErr != wantErr { t.Errorf("ParseAccessTokenResponse should have returned error %q, got %q", wantErr, gotErr) } }) } } sigstore-1.8.6/pkg/oauth/oidc/000077500000000000000000000000001463713551000162115ustar00rootroot00000000000000sigstore-1.8.6/pkg/oauth/oidc/doc.go000066400000000000000000000012421463713551000173040ustar00rootroot00000000000000// // 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 oidc contains utilities related to OIDC tokens. package oidc sigstore-1.8.6/pkg/oauth/oidc/interactive.go000066400000000000000000000146161463713551000210650ustar00rootroot00000000000000// 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 oidc implements support for fetching OIDC tokens package oidc import ( "context" "errors" "fmt" "net" "net/http" "net/url" "os" "time" coreoidc "github.com/coreos/go-oidc/v3/oidc" "github.com/pkg/browser" "github.com/segmentio/ksuid" "github.com/sigstore/sigstore/pkg/oauth" "golang.org/x/oauth2" ) const oobRedirectURI = "urn:ietf:wg:oauth:2.0:oob" type browserOpener func(url string) error func doOobFlow(cfg *oauth2.Config, stateToken string, opts []oauth2.AuthCodeOption) string { cfg.RedirectURL = oobRedirectURI authURL := cfg.AuthCodeURL(stateToken, opts...) fmt.Fprintln(os.Stderr, "Go to the following link in a browser:\n\n\t", authURL) fmt.Fprintf(os.Stderr, "Enter verification code: ") var code string fmt.Scanln(&code) return code } func startRedirectListener(state, htmlPage, redirectURL string, codeCh chan string, errCh chan error) (*http.Server, *url.URL, error) { var listener net.Listener var urlListener *url.URL var err error if redirectURL == "" { listener, err = net.Listen("tcp", "localhost:0") // ":0" == OS picks if err != nil { return nil, nil, err } addr, ok := listener.Addr().(*net.TCPAddr) if !ok { return nil, nil, fmt.Errorf("listener addr is not TCPAddr") } urlListener = &url.URL{ Scheme: "http", Host: fmt.Sprintf("localhost:%d", addr.Port), Path: "/auth/callback", } } else { urlListener, err = url.Parse(redirectURL) if err != nil { return nil, nil, err } listener, err = net.Listen("tcp", urlListener.Host) if err != nil { return nil, nil, err } } m := http.NewServeMux() s := &http.Server{ Addr: urlListener.Host, Handler: m, // an arbitrary reasonable value to fix gosec lint error ReadHeaderTimeout: 2 * time.Second, } m.HandleFunc(urlListener.Path, func(w http.ResponseWriter, r *http.Request) { // even though these are fetched from the FormValue method, // these are supplied as query parameters if r.FormValue("state") != state { errCh <- errors.New("invalid state token") return } codeCh <- r.FormValue("code") fmt.Fprint(w, htmlPage) }) go func() { if err := s.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { errCh <- err } }() return s, urlListener, nil } func getCode(codeCh chan string, errCh chan error) (string, error) { select { case code := <-codeCh: return code, nil case err := <-errCh: return "", err case <-time.After(120 * time.Second): return "", errors.New("timeout") } } // newKSUID returns a globally unique, base62 (URL-safe) encoded, 27 character string. func newKSUID() string { return ksuid.New().String() } type interactiveIDTokenSource struct { cfg oauth2.Config oidp *coreoidc.Provider extraAuthCodeOpts []oauth2.AuthCodeOption browser browserOpener autoclose bool // autoclose specifies whether to close window after successful authentication autocloseTimeout int // autocloseTimeout specifies the time to wait before closing the window } var errWontOpenBrowser = errors.New("not opening that browser") func failBrowser(string) error { return errWontOpenBrowser } func (idts *interactiveIDTokenSource) IDToken(ctx context.Context) (*IDToken, error) { cfg := idts.cfg p := idts.oidp // generate random fields and save them for comparison after OAuth2 dance stateToken := newKSUID() nonce := newKSUID() codeCh := make(chan string) errCh := make(chan error) // get html success page with configured autoclose and autocloseTimeout settings htmlPage, err := oauth.GetInteractiveSuccessHTML(idts.autoclose, idts.autocloseTimeout) if err != nil { return nil, err } // starts listener using the redirect_uri, otherwise starts on ephemeral port redirectServer, redirectURL, err := startRedirectListener( stateToken, htmlPage, cfg.RedirectURL, codeCh, errCh, ) if err != nil { close(codeCh) close(errCh) return nil, fmt.Errorf("starting redirect listener: %w", err) } defer func() { go func() { _ = redirectServer.Shutdown(context.Background()) close(codeCh) close(errCh) }() }() cfg.RedirectURL = redirectURL.String() // require that OIDC provider support PKCE to provide sufficient security for the CLI pkce, err := NewPKCE(p) if err != nil { return nil, err } opts := append(pkce.AuthURLOpts(), oauth2.AccessTypeOnline, coreoidc.Nonce(nonce)) if len(idts.extraAuthCodeOpts) > 0 { opts = append(opts, idts.extraAuthCodeOpts...) } authCodeURL := cfg.AuthCodeURL(stateToken, opts...) var code string if err := idts.browser(authCodeURL); err != nil { // Swap to the out of band flow if we can't open the browser if !errors.Is(err, errWontOpenBrowser) { fmt.Fprintf(os.Stderr, "error opening browser: %v\n", err) } code = doOobFlow(&cfg, stateToken, opts) } else { fmt.Fprintf(os.Stderr, "Your browser will now be opened to:\n%s\n", authCodeURL) code, err = getCode(codeCh, errCh) if err != nil { fmt.Fprintf(os.Stderr, "error getting code from local server: %v\n", err) code = doOobFlow(&cfg, stateToken, opts) } } token, err := cfg.Exchange(ctx, code, append(pkce.TokenURLOpts(), coreoidc.Nonce(nonce))...) if err != nil { return nil, err } verifier := p.Verifier(&coreoidc.Config{ClientID: cfg.ClientID}) return extractAndVerifyIDToken(ctx, token, verifier, nonce) } // InteractiveIDTokenSource returns an `IDTokenSource` which performs an interactive Oauth token flow in order to retrieve an `IDToken`. func InteractiveIDTokenSource(cfg oauth2.Config, oidp *coreoidc.Provider, extraAuthCodeOpts []oauth2.AuthCodeOption, allowBrowser, autoclose bool, autocloseTimeout int) IDTokenSource { ts := &interactiveIDTokenSource{cfg: cfg, oidp: oidp, extraAuthCodeOpts: extraAuthCodeOpts, browser: failBrowser, autoclose: autoclose, autocloseTimeout: autocloseTimeout} if allowBrowser { ts.browser = browser.OpenURL } return ts } sigstore-1.8.6/pkg/oauth/oidc/interactive_e2e_test.go000066400000000000000000000055041463713551000226530ustar00rootroot00000000000000// 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. //go:build e2e // +build e2e package oidc import ( "context" "errors" "os" "testing" coreoidc "github.com/coreos/go-oidc/v3/oidc" "github.com/go-rod/rod" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "golang.org/x/oauth2" ) type claims struct { Email string `json:"email"` Verified bool `json:"email_verified"` Subject string `json:"sub"` } func identityFromClaims(c claims) (string, error) { if c.Email != "" { if !c.Verified { return "", errors.New("not verified by identity provider") } return c.Email, nil } if c.Subject == "" { return "", errors.New("no subject found in claims") } return c.Subject, nil } // identityFromIDToken extracts the email or subject claim from an `IDToken“ func identityFromIDToken(tok *IDToken) (string, error) { claims := claims{} oidcTok := tok.IDToken if err := oidcTok.Claims(&claims); err != nil { return "", err } return identityFromClaims(claims) } type InteractiveOIDCSuite struct { suite.Suite } func (suite *InteractiveOIDCSuite) TestInteractiveIDTokenSource() { ctx := context.Background() urlCh := make(chan string) defer close(urlCh) browserOpener := func(input string) error { urlCh <- input return nil } provider, err := coreoidc.NewProvider(ctx, os.Getenv("OIDC_ISSUER")) require.Nil(suite.T(), err) cfg := oauth2.Config{ ClientID: os.Getenv("OIDC_ID"), ClientSecret: "", Endpoint: provider.Endpoint(), Scopes: []string{coreoidc.ScopeOpenID, "email"}, } autoclose := false autocloseTimeout := 0 ts := &interactiveIDTokenSource{ cfg: cfg, oidp: provider, browser: browserOpener, autoclose: autoclose, autocloseTimeout: autocloseTimeout, } go func() { authCodeURL := <-urlCh page := rod.New().MustConnect().MustPage(authCodeURL) page.MustElement("body > div.dex-container > div > div > div:nth-child(2) > a > button").MustClick() }() idToken, err := ts.IDToken(ctx) require.Nil(suite.T(), err) email, err := identityFromIDToken(idToken) require.Nil(suite.T(), err) require.NotNil(suite.T(), email) require.Equal(suite.T(), "kilgore@kilgore.trout", email) } func TestInteractiveOIDCFlow(t *testing.T) { suite.Run(t, new(InteractiveOIDCSuite)) } sigstore-1.8.6/pkg/oauth/oidc/pkce.go000066400000000000000000000071361463713551000174710ustar00rootroot00000000000000// 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 oidc import ( "crypto/sha256" "encoding/base64" "fmt" "regexp" coreoidc "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) const ( // PKCES256 is the SHA256 option required by the PKCE RFC PKCES256 = "S256" ) // PKCE specifies the challenge and value pair required to fulfill RFC7636 type PKCE struct { Challenge string Method string Value string } // NewPKCE creates a new PKCE challenge for the specified provider per its supported methods (obtained through OIDC discovery endpoint) func NewPKCE(provider *coreoidc.Provider) (*PKCE, error) { var providerClaims struct { CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` } if err := provider.Claims(&providerClaims); err != nil { // will only error out if the JSON was malformed, which shouldn't happen at this point return nil, err } var chosenMethod string for _, method := range providerClaims.CodeChallengeMethodsSupported { // per RFC7636, any server that supports PKCE must support S256 if method == PKCES256 && chosenMethod != PKCES256 { chosenMethod = PKCES256 break } else if method != "plain" { fmt.Printf("Unsupported code challenge method in list: '%v'", method) } } if chosenMethod == "" { if providerIsAzureBacked(provider) { chosenMethod = PKCES256 } else { return nil, fmt.Errorf("PKCE is not supported by OIDC provider '%v'", provider.Endpoint().AuthURL) } } // we use two 27 character strings to meet requirements of RFC 7636: // (minimum length of 43 characters and a maximum length of 128 characters) value := newKSUID() + newKSUID() h := sha256.Sum256([]byte(value)) challenge := base64.RawURLEncoding.EncodeToString(h[:]) return &PKCE{ Challenge: challenge, Method: chosenMethod, Value: value, }, nil } // AuthURLOpts returns the set of request parameters required during the initial exchange of the OAuth2 flow func (p *PKCE) AuthURLOpts() []oauth2.AuthCodeOption { return []oauth2.AuthCodeOption{ oauth2.SetAuthURLParam("code_challenge_method", p.Method), oauth2.SetAuthURLParam("code_challenge", p.Challenge), } } // TokenURLOpts returns the set of request parameters required during the token request exchange flow func (p *PKCE) TokenURLOpts() []oauth2.AuthCodeOption { return []oauth2.AuthCodeOption{ oauth2.SetAuthURLParam("code_verifier", p.Value), } } var azureregex = regexp.MustCompile(`^https:\/\/login\.microsoftonline\.(com|us)\/`) // providerIsAzureBacked returns a boolean indicating whether the provider is Azure-backed; // Azure supports PKCE but does not advertise it in their OIDC discovery endpoint func providerIsAzureBacked(p *coreoidc.Provider) bool { // Per https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud#azure-ad-authentication-endpoints // if endpoint starts with any of these strings then we should attempt PKCE anyway as their OIDC discovery doc // does not advertise supporting PKCE but they actually do return p != nil && azureregex.MatchString(p.Endpoint().AuthURL) } sigstore-1.8.6/pkg/oauth/oidc/pkce_test.go000066400000000000000000000034071463713551000205250ustar00rootroot00000000000000// 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 oidc import ( "context" "fmt" "testing" coreoidc "github.com/coreos/go-oidc/v3/oidc" ) func TestProviderIsAzureBacked(t *testing.T) { actualAzureProviders := []string{ "https://login.microsoftonline.com/6babcaad-604b-40ac-a9d7-9fd97c0b779f/v2.0", } notAzureProviders := []string{ "https://accounts.google.com", "https://login.salesforce.com", } for _, tc := range actualAzureProviders { t.Run(fmt.Sprintf("testing azure provider %v", tc), func(t *testing.T) { p, err := coreoidc.NewProvider(context.Background(), tc) if err != nil { t.Error(err) } if !providerIsAzureBacked(p) { t.Errorf("valid azure provider URL %v was not detected as being azure backed", tc) } }) } for _, tc := range notAzureProviders { t.Run(fmt.Sprintf("testing invalid azure provider %v", tc), func(t *testing.T) { p, err := coreoidc.NewProvider(context.Background(), tc) if err != nil { t.Error(err) } if providerIsAzureBacked(p) { t.Errorf("invalid azure provider URL %v was detected as being azure backed", tc) } }) } if providerIsAzureBacked(nil) != false { t.Errorf("nil provider should not return true for being Azure-backed") } } sigstore-1.8.6/pkg/oauth/oidc/token.go000066400000000000000000000042501463713551000176610ustar00rootroot00000000000000// 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 oidc import ( "context" "errors" coreoidc "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) // IDToken is a structured representation of an OIDC IDToken. type IDToken struct { coreoidc.IDToken } // IDTokenSource provides `IDTokens`. type IDTokenSource interface { // IDToken returns an ID token or an error. IDToken(context.Context) (*IDToken, error) } type staticIDTokenSource struct { idt *IDToken } func (s staticIDTokenSource) IDToken(context.Context) (*IDToken, error) { return s.idt, nil } // StaticIDTokenSource returns an `IDTokenSource` which always returns the given `IDToken`. func StaticIDTokenSource(idt *IDToken) IDTokenSource { return staticIDTokenSource{idt: idt} } // extractAndVerifyIDToken extracts the ID token from the given `oauth2.Token`, then verifies it against the given verifier and nonce. func extractAndVerifyIDToken(ctx context.Context, t *oauth2.Token, v *coreoidc.IDTokenVerifier, nonce string) (*IDToken, error) { // requesting 'openid' scope should ensure an id_token is given when exchanging the code for an access token unverifiedIDToken, ok := t.Extra("id_token").(string) if !ok { return nil, errors.New("id_token not present") } // verify nonce, client ID, access token hash before using it idToken, err := v.Verify(ctx, unverifiedIDToken) if err != nil { return nil, err } if idToken.Nonce != nonce { return nil, errors.New("nonce does not match value sent") } if idToken.AccessTokenHash != "" { if err := idToken.VerifyAccessToken(t.AccessToken); err != nil { return nil, err } } return &IDToken{*idToken}, nil } sigstore-1.8.6/pkg/oauthflow/000077500000000000000000000000001463713551000161635ustar00rootroot00000000000000sigstore-1.8.6/pkg/oauthflow/client_credentials.go000066400000000000000000000104601463713551000223460ustar00rootroot00000000000000// // Copyright 2024 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 oauthflow import ( "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) // CodeURL fetches the client credentials token authorization endpoint URL from the provider's well-known configuration endpoint func (d *DefaultFlowClientCredentials) CodeURL() (string, error) { if d.codeURL != "" { return d.codeURL, nil } wellKnown := strings.TrimSuffix(d.Issuer, "/") + "/.well-known/openid-configuration" /* #nosec */ httpClient := &http.Client{ Timeout: 3 * time.Second, } resp, err := httpClient.Get(wellKnown) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("unable to read response body: %w", err) } if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("%s: %s", resp.Status, body) } providerConfig := struct { Issuer string `json:"issuer"` TokenEndpoint string `json:"token_endpoint"` }{} if err = json.Unmarshal(body, &providerConfig); err != nil { return "", fmt.Errorf("oidc: failed to decode provider discovery object: %w", err) } if d.Issuer != providerConfig.Issuer { return "", fmt.Errorf("oidc: issuer did not match the issuer returned by provider, expected %q got %q", d.Issuer, providerConfig.Issuer) } if providerConfig.TokenEndpoint == "" { return "", fmt.Errorf("oidc: client credentials token authorization endpoint not returned by provider") } d.codeURL = providerConfig.TokenEndpoint return d.codeURL, nil } // DefaultFlowClientCredentials fetches an OIDC Identity token using the Client Credentials Grant flow as specified in RFC8628 type DefaultFlowClientCredentials struct { Issuer string codeURL string } // NewClientCredentialsFlow creates a new DefaultFlowClientCredentials that retrieves an OIDC Identity Token using a Client Credentials Grant func NewClientCredentialsFlow(issuer string) *DefaultFlowClientCredentials { return &DefaultFlowClientCredentials{ Issuer: issuer, } } func (d *DefaultFlowClientCredentials) clientCredentialsFlow(_ *oidc.Provider, clientID, clientSecret, redirectURL string) (string, error) { data := url.Values{ "client_id": []string{clientID}, "client_secret": []string{clientSecret}, "scope": []string{"openid email"}, "grant_type": []string{"client_credentials"}, } if redirectURL != "" { // If a redirect uri is provided then use it data["redirect_uri"] = []string{redirectURL} } codeURL, err := d.CodeURL() if err != nil { return "", err } /* #nosec */ resp, err := http.PostForm(codeURL, data) if err != nil { return "", err } defer resp.Body.Close() b, err := io.ReadAll(resp.Body) if err != nil { return "", err } if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("%s: %s", resp.Status, b) } tr := tokenResp{} if err := json.Unmarshal(b, &tr); err != nil { return "", err } if tr.IDToken != "" { fmt.Println("Token received!") return tr.IDToken, nil } return "", fmt.Errorf("unexpected error in client flow: %s", tr.Error) } // GetIDToken gets an OIDC ID Token from the specified provider using the Client Credentials Grant flow func (d *DefaultFlowClientCredentials) GetIDToken(p *oidc.Provider, cfg oauth2.Config) (*OIDCIDToken, error) { idToken, err := d.clientCredentialsFlow(p, cfg.ClientID, cfg.ClientSecret, cfg.RedirectURL) if err != nil { return nil, err } verifier := p.Verifier(&oidc.Config{ClientID: cfg.ClientID}) parsedIDToken, err := verifier.Verify(context.Background(), idToken) if err != nil { return nil, err } subj, err := SubjectFromToken(parsedIDToken) if err != nil { return nil, err } return &OIDCIDToken{ RawString: idToken, Subject: subj, }, nil } sigstore-1.8.6/pkg/oauthflow/client_credentials_test.go000066400000000000000000000040571463713551000234120ustar00rootroot00000000000000// // Copyright 2024 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 oauthflow import ( "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "strings" "testing" "github.com/coreos/go-oidc/v3/oidc" ) type testccDriver struct { respCh chan interface{} t *testing.T } func (td *testccDriver) handler(w http.ResponseWriter, r *http.Request) { td.t.Log("got request:", r.URL.Path) if r.URL.Path == "/.well-known/openid-configuration" { _, _ = w.Write([]byte(strings.ReplaceAll(wellKnownOIDCConfig, "ISSUER", fmt.Sprintf("http://%s", r.Host)))) return } nextReply := <-td.respCh b, err := json.Marshal(nextReply) if err != nil { w.WriteHeader(http.StatusBadRequest) return } switch r.URL.Path { case "/token": _, _ = w.Write(b) default: w.WriteHeader(http.StatusBadRequest) return } } func TestClientCredentialsFlowTokenGetter_ccFlow(t *testing.T) { td := testccDriver{ respCh: make(chan interface{}, 3), t: t, } ts := httptest.NewServer(http.HandlerFunc(td.handler)) defer ts.Close() dtg := DefaultFlowClientCredentials{ Issuer: ts.URL, } p, pErr := oidc.NewProvider(context.Background(), ts.URL) if pErr != nil { t.Fatal(pErr) } tokenCh, errCh := make(chan string), make(chan error) go func() { token, err := dtg.clientCredentialsFlow(p, "sigstore", "", "") tokenCh <- token errCh <- err }() td.respCh <- tokenResponse("mytoken", "") token := <-tokenCh err := <-errCh if err != nil { t.Fatal(err) } if token != "mytoken" { t.Fatal("expected mytoken") } } sigstore-1.8.6/pkg/oauthflow/device.go000066400000000000000000000164321463713551000177570ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package oauthflow implements OAuth/OIDC support for device and token flows package oauthflow import ( "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) const ( // SigstoreDeviceURL specifies the Device Code endpoint for the public good Sigstore service /* #nosec */ // Deprecated: this constant (while correct) should not be used SigstoreDeviceURL = "https://oauth2.sigstore.dev/auth/device/code" // SigstoreTokenURL specifies the Token endpoint for the public good Sigstore service /* #nosec */ // Deprecated: this constant (while correct) should not be used SigstoreTokenURL = "https://oauth2.sigstore.dev/auth/device/token" ) type deviceResp struct { DeviceCode string `json:"device_code"` UserCode string `json:"user_code"` VerificationURI string `json:"verification_uri"` VerificationURIComplete string `json:"verification_uri_complete"` Interval int `json:"interval"` ExpiresIn int `json:"expires_in"` } type tokenResp struct { IDToken string `json:"id_token"` Error string `json:"error"` } // DeviceFlowTokenGetter fetches an OIDC Identity token using the Device Code Grant flow as specified in RFC8628 type DeviceFlowTokenGetter struct { MessagePrinter func(string) Sleeper func(time.Duration) Issuer string codeURL string } // NewDeviceFlowTokenGetter creates a new DeviceFlowTokenGetter that retrieves an OIDC Identity Token using a Device Code Grant // Deprecated: NewDeviceFlowTokenGetter is deprecated; use NewDeviceFlowTokenGetterForIssuer() instead func NewDeviceFlowTokenGetter(issuer, codeURL, _ string) *DeviceFlowTokenGetter { return &DeviceFlowTokenGetter{ MessagePrinter: func(s string) { fmt.Println(s) }, Sleeper: time.Sleep, Issuer: issuer, codeURL: codeURL, } } // NewDeviceFlowTokenGetterForIssuer creates a new DeviceFlowTokenGetter that retrieves an OIDC Identity Token using a Device Code Grant func NewDeviceFlowTokenGetterForIssuer(issuer string) *DeviceFlowTokenGetter { return &DeviceFlowTokenGetter{ MessagePrinter: func(s string) { fmt.Println(s) }, Sleeper: time.Sleep, Issuer: issuer, } } func (d *DeviceFlowTokenGetter) deviceFlow(p *oidc.Provider, clientID, redirectURL string) (string, error) { // require that OIDC provider support PKCE to provide sufficient security for the CLI pkce, err := NewPKCE(p) if err != nil { return "", err } data := url.Values{ "client_id": []string{clientID}, "scope": []string{"openid email"}, "code_challenge_method": []string{pkce.Method}, "code_challenge": []string{pkce.Challenge}, } if redirectURL != "" { // If a redirect uri is provided then use it data["redirect_uri"] = []string{redirectURL} } codeURL, err := d.CodeURL() if err != nil { return "", err } /* #nosec */ resp, err := http.PostForm(codeURL, data) if err != nil { return "", err } defer resp.Body.Close() b, err := io.ReadAll(resp.Body) if err != nil { return "", err } if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("%s: %s", resp.Status, b) } parsed := deviceResp{} if err := json.Unmarshal(b, &parsed); err != nil { return "", err } uri := parsed.VerificationURIComplete if uri == "" { uri = parsed.VerificationURI } d.MessagePrinter(fmt.Sprintf("Enter the verification code %s in your browser at: %s", parsed.UserCode, uri)) d.MessagePrinter(fmt.Sprintf("Code will be valid for %d seconds", parsed.ExpiresIn)) for { // Some providers use a secret here, we don't need for sigstore oauth one so leave it off. data := url.Values{ "grant_type": []string{"urn:ietf:params:oauth:grant-type:device_code"}, "device_code": []string{parsed.DeviceCode}, "scope": []string{"openid", "email"}, "code_verifier": []string{pkce.Value}, } /* #nosec */ resp, err := http.PostForm(p.Endpoint().TokenURL, data) if err != nil { return "", err } defer resp.Body.Close() b, err := io.ReadAll(resp.Body) if err != nil { return "", err } tr := tokenResp{} if err := json.Unmarshal(b, &tr); err != nil { return "", err } if tr.IDToken != "" { d.MessagePrinter("Token received!") return tr.IDToken, nil } switch tr.Error { case "access_denied", "expired_token": return "", fmt.Errorf("error obtaining token: %s", tr.Error) case "authorization_pending": d.Sleeper(time.Duration(parsed.Interval) * time.Second) case "slow_down": // Add ten seconds if we got told to slow down d.Sleeper(time.Duration(parsed.Interval)*time.Second + 10*time.Second) default: return "", fmt.Errorf("unexpected error in device flow: %s", tr.Error) } } } // GetIDToken gets an OIDC ID Token from the specified provider using the device code grant flow func (d *DeviceFlowTokenGetter) GetIDToken(p *oidc.Provider, cfg oauth2.Config) (*OIDCIDToken, error) { idToken, err := d.deviceFlow(p, cfg.ClientID, cfg.RedirectURL) if err != nil { return nil, err } verifier := p.Verifier(&oidc.Config{ClientID: cfg.ClientID}) parsedIDToken, err := verifier.Verify(context.Background(), idToken) if err != nil { return nil, err } subj, err := SubjectFromToken(parsedIDToken) if err != nil { return nil, err } return &OIDCIDToken{ RawString: idToken, Subject: subj, }, nil } // CodeURL fetches the device authorization endpoint URL from the provider's well-known configuration endpoint func (d *DeviceFlowTokenGetter) CodeURL() (string, error) { if d.codeURL != "" { return d.codeURL, nil } wellKnown := strings.TrimSuffix(d.Issuer, "/") + "/.well-known/openid-configuration" /* #nosec */ httpClient := &http.Client{ Timeout: 3 * time.Second, } resp, err := httpClient.Get(wellKnown) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("unable to read response body: %w", err) } if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("%s: %s", resp.Status, body) } providerConfig := struct { Issuer string `json:"issuer"` DeviceEndpoint string `json:"device_authorization_endpoint"` }{} if err = json.Unmarshal(body, &providerConfig); err != nil { return "", fmt.Errorf("oidc: failed to decode provider discovery object: %w", err) } if d.Issuer != providerConfig.Issuer { return "", fmt.Errorf("oidc: issuer did not match the issuer returned by provider, expected %q got %q", d.Issuer, providerConfig.Issuer) } if providerConfig.DeviceEndpoint == "" { return "", fmt.Errorf("oidc: device authorization endpoint not returned by provider") } d.codeURL = providerConfig.DeviceEndpoint return d.codeURL, nil } sigstore-1.8.6/pkg/oauthflow/device_test.go000066400000000000000000000071651463713551000210210ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package oauthflow import ( "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/coreos/go-oidc/v3/oidc" ) const wellKnownOIDCConfig string = ` { "issuer": "ISSUER", "authorization_endpoint": "ISSUER/auth", "token_endpoint": "ISSUER/token", "jwks_uri": "ISSUER/keys", "userinfo_endpoint": "ISSUER/userinfo", "device_authorization_endpoint": "ISSUER/device/code", "grant_types_supported": [ "authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code" ], "response_types_supported": [ "code" ], "subject_types_supported": [ "public" ], "id_token_signing_alg_values_supported": [ "RS256" ], "code_challenge_methods_supported": [ "S256", "plain" ], "scopes_supported": [ "openid", "email", "groups", "profile", "offline_access" ], "token_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ], "claims_supported": [ "iss", "sub", "aud", "iat", "exp", "email", "email_verified", "locale", "name", "preferred_username", "at_hash" ] }` type testDriver struct { msgs []string respCh chan interface{} t *testing.T } func (td *testDriver) writeMsg(s string) { td.msgs = append(td.msgs, s) } func (td *testDriver) handler(w http.ResponseWriter, r *http.Request) { td.t.Log("got request:", r.URL.Path) if r.URL.Path == "/.well-known/openid-configuration" { _, _ = w.Write([]byte(strings.ReplaceAll(wellKnownOIDCConfig, "ISSUER", fmt.Sprintf("http://%s", r.Host)))) return } nextReply := <-td.respCh b, err := json.Marshal(nextReply) if err != nil { w.WriteHeader(http.StatusBadRequest) return } switch r.URL.Path { case "/token", "/device/code": _, _ = w.Write(b) default: w.WriteHeader(http.StatusBadRequest) return } } func TestDeviceFlowTokenGetter_deviceFlow(t *testing.T) { td := testDriver{ respCh: make(chan interface{}, 3), t: t, } ts := httptest.NewServer(http.HandlerFunc(td.handler)) defer ts.Close() dtg := DeviceFlowTokenGetter{ MessagePrinter: td.writeMsg, Sleeper: func(_ time.Duration) {}, Issuer: ts.URL, } p, pErr := oidc.NewProvider(context.Background(), ts.URL) if pErr != nil { t.Fatal(pErr) } tokenCh, errCh := make(chan string), make(chan error) go func() { token, err := dtg.deviceFlow(p, "sigstore", "") tokenCh <- token errCh <- err }() td.respCh <- codeResponse() td.respCh <- tokenResponse("mytoken", "") token := <-tokenCh err := <-errCh if err != nil { t.Fatal(err) } if token != "mytoken" { t.Fatal("expected mytoken") } if !strings.Contains(td.msgs[0], "complete-uri") { t.Fatal("expected URL to be logged, got:", td.msgs[0]) } } func codeResponse() deviceResp { return deviceResp{ UserCode: "mysecret", DeviceCode: "foobar", Interval: 3, VerificationURIComplete: "complete-uri", } } func tokenResponse(idToken, err string) tokenResp { return tokenResp{ IDToken: idToken, Error: err, } } sigstore-1.8.6/pkg/oauthflow/doc.go000066400000000000000000000012621463713551000172600ustar00rootroot00000000000000// // 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 oauthflow contains utilities to obtain OAuth2/OIDC tokens. package oauthflow sigstore-1.8.6/pkg/oauthflow/e2e_test.go000066400000000000000000000030661463713551000202310ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build e2e // +build e2e package oauthflow import ( "os" "testing" "github.com/go-rod/rod" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) type OAuthSuite struct { suite.Suite } func (suite *OAuthSuite) TestOauthFlow() { urlCh := make(chan string) oldOpener := browserOpener browserOpener = func(input string) error { urlCh <- input return nil } defer func() { browserOpener = oldOpener }() go func() { authCodeURL := <-urlCh page := rod.New().MustConnect().MustPage(authCodeURL) page.MustElement("body > div.dex-container > div > div > div:nth-child(2) > a > button").MustClick() }() idToken, err := OIDConnect( os.Getenv("OIDC_ISSUER"), os.Getenv("OIDC_ID"), "", "", DefaultIDTokenGetter, ) require.Nil(suite.T(), err) email := idToken.Subject require.NotNil(suite.T(), email) require.Equal(suite.T(), "kilgore@kilgore.trout", email) } func TestOAuthFlow(t *testing.T) { suite.Run(t, new(OAuthSuite)) } sigstore-1.8.6/pkg/oauthflow/flow.go000066400000000000000000000141361463713551000174660ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package oauthflow import ( "context" "encoding/json" "errors" "log" "github.com/coreos/go-oidc/v3/oidc" "github.com/go-jose/go-jose/v3" soauth "github.com/sigstore/sigstore/pkg/oauth" "golang.org/x/oauth2" ) const ( // PublicInstanceGithubAuthSubURL Default connector ids used by `oauth2.sigstore.dev` for Github PublicInstanceGithubAuthSubURL = "https://github.com/login/oauth" // PublicInstanceGoogleAuthSubURL Default connector ids used by `oauth2.sigstore.dev` for Google PublicInstanceGoogleAuthSubURL = "https://accounts.google.com" // PublicInstanceMicrosoftAuthSubURL Default connector ids used by `oauth2.sigstore.dev` for Microsoft PublicInstanceMicrosoftAuthSubURL = "https://login.microsoftonline.com" ) // TokenGetter provides a way to get an OIDC ID Token from an OIDC IdP type TokenGetter interface { GetIDToken(provider *oidc.Provider, config oauth2.Config) (*OIDCIDToken, error) } // OIDCIDToken represents an OIDC Identity Token type OIDCIDToken struct { RawString string // RawString provides the raw token (a base64-encoded JWT) value Subject string // Subject is the extracted subject from the raw token } // init func init() { // set the default HTML page for the DefaultIDTokenGetter htmlPage, err := soauth.GetInteractiveSuccessHTML(false, 10) if err != nil { log.Print("failed to get interactive success html, defaulting to original static page") } else { DefaultIDTokenGetter.HTMLPage = htmlPage } } // ConnectorIDOpt requests the value of prov as a the connector_id (either on URL or in form body) on the initial request; // this is used by Dex func ConnectorIDOpt(prov string) oauth2.AuthCodeOption { return oauth2.SetAuthURLParam("connector_id", prov) } // DefaultIDTokenGetter is the default implementation. // The HTML page and message printed to the terminal can be customized. var DefaultIDTokenGetter = &InteractiveIDTokenGetter{ HTMLPage: soauth.InteractiveSuccessHTML, } // PublicInstanceGithubIDTokenGetter is a `oauth2.sigstore.dev` flow selecting github as an Idp // Flow is based on `DefaultIDTokenGetter` fields var PublicInstanceGithubIDTokenGetter = &InteractiveIDTokenGetter{ HTMLPage: DefaultIDTokenGetter.HTMLPage, ExtraAuthURLParams: []oauth2.AuthCodeOption{ConnectorIDOpt(PublicInstanceGithubAuthSubURL)}, } // PublicInstanceGoogleIDTokenGetter is a `oauth2.sigstore.dev` flow selecting github as an Idp // Flow is based on `DefaultIDTokenGetter` fields var PublicInstanceGoogleIDTokenGetter = &InteractiveIDTokenGetter{ HTMLPage: DefaultIDTokenGetter.HTMLPage, ExtraAuthURLParams: []oauth2.AuthCodeOption{ConnectorIDOpt(PublicInstanceGoogleAuthSubURL)}, } // PublicInstanceMicrosoftIDTokenGetter is a `oauth2.sigstore.dev` flow selecting microsoft as an Idp // Flow is based on `DefaultIDTokenGetter` fields var PublicInstanceMicrosoftIDTokenGetter = &InteractiveIDTokenGetter{ HTMLPage: DefaultIDTokenGetter.HTMLPage, ExtraAuthURLParams: []oauth2.AuthCodeOption{ConnectorIDOpt(PublicInstanceMicrosoftAuthSubURL)}, } // OIDConnect requests an OIDC Identity Token from the specified issuer using the specified client credentials and TokenGetter // NOTE: If the redirectURL is empty a listener on localhost:0 is configured with '/auth/callback' as default path. func OIDConnect(issuer, id, secret, redirectURL string, tg TokenGetter) (*OIDCIDToken, error) { // Check if it's a StaticTokenGetter since NewProvider below will make // network calls unnecessarily and they are ignored. if sg, ok := tg.(*StaticTokenGetter); ok { return sg.GetIDToken(nil, oauth2.Config{}) } provider, err := oidc.NewProvider(context.Background(), issuer) if err != nil { return nil, err } config := oauth2.Config{ ClientID: id, ClientSecret: secret, Endpoint: provider.Endpoint(), Scopes: []string{oidc.ScopeOpenID, "email"}, RedirectURL: redirectURL, } return tg.GetIDToken(provider, config) } type claims struct { Email string `json:"email"` Verified bool `json:"email_verified"` Subject string `json:"sub"` } // SubjectFromToken extracts the subject claim from an OIDC Identity Token func SubjectFromToken(tok *oidc.IDToken) (string, error) { claims := claims{} if err := tok.Claims(&claims); err != nil { return "", err } return subjectFromClaims(claims) } func subjectFromClaims(c claims) (string, error) { if c.Email != "" { if !c.Verified { return "", errors.New("not verified by identity provider") } return c.Email, nil } if c.Subject == "" { return "", errors.New("no subject found in claims") } return c.Subject, nil } // StaticTokenGetter is a token getter that works on a JWT that is already known type StaticTokenGetter struct { RawToken string } // GetIDToken extracts an OIDCIDToken from the raw token *without verification* func (stg *StaticTokenGetter) GetIDToken(_ *oidc.Provider, _ oauth2.Config) (*OIDCIDToken, error) { unsafeTok, err := jose.ParseSigned(stg.RawToken) if err != nil { return nil, err } // THIS LOGIC IS GENERALLY UNSAFE BUT OK HERE // We are only parsing the id-token passed directly to a command line tool by a user, so it is trusted locally. // We need to extract the email address to attach an additional signed proof to the server. // THE SERVER WILL DO REAL VERIFICATION HERE unsafePayload := unsafeTok.UnsafePayloadWithoutVerification() claims := claims{} if err := json.Unmarshal(unsafePayload, &claims); err != nil { return nil, err } subj, err := subjectFromClaims(claims) if err != nil { return nil, err } return &OIDCIDToken{ RawString: stg.RawToken, Subject: subj, }, nil } sigstore-1.8.6/pkg/oauthflow/flow_test.go000066400000000000000000000102131463713551000205150ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package oauthflow import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "encoding/json" "fmt" "net/http" "net/url" "reflect" "testing" "github.com/go-jose/go-jose/v3" "golang.org/x/oauth2" ) func TestGetCodeWorking(t *testing.T) { desiredState := "foo" desiredCode := "code" // We need to start this in the background and send our request to the server var gotCode string var gotErr error doneCh := make(chan string) errCh := make(chan error) getCodeFinished := make(chan error) _, url, _ := startRedirectListener(desiredState, "", "", doneCh, errCh) go func() { gotCode, gotErr = getCode(doneCh, errCh) getCodeFinished <- gotErr }() sendCodeAndState(t, url, desiredCode, desiredState) // block until we're sure getCode has returned if getCodeErr := <-getCodeFinished; getCodeErr != nil { t.Fatal(gotErr) } if gotCode != desiredCode { t.Errorf("got %s, expected %s", gotCode, desiredCode) } } func TestGetCodeWrongState(t *testing.T) { desiredState := "foo" desiredCode := "code" // We need to start this in the background and send our request to the server var gotErr error doneCh := make(chan string) errCh := make(chan error) getCodeFinished := make(chan error) _, u, _ := startRedirectListener(desiredState, "", "", doneCh, errCh) go func() { _, gotErr = getCode(doneCh, errCh) getCodeFinished <- gotErr }() sendCodeAndState(t, u, desiredCode, "WRONG") // block until we're sure getCode has returned if getCodeErr := <-getCodeFinished; getCodeErr == nil { t.Fatal("expected error, sent wrong state!") } } func sendCodeAndState(t *testing.T, redirectURL *url.URL, code, state string) { t.Helper() testURL, _ := url.Parse(fmt.Sprintf("%v?code=%v&state=%v", redirectURL.String(), code, state)) if _, err := http.Get(testURL.String()); err != nil { t.Fatal(err) } } func TestStaticTokenGetter_GetIDToken(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } k := jose.SigningKey{ Algorithm: jose.ES256, Key: priv, } signer, err := jose.NewSigner(k, nil) if err != nil { t.Fatal(err) } tests := []struct { name string payload interface{} want *OIDCIDToken wantErr bool }{ { name: "no email", payload: struct { A string }{ A: "foo", }, wantErr: true, }, { name: "no verified", payload: struct { Email string }{ Email: "foobar", }, wantErr: true, }, { name: "not verified", payload: claims{ Email: "foobar", Verified: false, }, wantErr: true, }, { name: "verified", payload: claims{ Email: "foobar", Verified: true, }, want: &OIDCIDToken{ Subject: "foobar", }, }, { name: "spiffeid", payload: claims{ Subject: "spiffe://foobar", }, want: &OIDCIDToken{ Subject: "spiffe://foobar", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { raw, err := json.Marshal(tt.payload) if err != nil { t.Fatal(err) } jws, err := signer.Sign(raw) if err != nil { t.Fatal(err) } token, err := jws.CompactSerialize() if err != nil { t.Fatal(err) } if tt.want != nil { tt.want.RawString = token } stg := &StaticTokenGetter{ RawToken: token, } got, err := stg.GetIDToken(nil, oauth2.Config{}) if (err != nil) != tt.wantErr { t.Errorf("StaticTokenGetter.GetIDToken() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("StaticTokenGetter.GetIDToken() = %v, want %v", got, tt.want) } }) } } sigstore-1.8.6/pkg/oauthflow/interactive.go000066400000000000000000000152611463713551000210340ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package oauthflow import ( "context" "errors" "fmt" "io" "net" "net/http" "net/url" "os" "time" "github.com/coreos/go-oidc/v3/oidc" "github.com/segmentio/ksuid" "github.com/skratchdot/open-golang/open" "golang.org/x/oauth2" ) const oobRedirectURI = "urn:ietf:wg:oauth:2.0:oob" var browserOpener = open.Run // InteractiveIDTokenGetter is a type to get ID tokens for oauth flows type InteractiveIDTokenGetter struct { HTMLPage string ExtraAuthURLParams []oauth2.AuthCodeOption Input io.Reader Output io.Writer } // GetIDToken gets an OIDC ID Token from the specified provider using an interactive browser session func (i *InteractiveIDTokenGetter) GetIDToken(p *oidc.Provider, cfg oauth2.Config) (*OIDCIDToken, error) { // generate random fields and save them for comparison after OAuth2 dance stateToken := randStr() nonce := randStr() doneCh := make(chan string) errCh := make(chan error) // starts listener using the redirect_uri, otherwise starts on ephemeral port redirectServer, redirectURL, err := startRedirectListener(stateToken, i.HTMLPage, cfg.RedirectURL, doneCh, errCh) if err != nil { return nil, fmt.Errorf("starting redirect listener: %w", err) } defer func() { go func() { _ = redirectServer.Shutdown(context.Background()) }() }() cfg.RedirectURL = redirectURL.String() // require that OIDC provider support PKCE to provide sufficient security for the CLI pkce, err := NewPKCE(p) if err != nil { return nil, err } opts := append(pkce.AuthURLOpts(), oauth2.AccessTypeOnline, oidc.Nonce(nonce)) if len(i.ExtraAuthURLParams) > 0 { opts = append(opts, i.ExtraAuthURLParams...) } authCodeURL := cfg.AuthCodeURL(stateToken, opts...) var code string if err := browserOpener(authCodeURL); err != nil { // Swap to the out of band flow if we can't open the browser fmt.Fprintf(i.GetOutput(), "error opening browser: %v\n", err) code = i.doOobFlow(&cfg, stateToken, opts) } else { fmt.Fprintf(i.GetOutput(), "Your browser will now be opened to:\n%s\n", authCodeURL) code, err = getCode(doneCh, errCh) if err != nil { fmt.Fprintf(i.GetOutput(), "error getting code from local server: %v\n", err) code = i.doOobFlow(&cfg, stateToken, opts) } } token, err := cfg.Exchange(context.Background(), code, append(pkce.TokenURLOpts(), oidc.Nonce(nonce))...) if err != nil { return nil, err } // requesting 'openid' scope should ensure an id_token is given when exchanging the code for an access token idToken, ok := token.Extra("id_token").(string) if !ok { return nil, errors.New("id_token not present") } // verify nonce, client ID, access token hash before using it verifier := p.Verifier(&oidc.Config{ClientID: cfg.ClientID}) parsedIDToken, err := verifier.Verify(context.Background(), idToken) if err != nil { return nil, err } if parsedIDToken.Nonce != nonce { return nil, errors.New("nonce does not match value sent") } if parsedIDToken.AccessTokenHash != "" { if err := parsedIDToken.VerifyAccessToken(token.AccessToken); err != nil { return nil, err } } email, err := SubjectFromToken(parsedIDToken) if err != nil { return nil, err } returnToken := OIDCIDToken{ RawString: idToken, Subject: email, } return &returnToken, nil } func (i *InteractiveIDTokenGetter) doOobFlow(cfg *oauth2.Config, stateToken string, opts []oauth2.AuthCodeOption) string { cfg.RedirectURL = oobRedirectURI authURL := cfg.AuthCodeURL(stateToken, opts...) fmt.Fprintln(i.GetOutput(), "Go to the following link in a browser:\n\n\t", authURL) fmt.Fprintf(i.GetOutput(), "Enter verification code: ") var code string fmt.Fscanf(i.GetInput(), "%s", &code) // New line in case read input doesn't move cursor to next line. fmt.Fprintln(i.GetOutput()) return code } // GetInput returns the input reader for the token getter. If one is not set, // it defaults to stdin. func (i *InteractiveIDTokenGetter) GetInput() io.Reader { if i.Input == nil { return os.Stdin } return i.Input } // GetOutput returns the output writer for the token getter. If one is not set, // it defaults to stderr. func (i *InteractiveIDTokenGetter) GetOutput() io.Writer { if i.Output == nil { return os.Stderr } return i.Output } func startRedirectListener(state, htmlPage, redirectURL string, doneCh chan string, errCh chan error) (*http.Server, *url.URL, error) { var listener net.Listener var urlListener *url.URL var err error if redirectURL == "" { listener, err = net.Listen("tcp", "localhost:0") if err != nil { return nil, nil, err } addr, ok := listener.Addr().(*net.TCPAddr) if !ok { return nil, nil, fmt.Errorf("listener addr is not TCPAddr") } urlListener = &url.URL{ Scheme: "http", Host: fmt.Sprintf("localhost:%d", addr.Port), Path: "/auth/callback", } } else { urlListener, err = url.Parse(redirectURL) if err != nil { return nil, nil, err } listener, err = net.Listen("tcp", urlListener.Host) if err != nil { return nil, nil, err } } m := http.NewServeMux() s := &http.Server{ Addr: urlListener.Host, Handler: m, // an arbitrary reasonable value to fix gosec lint error ReadHeaderTimeout: 2 * time.Second, } m.HandleFunc(urlListener.Path, func(w http.ResponseWriter, r *http.Request) { // even though these are fetched from the FormValue method, // these are supplied as query parameters if r.FormValue("state") != state { errCh <- errors.New("invalid state token") return } doneCh <- r.FormValue("code") fmt.Fprint(w, htmlPage) }) go func() { if err := s.Serve(listener); err != nil && err != http.ErrServerClosed { errCh <- err } }() return s, urlListener, nil } func getCode(doneCh chan string, errCh chan error) (string, error) { timeoutCh := time.NewTimer(120 * time.Second) select { case code := <-doneCh: return code, nil case err := <-errCh: return "", err case <-timeoutCh.C: return "", errors.New("timeout") } } func randStr() string { // we use ksuid here to ensure we get globally unique values to mitigate // risk of replay attacks // output is a 27 character base62 string which is by default URL-safe return ksuid.New().String() } sigstore-1.8.6/pkg/oauthflow/interactive_test.go000066400000000000000000000022161463713551000220670ustar00rootroot00000000000000// 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 oauthflow import ( "bytes" "os" "testing" ) func TestInteractiveFlow_IO(t *testing.T) { t.Run("default", func(t *testing.T) { f := &InteractiveIDTokenGetter{} if f.GetInput() != os.Stdin { t.Error("expected stdin") } if f.GetOutput() != os.Stderr { t.Error("expected stderr") } }) t.Run("buffer", func(t *testing.T) { b := new(bytes.Buffer) f := &InteractiveIDTokenGetter{ Input: b, Output: b, } if f.GetInput() != b { t.Error("expected buffer") } if f.GetOutput() != b { t.Error("expected buffer") } }) } sigstore-1.8.6/pkg/oauthflow/pkce.go000066400000000000000000000071501463713551000174370ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package oauthflow import ( "crypto/sha256" "encoding/base64" "fmt" "regexp" "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) const ( // PKCES256 is the SHA256 option required by the PKCE RFC PKCES256 = "S256" ) // PKCE specifies the challenge and value pair required to fulfill RFC7636 type PKCE struct { Challenge string Method string Value string } // NewPKCE creates a new PKCE challenge for the specified provider per its supported methods (obtained through OIDC discovery endpoint) func NewPKCE(provider *oidc.Provider) (*PKCE, error) { var providerClaims struct { CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` } if err := provider.Claims(&providerClaims); err != nil { // will only error out if the JSON was malformed, which shouldn't happen at this point return nil, err } var chosenMethod string for _, method := range providerClaims.CodeChallengeMethodsSupported { // per RFC7636, any server that supports PKCE must support S256 if method == PKCES256 && chosenMethod != PKCES256 { chosenMethod = PKCES256 break } else if method != "plain" { fmt.Printf("Unsupported code challenge method in list: '%v'", method) } } if chosenMethod == "" { if providerIsAzureBacked(provider) { chosenMethod = PKCES256 } else { return nil, fmt.Errorf("PKCE is not supported by OIDC provider '%v'", provider.Endpoint().AuthURL) } } // we use two 27 character strings to meet requirements of RFC 7636: // (minimum length of 43 characters and a maximum length of 128 characters) value := randStr() + randStr() h := sha256.New() _, _ = h.Write([]byte(value)) challenge := base64.RawURLEncoding.EncodeToString(h.Sum(nil)) return &PKCE{ Challenge: challenge, Method: chosenMethod, Value: value, }, nil } // AuthURLOpts returns the set of request parameters required during the initial exchange of the OAuth2 flow func (p *PKCE) AuthURLOpts() []oauth2.AuthCodeOption { return []oauth2.AuthCodeOption{ oauth2.SetAuthURLParam("code_challenge_method", p.Method), oauth2.SetAuthURLParam("code_challenge", p.Challenge), } } // TokenURLOpts returns the set of request parameters required during the token request exchange flow func (p *PKCE) TokenURLOpts() []oauth2.AuthCodeOption { return []oauth2.AuthCodeOption{ oauth2.SetAuthURLParam("code_verifier", p.Value), } } var azureregex = regexp.MustCompile(`^https:\/\/login\.microsoftonline\.(com|us)\/`) // providerIsAzureBacked returns a boolean indicating whether the provider is Azure-backed; // Azure supports PKCE but does not advertise it in their OIDC discovery endpoint func providerIsAzureBacked(p *oidc.Provider) bool { // Per https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud#azure-ad-authentication-endpoints // if endpoint starts with any of these strings then we should attempt PKCE anyway as their OIDC discovery doc // does not advertise supporting PKCE but they actually do return p != nil && azureregex.MatchString(p.Endpoint().AuthURL) } sigstore-1.8.6/pkg/oauthflow/pkce_test.go000066400000000000000000000033761463713551000205040ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package oauthflow import ( "context" "fmt" "testing" "github.com/coreos/go-oidc/v3/oidc" ) func TestProviderIsAzureBacked(t *testing.T) { actualAzureProviders := []string{ "https://login.microsoftonline.com/6babcaad-604b-40ac-a9d7-9fd97c0b779f/v2.0", } notAzureProviders := []string{ "https://accounts.google.com", "https://login.salesforce.com", } for _, tc := range actualAzureProviders { t.Run(fmt.Sprintf("testing azure provider %v", tc), func(t *testing.T) { p, err := oidc.NewProvider(context.Background(), tc) if err != nil { t.Error(err) } if !providerIsAzureBacked(p) { t.Errorf("valid azure provider URL %v was not detected as being azure backed", tc) } }) } for _, tc := range notAzureProviders { t.Run(fmt.Sprintf("testing invalid azure provider %v", tc), func(t *testing.T) { p, err := oidc.NewProvider(context.Background(), tc) if err != nil { t.Error(err) } if providerIsAzureBacked(p) { t.Errorf("invalid azure provider URL %v was detected as being azure backed", tc) } }) } if providerIsAzureBacked(nil) != false { t.Errorf("nil provider should not return true for being Azure-backed") } } sigstore-1.8.6/pkg/signature/000077500000000000000000000000001463713551000161545ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/doc.go000066400000000000000000000012761463713551000172560ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package signature contains types and utilities related to Sigstore signatures. package signature sigstore-1.8.6/pkg/signature/dsse/000077500000000000000000000000001463713551000171125ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/dsse/adapters.go000066400000000000000000000047501463713551000212520ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package dsse includes wrappers to support DSSE package dsse import ( "bytes" "context" "crypto" "errors" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" ) // SignerAdapter wraps a `sigstore/signature.Signer`, making it compatible with `go-securesystemslib/dsse.Signer`. type SignerAdapter struct { SignatureSigner signature.Signer Pub crypto.PublicKey Opts []signature.SignOption PubKeyID string } // Sign implements `go-securesystemslib/dsse.Signer` func (a *SignerAdapter) Sign(ctx context.Context, data []byte) ([]byte, error) { return a.SignatureSigner.SignMessage(bytes.NewReader(data), append(a.Opts, options.WithContext(ctx))...) } // Verify disabled `go-securesystemslib/dsse.Verifier` func (a *SignerAdapter) Verify(_ context.Context, _, _ []byte) error { return errors.New("Verify disabled") } // Public implements `go-securesystemslib/dsse.Verifier` func (a *SignerAdapter) Public() crypto.PublicKey { return a.Pub } // KeyID implements `go-securesystemslib/dsse.Verifier` func (a SignerAdapter) KeyID() (string, error) { return a.PubKeyID, nil } // VerifierAdapter wraps a `sigstore/signature.Verifier`, making it compatible with `go-securesystemslib/dsse.Verifier`. type VerifierAdapter struct { SignatureVerifier signature.Verifier Pub crypto.PublicKey PubKeyID string } // Verify implements `go-securesystemslib/dsse.Verifier` func (a *VerifierAdapter) Verify(ctx context.Context, data, sig []byte) error { return a.SignatureVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithContext(ctx)) } // Public implements `go-securesystemslib/dsse.Verifier` func (a *VerifierAdapter) Public() crypto.PublicKey { return a.Pub } // KeyID implements `go-securesystemslib/dsse.Verifier` func (a *VerifierAdapter) KeyID() (string, error) { return a.PubKeyID, nil } sigstore-1.8.6/pkg/signature/dsse/adapters_test.go000066400000000000000000000021471463713551000223070ustar00rootroot00000000000000// // 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 dsse import ( "testing" "github.com/secure-systems-lab/go-securesystemslib/dsse" ) // TestImplementDSSESigner doesn't functionally test anything, but will fail to compile if the interface is not implemented func TestImplementsDSSESigner(_ *testing.T) { var _ dsse.Signer = &SignerAdapter{} } // TestImplementDSSEVerifier doesn't functionally test anything, but will fail to compile if the interface is not implemented func TestImplementsDSSEVerifier(_ *testing.T) { var _ dsse.Verifier = &VerifierAdapter{} } sigstore-1.8.6/pkg/signature/dsse/doc.go000066400000000000000000000012531463713551000202070ustar00rootroot00000000000000// // 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 dsse contains handlers for Dead Simple Signing Envelopes package dsse sigstore-1.8.6/pkg/signature/dsse/dsse.go000066400000000000000000000101231463713551000203740ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package dsse import ( "bytes" "context" "crypto" "encoding/base64" "encoding/json" "io" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/sigstore/pkg/signature" ) // WrapSigner returns a signature.Signer that uses the DSSE encoding format func WrapSigner(s signature.Signer, payloadType string) signature.Signer { return &wrappedSigner{ s: s, payloadType: payloadType, } } type wrappedSigner struct { s signature.Signer payloadType string } // PublicKey returns the public key associated with the signer func (w *wrappedSigner) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { return w.s.PublicKey(opts...) } // SignMessage signs the provided stream in the reader using the DSSE encoding format func (w *wrappedSigner) SignMessage(r io.Reader, opts ...signature.SignOption) ([]byte, error) { p, err := io.ReadAll(r) if err != nil { return nil, err } pae := dsse.PAE(w.payloadType, p) sig, err := w.s.SignMessage(bytes.NewReader(pae), opts...) if err != nil { return nil, err } env := dsse.Envelope{ PayloadType: w.payloadType, Payload: base64.StdEncoding.EncodeToString(p), Signatures: []dsse.Signature{ { Sig: base64.StdEncoding.EncodeToString(sig), }, }, } return json.Marshal(env) } // WrapVerifier returns a signature.Verifier that uses the DSSE encoding format func WrapVerifier(v signature.Verifier) signature.Verifier { return &wrappedVerifier{ v: v, } } type wrappedVerifier struct { v signature.Verifier } // PublicKey returns the public key associated with the verifier func (w *wrappedVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { return w.v.PublicKey(opts...) } // VerifySignature verifies the signature specified in an DSSE envelope func (w *wrappedVerifier) VerifySignature(s, _ io.Reader, _ ...signature.VerifyOption) error { sig, err := io.ReadAll(s) if err != nil { return err } env := dsse.Envelope{} if err := json.Unmarshal(sig, &env); err != nil { return err } pub, err := w.PublicKey() if err != nil { return err } verifier, err := dsse.NewEnvelopeVerifier(&VerifierAdapter{ SignatureVerifier: w.v, Pub: pub, PubKeyID: "", // We do not want to limit verification to a specific key. }) if err != nil { return err } _, err = verifier.Verify(context.Background(), &env) return err } // WrapSignerVerifier returns a signature.SignerVerifier that uses the DSSE encoding format func WrapSignerVerifier(sv signature.SignerVerifier, payloadType string) signature.SignerVerifier { signer := &wrappedSigner{ payloadType: payloadType, s: sv, } verifier := &wrappedVerifier{ v: sv, } return &wrappedSignerVerifier{ signer: signer, verifier: verifier, } } type wrappedSignerVerifier struct { signer *wrappedSigner verifier *wrappedVerifier } // PublicKey returns the public key associated with the verifier func (w *wrappedSignerVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { return w.signer.PublicKey(opts...) } // VerifySignature verifies the signature specified in an DSSE envelope func (w *wrappedSignerVerifier) VerifySignature(s, r io.Reader, opts ...signature.VerifyOption) error { return w.verifier.VerifySignature(s, r, opts...) } // SignMessage signs the provided stream in the reader using the DSSE encoding format func (w *wrappedSignerVerifier) SignMessage(r io.Reader, opts ...signature.SignOption) ([]byte, error) { return w.signer.SignMessage(r, opts...) } sigstore-1.8.6/pkg/signature/dsse/dsse_test.go000066400000000000000000000100321463713551000214320ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package dsse import ( "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "encoding/base64" "encoding/json" "strings" "testing" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/sigstore/pkg/signature" ) func TestRoundTrip(t *testing.T) { p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } sv, err := signature.LoadECDSASignerVerifier(p, crypto.SHA256) if err != nil { t.Fatal(err) } data := "sometestdata" payloadType := "foo" wsv := WrapSignerVerifier(sv, payloadType) sig, err := wsv.SignMessage(strings.NewReader(data)) if err != nil { t.Fatal(err) } if err := wsv.VerifySignature(bytes.NewReader(sig), nil); err != nil { t.Fatal(err) } env := dsse.Envelope{} if err := json.Unmarshal(sig, &env); err != nil { t.Fatal(err) } if env.PayloadType != payloadType { t.Errorf("Expected payloadType %s, got %s", payloadType, env.PayloadType) } got, err := base64.StdEncoding.DecodeString(env.Payload) if err != nil { t.Fatal(err) } if string(got) != data { t.Errorf("Expected payload %s, got %s", data, env.Payload) } } func TestMultiRoundTrip(t *testing.T) { p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } sv, err := signature.LoadECDSASignerVerifier(p, crypto.SHA256) if err != nil { t.Fatal(err) } p2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } sv2, err := signature.LoadECDSASignerVerifier(p2, crypto.SHA256) if err != nil { t.Fatal(err) } data := "sometestdata" payloadType := "foo" wsv := WrapMultiSignerVerifier(payloadType, 2, sv, sv2) sig, err := wsv.SignMessage(strings.NewReader(data)) if err != nil { t.Fatal(err) } if err := wsv.VerifySignature(bytes.NewReader(sig), nil); err != nil { t.Fatal(err) } env := dsse.Envelope{} if err := json.Unmarshal(sig, &env); err != nil { t.Fatal(err) } if env.PayloadType != payloadType { t.Errorf("Expected payloadType %s, got %s", payloadType, env.PayloadType) } got, err := base64.StdEncoding.DecodeString(env.Payload) if err != nil { t.Fatal(err) } if string(got) != data { t.Errorf("Expected payload %s, got %s", data, env.Payload) } } func TestInvalidThresholdMultiRoundTrip(t *testing.T) { p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } sv, err := signature.LoadECDSASignerVerifier(p, crypto.SHA256) if err != nil { t.Fatal(err) } p2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } sv2, err := signature.LoadECDSASignerVerifier(p2, crypto.SHA256) if err != nil { t.Fatal(err) } data := "sometestdata" payloadType := "foo" ws := WrapMultiSigner(payloadType, sv, sv2) sig, err := ws.SignMessage(strings.NewReader(data)) if err != nil { t.Fatal(err) } wv := WrapMultiVerifier(payloadType, 2, sv) if err := wv.VerifySignature(bytes.NewReader(sig), nil); err == nil { t.Fatalf("Did not fail verification on bogus signature") } } func TestInvalidSignature(t *testing.T) { p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } v, err := signature.LoadECDSAVerifier(&p.PublicKey, crypto.SHA256) if err != nil { t.Fatal(err) } wv := WrapVerifier(v) sig := []byte("not valid JSON") if err := wv.VerifySignature(bytes.NewReader(sig), nil); err == nil { t.Fatalf("Did not fail verification on bogus signature") } } sigstore-1.8.6/pkg/signature/dsse/multidsse.go000066400000000000000000000123421463713551000214540ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package dsse import ( "context" "crypto" "encoding/json" "errors" "io" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/sigstore/pkg/signature" ) type wrappedMultiSigner struct { sLAdapters []dsse.Signer payloadType string } // WrapMultiSigner returns a signature.Signer that uses the DSSE encoding format func WrapMultiSigner(payloadType string, sL ...signature.Signer) signature.Signer { signerAdapterL := make([]dsse.Signer, 0, len(sL)) for _, s := range sL { pub, err := s.PublicKey() if err != nil { return nil } keyID, err := dsse.SHA256KeyID(pub) if err != nil { keyID = "" } signerAdapter := &SignerAdapter{ SignatureSigner: s, Pub: s.PublicKey, PubKeyID: keyID, // We do not want to limit verification to a specific key. } signerAdapterL = append(signerAdapterL, signerAdapter) } return &wrappedMultiSigner{ sLAdapters: signerAdapterL, payloadType: payloadType, } } // PublicKey returns the public key associated with the signer func (wL *wrappedMultiSigner) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { return nil, errors.New("not supported for multi signatures") } // SignMessage signs the provided stream in the reader using the DSSE encoding format func (wL *wrappedMultiSigner) SignMessage(r io.Reader, _ ...signature.SignOption) ([]byte, error) { p, err := io.ReadAll(r) if err != nil { return nil, err } envSigner, err := dsse.NewEnvelopeSigner(wL.sLAdapters...) if err != nil { return nil, err } env, err := envSigner.SignPayload(context.Background(), wL.payloadType, p) if err != nil { return nil, err } return json.Marshal(env) } type wrappedMultiVerifier struct { vLAdapters []dsse.Verifier threshold int payloadType string } // WrapMultiVerifier returns a signature.Verifier that uses the DSSE encoding format func WrapMultiVerifier(payloadType string, threshold int, vL ...signature.Verifier) signature.Verifier { verifierAdapterL := make([]dsse.Verifier, 0, len(vL)) for _, v := range vL { pub, err := v.PublicKey() if err != nil { return nil } keyID, err := dsse.SHA256KeyID(pub) if err != nil { keyID = "" } verifierAdapter := &VerifierAdapter{ SignatureVerifier: v, Pub: v.PublicKey, PubKeyID: keyID, // We do not want to limit verification to a specific key. } verifierAdapterL = append(verifierAdapterL, verifierAdapter) } return &wrappedMultiVerifier{ vLAdapters: verifierAdapterL, payloadType: payloadType, threshold: threshold, } } // PublicKey returns the public key associated with the signer func (wL *wrappedMultiVerifier) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { return nil, errors.New("not supported for multi signatures") } // VerifySignature verifies the signature specified in an DSSE envelope func (wL *wrappedMultiVerifier) VerifySignature(s, _ io.Reader, _ ...signature.VerifyOption) error { sig, err := io.ReadAll(s) if err != nil { return err } env := dsse.Envelope{} if err := json.Unmarshal(sig, &env); err != nil { return err } envVerifier, err := dsse.NewMultiEnvelopeVerifier(wL.threshold, wL.vLAdapters...) if err != nil { return err } _, err = envVerifier.Verify(context.Background(), &env) return err } // WrapMultiSignerVerifier returns a signature.SignerVerifier that uses the DSSE encoding format func WrapMultiSignerVerifier(payloadType string, threshold int, svL ...signature.SignerVerifier) signature.SignerVerifier { signerL := make([]signature.Signer, 0, len(svL)) verifierL := make([]signature.Verifier, 0, len(svL)) for _, sv := range svL { signerL = append(signerL, sv) verifierL = append(verifierL, sv) } sL := WrapMultiSigner(payloadType, signerL...) vL := WrapMultiVerifier(payloadType, threshold, verifierL...) return &wrappedMultiSignerVerifier{ signer: sL, verifier: vL, } } type wrappedMultiSignerVerifier struct { signer signature.Signer verifier signature.Verifier } // PublicKey returns the public key associated with the verifier func (w *wrappedMultiSignerVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { return w.signer.PublicKey(opts...) } // VerifySignature verifies the signature specified in an DSSE envelope func (w *wrappedMultiSignerVerifier) VerifySignature(s, r io.Reader, opts ...signature.VerifyOption) error { return w.verifier.VerifySignature(s, r, opts...) } // SignMessage signs the provided stream in the reader using the DSSE encoding format func (w *wrappedMultiSignerVerifier) SignMessage(r io.Reader, opts ...signature.SignOption) ([]byte, error) { return w.signer.SignMessage(r, opts...) } sigstore-1.8.6/pkg/signature/ecdsa.go000066400000000000000000000206441463713551000175700ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "encoding/asn1" "errors" "fmt" "io" "math/big" "github.com/sigstore/sigstore/pkg/signature/options" ) // checked on LoadSigner, LoadVerifier and SignMessage var ecdsaSupportedHashFuncs = []crypto.Hash{ crypto.SHA256, crypto.SHA512, crypto.SHA384, crypto.SHA224, } // checked on VerifySignature. Supports SHA1 verification. var ecdsaSupportedVerifyHashFuncs = []crypto.Hash{ crypto.SHA256, crypto.SHA512, crypto.SHA384, crypto.SHA224, crypto.SHA1, } // ECDSASigner is a signature.Signer that uses an Elliptic Curve DSA algorithm type ECDSASigner struct { hashFunc crypto.Hash priv *ecdsa.PrivateKey } // LoadECDSASigner calculates signatures using the specified private key and hash algorithm. // // hf must not be crypto.Hash(0). func LoadECDSASigner(priv *ecdsa.PrivateKey, hf crypto.Hash) (*ECDSASigner, error) { if priv == nil { return nil, errors.New("invalid ECDSA private key specified") } if !isSupportedAlg(hf, ecdsaSupportedHashFuncs) { return nil, errors.New("invalid hash function specified") } return &ECDSASigner{ priv: priv, hashFunc: hf, }, nil } // SignMessage signs the provided message. If the message is provided, // this method will compute the digest according to the hash function specified // when the ECDSASigner was created. // // This function recognizes the following Options listed in order of preference: // // - WithRand() // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (e ECDSASigner) SignMessage(message io.Reader, opts ...SignOption) ([]byte, error) { digest, _, err := ComputeDigestForSigning(message, e.hashFunc, ecdsaSupportedHashFuncs, opts...) if err != nil { return nil, err } rand := selectRandFromOpts(opts...) return ecdsa.SignASN1(rand, e.priv, digest) } // Public returns the public key that can be used to verify signatures created by // this signer. func (e ECDSASigner) Public() crypto.PublicKey { if e.priv == nil { return nil } return e.priv.Public() } // PublicKey returns the public key that can be used to verify signatures created by // this signer. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ECDSASigner) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.Public(), nil } // Sign computes the signature for the specified digest. If a source of entropy is // given in rand, it will be used instead of the default value (rand.Reader from crypto/rand). // // If opts are specified, the hash function in opts.Hash should be the one used to compute // digest. If opts are not specified, the value provided when the signer was created will be used instead. func (e ECDSASigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { ecdsaOpts := []SignOption{options.WithDigest(digest), options.WithRand(rand)} if opts != nil { ecdsaOpts = append(ecdsaOpts, options.WithCryptoSignerOpts(opts)) } return e.SignMessage(nil, ecdsaOpts...) } // ECDSAVerifier is a signature.Verifier that uses an Elliptic Curve DSA algorithm type ECDSAVerifier struct { publicKey *ecdsa.PublicKey hashFunc crypto.Hash } // LoadECDSAVerifier returns a Verifier that verifies signatures using the specified // ECDSA public key and hash algorithm. // // hf must not be crypto.Hash(0). func LoadECDSAVerifier(pub *ecdsa.PublicKey, hashFunc crypto.Hash) (*ECDSAVerifier, error) { if pub == nil { return nil, errors.New("invalid ECDSA public key specified") } if !isSupportedAlg(hashFunc, ecdsaSupportedHashFuncs) { return nil, errors.New("invalid hash function specified") } return &ECDSAVerifier{ publicKey: pub, hashFunc: hashFunc, }, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ECDSAVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.publicKey, nil } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the ECDSAVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (e ECDSAVerifier) VerifySignature(signature, message io.Reader, opts ...VerifyOption) error { if e.publicKey == nil { return errors.New("no public key set for ECDSAVerifier") } digest, _, err := ComputeDigestForVerifying(message, e.hashFunc, ecdsaSupportedVerifyHashFuncs, opts...) if err != nil { return err } if signature == nil { return errors.New("nil signature passed to VerifySignature") } sigBytes, err := io.ReadAll(signature) if err != nil { return fmt.Errorf("reading signature: %w", err) } // Without this check, VerifyASN1 panics on an invalid key. if !e.publicKey.Curve.IsOnCurve(e.publicKey.X, e.publicKey.Y) { return fmt.Errorf("invalid ECDSA public key for %s", e.publicKey.Params().Name) } asnParseTest := struct { R, S *big.Int }{} if _, err := asn1.Unmarshal(sigBytes, &asnParseTest); err == nil { if !ecdsa.VerifyASN1(e.publicKey, digest, sigBytes) { return errors.New("invalid signature when validating ASN.1 encoded signature") } } else { // deal with IEEE P1363 encoding of signatures if len(sigBytes) == 0 || len(sigBytes) > 132 || len(sigBytes)%2 != 0 { return errors.New("ecdsa: Invalid IEEE_P1363 encoded bytes") } r := new(big.Int).SetBytes(sigBytes[:len(sigBytes)/2]) s := new(big.Int).SetBytes(sigBytes[len(sigBytes)/2:]) if !ecdsa.Verify(e.publicKey, digest, r, s) { return errors.New("invalid signature when validating IEEE_P1363 encoded signature") } } return nil } // ECDSASignerVerifier is a signature.SignerVerifier that uses an Elliptic Curve DSA algorithm type ECDSASignerVerifier struct { *ECDSASigner *ECDSAVerifier } // LoadECDSASignerVerifier creates a combined signer and verifier. This is a convenience object // that simply wraps an instance of ECDSASigner and ECDSAVerifier. func LoadECDSASignerVerifier(priv *ecdsa.PrivateKey, hf crypto.Hash) (*ECDSASignerVerifier, error) { signer, err := LoadECDSASigner(priv, hf) if err != nil { return nil, fmt.Errorf("initializing signer: %w", err) } verifier, err := LoadECDSAVerifier(&priv.PublicKey, hf) if err != nil { return nil, fmt.Errorf("initializing verifier: %w", err) } return &ECDSASignerVerifier{ ECDSASigner: signer, ECDSAVerifier: verifier, }, nil } // NewDefaultECDSASignerVerifier creates a combined signer and verifier using ECDSA. // // This creates a new ECDSA key using the P-256 curve and uses the SHA256 hashing algorithm. func NewDefaultECDSASignerVerifier() (*ECDSASignerVerifier, *ecdsa.PrivateKey, error) { return NewECDSASignerVerifier(elliptic.P256(), rand.Reader, crypto.SHA256) } // NewECDSASignerVerifier creates a combined signer and verifier using ECDSA. // // This creates a new ECDSA key using the specified elliptic curve, entropy source, and hashing function. func NewECDSASignerVerifier(curve elliptic.Curve, rand io.Reader, hashFunc crypto.Hash) (*ECDSASignerVerifier, *ecdsa.PrivateKey, error) { priv, err := ecdsa.GenerateKey(curve, rand) if err != nil { return nil, nil, err } sv, err := LoadECDSASignerVerifier(priv, hashFunc) if err != nil { return nil, nil, err } return sv, priv, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ECDSASignerVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.publicKey, nil } sigstore-1.8.6/pkg/signature/ecdsa_test.go000066400000000000000000000120261463713551000206220ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "encoding/base64" "fmt" "math/big" "strings" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) // Generated with: // openssl ecparam -genkey -name prime256v1 > ec_private.pem // openssl pkcs8 -topk8 -in ec_private.pem -nocrypt const ecdsaPriv = `-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmrLtCpBdXgXLUr7o nSUPfo3oXMjmvuwTOjpTulIBKlKhRANCAATH6KSpTFe6uXFmW1qNEFXaO7fWPfZt pPZrHZ1cFykidZoURKoYXfkohJ+U/USYy8Sd8b4DMd5xDRZCnlDM0h37 -----END PRIVATE KEY-----` // Extracted from above with: // openssl ec -in ec_private.pem -pubout const ecdsaPub = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEx+ikqUxXurlxZltajRBV2ju31j32 baT2ax2dXBcpInWaFESqGF35KISflP1EmMvEnfG+AzHecQ0WQp5QzNId+w== -----END PUBLIC KEY-----` func TestECDSASignerVerifier(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ecdsaPriv), cryptoutils.SkipPassword) if err != nil { t.Errorf("unexpected error unmarshalling private key: %v", err) } sv, err := LoadECDSASignerVerifier(privateKey.(*ecdsa.PrivateKey), crypto.SHA256) if err != nil { t.Errorf("unexpected error creating signer/verifier: %v", err) } message := []byte("sign me") // created with openssl dgst -sign privKey.pem -sha256 sig, _ := base64.StdEncoding.DecodeString("MEQCIGvnAsUT6P4PoJoKxP331ZFU2LfzxnuvulK14Rl3zNKIAiBJCSA7NdmAZkLNqxmWnbBp8ntJYVZmUR0Tbmv6ftS8ww==") testingSigner(t, sv, "ecdsa", crypto.SHA256, message) testingVerifier(t, sv, "ecdsa", crypto.SHA256, sig, message) publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ecdsaPub)) if err != nil { t.Errorf("unexpected error unmarshalling public key: %v", err) } v, err := LoadECDSAVerifier(publicKey.(*ecdsa.PublicKey), crypto.SHA256) if err != nil { t.Errorf("unexpected error creating verifier: %v", err) } testingVerifier(t, v, "ecdsa", crypto.SHA256, sig, message) // test IEEE P1363 encoded signature // created via // import "github.com/tink-crypto/tink-go/signature/subtle" // subtle.NewECDSASignerFromPrivateKey("SHA256", "IEEE_P1363", privKey.(*ecdsa.PrivateKey)) ieeeSig, _ := base64.StdEncoding.DecodeString("bmvQGbNZEJyS3HAVPiuXY0/BGFcUq5cl22v3+sttMxBls5LO0W52qR2yk6q0E59wDNs15gvaODeTZ2d6MwH9OQ==") testingVerifier(t, v, "ecdsa", crypto.SHA256, ieeeSig, message) } func TestECDSASignerVerifierUnsupportedHash(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ecdsaPriv), cryptoutils.SkipPassword) if err != nil { t.Errorf("unexpected error unmarshalling private key: %v", err) } publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ecdsaPub)) if err != nil { t.Errorf("unexpected error unmarshalling public key key: %v", err) } _, err = LoadECDSASigner(privateKey.(*ecdsa.PrivateKey), crypto.SHA1) if !strings.Contains(err.Error(), "invalid hash function specified") { t.Errorf("expected error 'invalid hash function specified', got: %v", err.Error()) } _, err = LoadECDSAVerifier(publicKey.(*ecdsa.PublicKey), crypto.SHA1) if !strings.Contains(err.Error(), "invalid hash function specified") { t.Errorf("expected error 'invalid hash function specified', got: %v", err.Error()) } } func TestECDSALoadVerifierWithoutKey(t *testing.T) { key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) v, err := LoadECDSAVerifier(&key.PublicKey, crypto.SHA256) if err != nil { t.Fatalf("error creating verifier: %v", err) } v.publicKey = nil if err := v.VerifySignature(nil, nil); err == nil || !strings.Contains(err.Error(), "no public key") { t.Fatalf("expected error without public key, got: %v", err) } } // TestECDSALoadVerifierInvalidCurve tests gracefully handling an invalid curve. func TestECDSALoadVerifierInvalidCurve(t *testing.T) { data := []byte{1} x := ecdsa.PrivateKey{} z := new(big.Int) z.SetBytes(data) x.X = z x.Y = z x.D = z x.Curve = elliptic.P256() verifier, err := LoadECDSAVerifier(&x.PublicKey, crypto.SHA256) if err != nil { t.Fatalf("unexpected error loading verifier: %v", err) } msg := []byte("hello") digest := sha256.Sum256(msg) sig, err := ecdsa.SignASN1(rand.Reader, &x, digest[:]) if err != nil { fmt.Println(err) } if err := verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(msg)); err == nil || !strings.Contains(err.Error(), "invalid ECDSA public key") { t.Fatalf("expected error verifying signature with invalid curve, got %v", err) } } sigstore-1.8.6/pkg/signature/ed25519.go000066400000000000000000000142071463713551000175050ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "bytes" "crypto" "crypto/ed25519" "crypto/rand" "errors" "fmt" "io" ) var ed25519SupportedHashFuncs = []crypto.Hash{ crypto.Hash(0), } // ED25519Signer is a signature.Signer that uses the Ed25519 public-key signature system type ED25519Signer struct { priv ed25519.PrivateKey } // LoadED25519Signer calculates signatures using the specified private key. func LoadED25519Signer(priv ed25519.PrivateKey) (*ED25519Signer, error) { if priv == nil { return nil, errors.New("invalid ED25519 private key specified") } // check this to avoid panic and throw error gracefully if len(priv) != ed25519.PrivateKeySize { return nil, errors.New("invalid size for ED25519 key") } return &ED25519Signer{ priv: priv, }, nil } // SignMessage signs the provided message. Passing the WithDigest option is not // supported as ED25519 performs a two pass hash over the message during the // signing process. // // All options are ignored. func (e ED25519Signer) SignMessage(message io.Reader, _ ...SignOption) ([]byte, error) { messageBytes, _, err := ComputeDigestForSigning(message, crypto.Hash(0), ed25519SupportedHashFuncs) if err != nil { return nil, err } return ed25519.Sign(e.priv, messageBytes), nil } // Public returns the public key that can be used to verify signatures created by // this signer. func (e ED25519Signer) Public() crypto.PublicKey { if e.priv == nil { return nil } return e.priv.Public() } // PublicKey returns the public key that can be used to verify signatures created by // this signer. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ED25519Signer) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.Public(), nil } // Sign computes the signature for the specified message; the first and third arguments to this // function are ignored as they are not used by the ED25519 algorithm. func (e ED25519Signer) Sign(_ io.Reader, message []byte, _ crypto.SignerOpts) ([]byte, error) { if message == nil { return nil, errors.New("message must not be nil") } return e.SignMessage(bytes.NewReader(message)) } // ED25519Verifier is a signature.Verifier that uses the Ed25519 public-key signature system type ED25519Verifier struct { publicKey ed25519.PublicKey } // LoadED25519Verifier returns a Verifier that verifies signatures using the specified ED25519 public key. func LoadED25519Verifier(pub ed25519.PublicKey) (*ED25519Verifier, error) { if pub == nil { return nil, errors.New("invalid ED25519 public key specified") } return &ED25519Verifier{ publicKey: pub, }, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e *ED25519Verifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.publicKey, nil } // VerifySignature verifies the signature for the given message. // // This function returns nil if the verification succeeded, and an error message otherwise. // // All options are ignored if specified. func (e *ED25519Verifier) VerifySignature(signature, message io.Reader, _ ...VerifyOption) error { messageBytes, _, err := ComputeDigestForVerifying(message, crypto.Hash(0), ed25519SupportedHashFuncs) if err != nil { return err } if signature == nil { return errors.New("nil signature passed to VerifySignature") } sigBytes, err := io.ReadAll(signature) if err != nil { return fmt.Errorf("reading signature: %w", err) } if !ed25519.Verify(e.publicKey, messageBytes, sigBytes) { return errors.New("failed to verify signature") } return nil } // ED25519SignerVerifier is a signature.SignerVerifier that uses the Ed25519 public-key signature system type ED25519SignerVerifier struct { *ED25519Signer *ED25519Verifier } // LoadED25519SignerVerifier creates a combined signer and verifier. This is // a convenience object that simply wraps an instance of ED25519Signer and ED25519Verifier. func LoadED25519SignerVerifier(priv ed25519.PrivateKey) (*ED25519SignerVerifier, error) { signer, err := LoadED25519Signer(priv) if err != nil { return nil, fmt.Errorf("initializing signer: %w", err) } pub, ok := priv.Public().(ed25519.PublicKey) if !ok { return nil, fmt.Errorf("given key is not ed25519.PublicKey") } verifier, err := LoadED25519Verifier(pub) if err != nil { return nil, fmt.Errorf("initializing verifier: %w", err) } return &ED25519SignerVerifier{ ED25519Signer: signer, ED25519Verifier: verifier, }, nil } // NewDefaultED25519SignerVerifier creates a combined signer and verifier using ED25519. // This creates a new ED25519 key using crypto/rand as an entropy source. func NewDefaultED25519SignerVerifier() (*ED25519SignerVerifier, ed25519.PrivateKey, error) { return NewED25519SignerVerifier(rand.Reader) } // NewED25519SignerVerifier creates a combined signer and verifier using ED25519. // This creates a new ED25519 key using the specified entropy source. func NewED25519SignerVerifier(rand io.Reader) (*ED25519SignerVerifier, ed25519.PrivateKey, error) { _, priv, err := ed25519.GenerateKey(rand) if err != nil { return nil, nil, err } sv, err := LoadED25519SignerVerifier(priv) if err != nil { return nil, nil, err } return sv, priv, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ED25519SignerVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.publicKey, nil } sigstore-1.8.6/pkg/signature/ed25519_test.go000066400000000000000000000054601463713551000205450ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/ed25519" "encoding/base64" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) // Generated with: // openssl genpkey -algorithm ed25519 -outform PEM -out - const ed25519Priv = `-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIFP9CZb6J1DiOLfdIkPfy1bwBOCjEG6KR/cIdhw90J1H -----END PRIVATE KEY-----` // Extracted from above with: // openssl ec -in ec_private.pem -pubout const ed25519Pub = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA9wy4umF4RHQ8UQXo8fzEQNBWE4GsBMkCzQPAfHvkf/s= -----END PUBLIC KEY-----` func TestED25519SignerVerifier(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ed25519Priv), cryptoutils.SkipPassword) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPriv, ok := privateKey.(ed25519.PrivateKey) if !ok { t.Fatalf("expected ed25519.PrivateKey") } sv, err := LoadED25519SignerVerifier(edPriv) if err != nil { t.Fatalf("unexpected error creating signer/verifier: %v", err) } message := []byte("sign me") sig, _ := base64.StdEncoding.DecodeString("cnafwd8DKq2nQ564eN66ckYV8anVFGFi5vaYiQg2aal7ej/J0/OE0PPdKHLHe9wdzWRMFy5MpurRD/2cGXGLBQ==") testingSigner(t, sv, "ed25519", crypto.SHA256, message) testingVerifier(t, sv, "ed25519", crypto.SHA256, sig, message) pub, err := sv.PublicKey() if err != nil { t.Fatalf("unexpected error from PublicKey(): %v", err) } assertPublicKeyIsx509Marshalable(t, pub) } func TestED25519Verifier(t *testing.T) { publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ed25519Pub)) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPub, ok := publicKey.(ed25519.PublicKey) if !ok { t.Fatalf("public key is not ed25519") } v, err := LoadED25519Verifier(edPub) if err != nil { t.Fatalf("unexpected error creating verifier: %v", err) } message := []byte("sign me") sig, _ := base64.StdEncoding.DecodeString("cnafwd8DKq2nQ564eN66ckYV8anVFGFi5vaYiQg2aal7ej/J0/OE0PPdKHLHe9wdzWRMFy5MpurRD/2cGXGLBQ==") testingVerifier(t, v, "ed25519", crypto.SHA256, sig, message) pub, err := v.PublicKey() if err != nil { t.Fatalf("unexpected error from PublicKey(): %v", err) } assertPublicKeyIsx509Marshalable(t, pub) } sigstore-1.8.6/pkg/signature/ed25519ph.go000066400000000000000000000160311463713551000200320ustar00rootroot00000000000000// // Copyright 2024 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 signature import ( "crypto" "crypto/ed25519" "crypto/rand" "errors" "fmt" "io" "github.com/sigstore/sigstore/pkg/signature/options" ) var ed25519phSupportedHashFuncs = []crypto.Hash{ crypto.SHA512, } // ED25519phSigner is a signature.Signer that uses the Ed25519 public-key signature system with pre-hashing type ED25519phSigner struct { priv ed25519.PrivateKey } // LoadED25519phSigner calculates signatures using the specified private key. func LoadED25519phSigner(priv ed25519.PrivateKey) (*ED25519phSigner, error) { if priv == nil { return nil, errors.New("invalid ED25519 private key specified") } return &ED25519phSigner{ priv: priv, }, nil } // ToED25519SignerVerifier creates a ED25519SignerVerifier from a ED25519phSignerVerifier // // Clients that use ED25519phSignerVerifier should use this method to get a // SignerVerifier that uses the same ED25519 private key, but with the Pure // Ed25519 algorithm. This might be necessary to interact with Fulcio, which // only supports the Pure Ed25519 algorithm. func (e ED25519phSignerVerifier) ToED25519SignerVerifier() (*ED25519SignerVerifier, error) { return LoadED25519SignerVerifier(e.priv) } // SignMessage signs the provided message. If the message is provided, // this method will compute the digest according to the hash function specified // when the ED25519phSigner was created. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (e ED25519phSigner) SignMessage(message io.Reader, opts ...SignOption) ([]byte, error) { digest, _, err := ComputeDigestForSigning(message, crypto.SHA512, ed25519phSupportedHashFuncs, opts...) if err != nil { return nil, err } return e.priv.Sign(nil, digest, crypto.SHA512) } // Public returns the public key that can be used to verify signatures created by // this signer. func (e ED25519phSigner) Public() crypto.PublicKey { if e.priv == nil { return nil } return e.priv.Public() } // PublicKey returns the public key that can be used to verify signatures created by // this signer. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ED25519phSigner) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.Public(), nil } // Sign computes the signature for the specified message; the first and third arguments to this // function are ignored as they are not used by the ED25519ph algorithm. func (e ED25519phSigner) Sign(_ io.Reader, digest []byte, _ crypto.SignerOpts) ([]byte, error) { return e.SignMessage(nil, options.WithDigest(digest)) } // ED25519phVerifier is a signature.Verifier that uses the Ed25519 public-key signature system type ED25519phVerifier struct { publicKey ed25519.PublicKey } // LoadED25519phVerifier returns a Verifier that verifies signatures using the // specified ED25519 public key. func LoadED25519phVerifier(pub ed25519.PublicKey) (*ED25519phVerifier, error) { if pub == nil { return nil, errors.New("invalid ED25519 public key specified") } return &ED25519phVerifier{ publicKey: pub, }, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e *ED25519phVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.publicKey, nil } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the ED25519phVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (e *ED25519phVerifier) VerifySignature(signature, message io.Reader, opts ...VerifyOption) error { if signature == nil { return errors.New("nil signature passed to VerifySignature") } digest, _, err := ComputeDigestForVerifying(message, crypto.SHA512, ed25519phSupportedHashFuncs, opts...) if err != nil { return err } sigBytes, err := io.ReadAll(signature) if err != nil { return fmt.Errorf("reading signature: %w", err) } if err := ed25519.VerifyWithOptions(e.publicKey, digest, sigBytes, &ed25519.Options{Hash: crypto.SHA512}); err != nil { return fmt.Errorf("failed to verify signature: %w", err) } return nil } // ED25519phSignerVerifier is a signature.SignerVerifier that uses the Ed25519 public-key signature system type ED25519phSignerVerifier struct { *ED25519phSigner *ED25519phVerifier } // LoadED25519phSignerVerifier creates a combined signer and verifier. This is // a convenience object that simply wraps an instance of ED25519phSigner and ED25519phVerifier. func LoadED25519phSignerVerifier(priv ed25519.PrivateKey) (*ED25519phSignerVerifier, error) { signer, err := LoadED25519phSigner(priv) if err != nil { return nil, fmt.Errorf("initializing signer: %w", err) } pub, ok := priv.Public().(ed25519.PublicKey) if !ok { return nil, fmt.Errorf("given key is not ed25519.PublicKey") } verifier, err := LoadED25519phVerifier(pub) if err != nil { return nil, fmt.Errorf("initializing verifier: %w", err) } return &ED25519phSignerVerifier{ ED25519phSigner: signer, ED25519phVerifier: verifier, }, nil } // NewDefaultED25519phSignerVerifier creates a combined signer and verifier using ED25519. // This creates a new ED25519 key using crypto/rand as an entropy source. func NewDefaultED25519phSignerVerifier() (*ED25519phSignerVerifier, ed25519.PrivateKey, error) { return NewED25519phSignerVerifier(rand.Reader) } // NewED25519phSignerVerifier creates a combined signer and verifier using ED25519. // This creates a new ED25519 key using the specified entropy source. func NewED25519phSignerVerifier(rand io.Reader) (*ED25519phSignerVerifier, ed25519.PrivateKey, error) { _, priv, err := ed25519.GenerateKey(rand) if err != nil { return nil, nil, err } sv, err := LoadED25519phSignerVerifier(priv) if err != nil { return nil, nil, err } return sv, priv, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (e ED25519phSignerVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return e.publicKey, nil } sigstore-1.8.6/pkg/signature/ed25519ph_test.go000066400000000000000000000055061463713551000210760ustar00rootroot00000000000000// // Copyright 2024 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 signature import ( "crypto" "crypto/ed25519" "encoding/base64" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) // Generated with: // openssl genpkey -algorithm ed25519 -outform PEM -out - const ed25519phPriv = `-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIFP9CZb6J1DiOLfdIkPfy1bwBOCjEG6KR/cIdhw90J1H -----END PRIVATE KEY-----` // Extracted from above with: // openssl ec -in ec_private.pem -pubout const ed25519phPub = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA9wy4umF4RHQ8UQXo8fzEQNBWE4GsBMkCzQPAfHvkf/s= -----END PUBLIC KEY-----` func TestED25519phSignerVerifier(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ed25519phPriv), cryptoutils.SkipPassword) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPriv, ok := privateKey.(ed25519.PrivateKey) if !ok { t.Fatalf("expected ed25519.PrivateKey") } sv, err := LoadED25519phSignerVerifier(edPriv) if err != nil { t.Fatalf("unexpected error creating signer/verifier: %v", err) } message := []byte("sign me") sig, _ := base64.StdEncoding.DecodeString("9D4pA8jutZnbqKy4fFRl+kDsVUCO50qrOD1lxmsiUFk6NX+7OXUK5BCMkE2KYPRDxjkDFBzbDZEQhaFdDV5tDg==") testingSigner(t, sv, "ed25519ph", crypto.SHA512, message) testingVerifier(t, sv, "ed25519ph", crypto.SHA512, sig, message) pub, err := sv.PublicKey() if err != nil { t.Fatalf("unexpected error from PublicKey(): %v", err) } assertPublicKeyIsx509Marshalable(t, pub) } func TestED25519phVerifier(t *testing.T) { publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ed25519phPub)) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPub, ok := publicKey.(ed25519.PublicKey) if !ok { t.Fatalf("public key is not ed25519") } v, err := LoadED25519phVerifier(edPub) if err != nil { t.Fatalf("unexpected error creating verifier: %v", err) } message := []byte("sign me") sig, _ := base64.StdEncoding.DecodeString("9D4pA8jutZnbqKy4fFRl+kDsVUCO50qrOD1lxmsiUFk6NX+7OXUK5BCMkE2KYPRDxjkDFBzbDZEQhaFdDV5tDg==") testingVerifier(t, v, "ed25519ph", crypto.SHA512, sig, message) pub, err := v.PublicKey() if err != nil { t.Fatalf("unexpected error from PublicKey(): %v", err) } assertPublicKeyIsx509Marshalable(t, pub) } sigstore-1.8.6/pkg/signature/kms/000077500000000000000000000000001463713551000167465ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/kms/aws/000077500000000000000000000000001463713551000175405ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/kms/aws/aws_test.go000066400000000000000000000116401463713551000217220ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package aws import "testing" func TestParseReference(t *testing.T) { tests := []struct { in string wantEndpoint string wantKeyID string wantAlias string wantErr bool }{ { in: "awskms:///1234abcd-12ab-34cd-56ef-1234567890ab", wantEndpoint: "", wantKeyID: "1234abcd-12ab-34cd-56ef-1234567890ab", wantAlias: "", wantErr: false, }, { // multi-region key in: "awskms:///mrk-1234abcd12ab34cd56ef1234567890ab", wantEndpoint: "", wantKeyID: "mrk-1234abcd12ab34cd56ef1234567890ab", wantAlias: "", wantErr: false, }, { in: "awskms:///1234ABCD-12AB-34CD-56EF-1234567890AB", wantEndpoint: "", wantKeyID: "1234ABCD-12AB-34CD-56EF-1234567890AB", wantAlias: "", wantErr: false, }, { in: "awskms://localhost:4566/1234abcd-12ab-34cd-56ef-1234567890ab", wantEndpoint: "localhost:4566", wantKeyID: "1234abcd-12ab-34cd-56ef-1234567890ab", wantAlias: "", wantErr: false, }, { in: "awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", wantEndpoint: "", wantKeyID: "arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", wantAlias: "", wantErr: false, }, { in: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", wantEndpoint: "localhost:4566", wantKeyID: "arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", wantAlias: "", wantErr: false, }, { in: "awskms:///alias/ExampleAlias", wantEndpoint: "", wantKeyID: "alias/ExampleAlias", wantAlias: "alias/ExampleAlias", wantErr: false, }, { in: "awskms://localhost:4566/alias/ExampleAlias", wantEndpoint: "localhost:4566", wantKeyID: "alias/ExampleAlias", wantAlias: "alias/ExampleAlias", wantErr: false, }, { in: "awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", wantEndpoint: "", wantKeyID: "arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", wantAlias: "alias/ExampleAlias", wantErr: false, }, { in: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:alias/ExampleAlias", wantEndpoint: "", wantKeyID: "arn:aws-us-gov:kms:us-gov-west-1:111122223333:alias/ExampleAlias", wantAlias: "alias/ExampleAlias", wantErr: false, }, { in: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", wantEndpoint: "", wantKeyID: "arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", wantAlias: "", wantErr: false, }, { in: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", wantEndpoint: "localhost:4566", wantKeyID: "arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", wantAlias: "alias/ExampleAlias", wantErr: false, }, { // missing alias/ prefix in: "awskms:///missingalias", wantEndpoint: "", wantKeyID: "", wantAlias: "", wantErr: true, }, { // invalid UUID in: "awskms:///1234abcd-12ab-YYYY-56ef-1234567890ab", wantEndpoint: "", wantKeyID: "", wantAlias: "", wantErr: true, }, { // Currently, references without endpoints must use 3 // slashes. It would be nice to support this format, // but that would be harder to parse. in: "awskms://1234abcd-12ab-34cd-56ef-1234567890ab", wantEndpoint: "", wantKeyID: "", wantAlias: "", wantErr: true, }, } for _, tt := range tests { t.Run(tt.in, func(t *testing.T) { gotEndpoint, gotKeyID, gotAlias, err := ParseReference(tt.in) if (err != nil) != tt.wantErr { t.Errorf("ParseReference() error = %v, wantErr %v", err, tt.wantErr) return } if gotEndpoint != tt.wantEndpoint { t.Errorf("ParseReference() gotEndpoint = %v, want %v", gotEndpoint, tt.wantEndpoint) } if gotKeyID != tt.wantKeyID { t.Errorf("ParseReference() gotKeyID = %v, want %v", gotKeyID, tt.wantKeyID) } if gotAlias != tt.wantAlias { t.Errorf("ParseReference() gotAlias = %v, want %v", gotAlias, tt.wantAlias) } }) } } sigstore-1.8.6/pkg/signature/kms/aws/client.go000066400000000000000000000256431463713551000213570ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package aws implement the interface with amazon aws kms service package aws import ( "context" "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/tls" "crypto/x509" "errors" "fmt" "io" "net/http" "os" "regexp" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/jellydator/ttlcache/v3" "github.com/sigstore/sigstore/pkg/signature" sigkms "github.com/sigstore/sigstore/pkg/signature/kms" ) func init() { sigkms.AddProvider(ReferenceScheme, func(ctx context.Context, keyResourceID string, _ crypto.Hash, _ ...signature.RPCOption) (sigkms.SignerVerifier, error) { return LoadSignerVerifier(ctx, keyResourceID) }) } const ( cacheKey = "signer" // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets ReferenceScheme = "awskms://" ) type awsClient struct { client *kms.Client endpoint string keyID string alias string keyCache *ttlcache.Cache[string, cmk] } var ( errKMSReference = errors.New("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)") // Key ID/ALIAS/ARN conforms to KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id // Key format examples: // Key ID: awskms:///1234abcd-12ab-34cd-56ef-1234567890ab // Key ID with endpoint: awskms://localhost:4566/1234abcd-12ab-34cd-56ef-1234567890ab // Key ARN: awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab // Key ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab // Alias name: awskms:///alias/ExampleAlias // Alias name with endpoint: awskms://localhost:4566/alias/ExampleAlias // Alias ARN: awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias // Alias ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias uuidRE = `m?r?k?-?[A-Fa-f0-9]{8}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{12}` arnRE = `arn:(?:aws|aws-us-gov|aws-cn):kms:[a-z0-9-]+:\d{12}:` hostRE = `([^/]*)/` keyIDRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + uuidRE + `)$`) keyARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `key/` + uuidRE + `)$`) aliasNameRE = regexp.MustCompile(`^awskms://` + hostRE + `((alias/.*))$`) aliasARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `(alias/.*))$`) allREs = []*regexp.Regexp{keyIDRE, keyARNRE, aliasNameRE, aliasARNRE} ) // ValidReference returns a non-nil error if the reference string is invalid func ValidReference(ref string) error { for _, re := range allREs { if re.MatchString(ref) { return nil } } return errKMSReference } // ParseReference parses an awskms-scheme URI into its constituent parts. func ParseReference(resourceID string) (endpoint, keyID, alias string, err error) { var v []string for _, re := range allREs { v = re.FindStringSubmatch(resourceID) if len(v) >= 3 { endpoint, keyID = v[1], v[2] if len(v) == 4 { alias = v[3] } return } } err = fmt.Errorf("invalid awskms format %q", resourceID) return } func newAWSClient(ctx context.Context, keyResourceID string, opts ...func(*config.LoadOptions) error) (*awsClient, error) { if err := ValidReference(keyResourceID); err != nil { return nil, err } a := &awsClient{} var err error a.endpoint, a.keyID, a.alias, err = ParseReference(keyResourceID) if err != nil { return nil, err } if err := a.setupClient(ctx, opts...); err != nil { return nil, err } a.keyCache = ttlcache.New[string, cmk]( ttlcache.WithDisableTouchOnHit[string, cmk](), ) return a, nil } func (a *awsClient) setupClient(ctx context.Context, opts ...func(*config.LoadOptions) error) (err error) { if a.endpoint != "" { opts = append(opts, config.WithEndpointResolverWithOptions( aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: "https://" + a.endpoint, }, nil }), )) } if os.Getenv("AWS_TLS_INSECURE_SKIP_VERIFY") == "1" { opts = append(opts, config.WithHTTPClient(&http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // nolint: gosec }, })) } cfg, err := config.LoadDefaultConfig(ctx, opts...) if err != nil { return fmt.Errorf("loading AWS config: %w", err) } a.client = kms.NewFromConfig(cfg) return } type cmk struct { KeyMetadata *types.KeyMetadata PublicKey crypto.PublicKey } func (c *cmk) HashFunc() crypto.Hash { switch c.KeyMetadata.SigningAlgorithms[0] { case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecEcdsaSha256: return crypto.SHA256 case types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecEcdsaSha384: return crypto.SHA384 case types.SigningAlgorithmSpecRsassaPssSha512, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512, types.SigningAlgorithmSpecEcdsaSha512: return crypto.SHA512 default: return 0 } } func (c *cmk) Verifier() (signature.Verifier, error) { switch c.KeyMetadata.SigningAlgorithms[0] { case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPssSha512: pub, ok := c.PublicKey.(*rsa.PublicKey) if !ok { return nil, fmt.Errorf("public key is not rsa") } return signature.LoadRSAPSSVerifier(pub, c.HashFunc(), nil) case types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512: pub, ok := c.PublicKey.(*rsa.PublicKey) if !ok { return nil, fmt.Errorf("public key is not rsa") } return signature.LoadRSAPKCS1v15Verifier(pub, c.HashFunc()) case types.SigningAlgorithmSpecEcdsaSha256, types.SigningAlgorithmSpecEcdsaSha384, types.SigningAlgorithmSpecEcdsaSha512: pub, ok := c.PublicKey.(*ecdsa.PublicKey) if !ok { return nil, fmt.Errorf("public key is not ecdsa") } return signature.LoadECDSAVerifier(pub, c.HashFunc()) default: return nil, fmt.Errorf("signing algorithm unsupported") } } func (a *awsClient) fetchCMK(ctx context.Context) (*cmk, error) { var err error cmk := &cmk{} cmk.PublicKey, err = a.fetchPublicKey(ctx) if err != nil { return nil, err } cmk.KeyMetadata, err = a.fetchKeyMetadata(ctx) if err != nil { return nil, err } return cmk, nil } func (a *awsClient) getHashFunc(ctx context.Context) (crypto.Hash, error) { cmk, err := a.getCMK(ctx) if err != nil { return 0, err } return cmk.HashFunc(), nil } func (a *awsClient) getCMK(ctx context.Context) (*cmk, error) { var lerr error loader := ttlcache.LoaderFunc[string, cmk]( func(c *ttlcache.Cache[string, cmk], key string) *ttlcache.Item[string, cmk] { var k *cmk k, lerr = a.fetchCMK(ctx) if lerr == nil { return c.Set(cacheKey, *k, time.Second*300) } return nil }, ) item := a.keyCache.Get(cacheKey, ttlcache.WithLoader[string, cmk](loader)) if lerr == nil { cmk := item.Value() return &cmk, nil } return nil, lerr } func (a *awsClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { if a.alias == "" { return nil, errors.New("must use alias key format") } // look for existing key first cmk, err := a.getCMK(ctx) if err == nil { out := cmk.PublicKey return out, nil } // return error if not *kms.NotFoundException var errNotFound *types.NotFoundException if !errors.As(err, &errNotFound) { return nil, fmt.Errorf("looking up key: %w", err) } usage := types.KeyUsageTypeSignVerify description := "Created by Sigstore" key, err := a.client.CreateKey(ctx, &kms.CreateKeyInput{ CustomerMasterKeySpec: types.CustomerMasterKeySpec(algorithm), KeyUsage: usage, Description: &description, }) if err != nil { return nil, fmt.Errorf("creating key: %w", err) } _, err = a.client.CreateAlias(ctx, &kms.CreateAliasInput{ AliasName: &a.alias, TargetKeyId: key.KeyMetadata.KeyId, }) if err != nil { return nil, fmt.Errorf("creating alias %q: %w", a.alias, err) } cmk, err = a.getCMK(ctx) if err != nil { return nil, fmt.Errorf("retrieving PublicKey from cache: %w", err) } return cmk.PublicKey, err } func (a *awsClient) verify(ctx context.Context, sig, message io.Reader, opts ...signature.VerifyOption) error { cmk, err := a.getCMK(ctx) if err != nil { return err } verifier, err := cmk.Verifier() if err != nil { return err } return verifier.VerifySignature(sig, message, opts...) } func (a *awsClient) verifyRemotely(ctx context.Context, sig, digest []byte) error { cmk, err := a.getCMK(ctx) if err != nil { return err } alg := cmk.KeyMetadata.SigningAlgorithms[0] messageType := types.MessageTypeDigest if _, err := a.client.Verify(ctx, &kms.VerifyInput{ KeyId: &a.keyID, Message: digest, MessageType: messageType, Signature: sig, SigningAlgorithm: alg, }); err != nil { return fmt.Errorf("unable to verify signature: %w", err) } return nil } func (a *awsClient) sign(ctx context.Context, digest []byte, _ crypto.Hash) ([]byte, error) { cmk, err := a.getCMK(ctx) if err != nil { return nil, err } alg := cmk.KeyMetadata.SigningAlgorithms[0] messageType := types.MessageTypeDigest out, err := a.client.Sign(ctx, &kms.SignInput{ KeyId: &a.keyID, Message: digest, MessageType: messageType, SigningAlgorithm: alg, }) if err != nil { return nil, fmt.Errorf("signing with kms: %w", err) } return out.Signature, nil } func (a *awsClient) fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) { out, err := a.client.GetPublicKey(ctx, &kms.GetPublicKeyInput{ KeyId: &a.keyID, }) if err != nil { return nil, fmt.Errorf("getting public key: %w", err) } key, err := x509.ParsePKIXPublicKey(out.PublicKey) if err != nil { return nil, fmt.Errorf("parsing public key: %w", err) } return key, nil } func (a *awsClient) fetchKeyMetadata(ctx context.Context) (*types.KeyMetadata, error) { out, err := a.client.DescribeKey(ctx, &kms.DescribeKeyInput{ KeyId: &a.keyID, }) if err != nil { return nil, fmt.Errorf("getting key metadata: %w", err) } return out.KeyMetadata, nil } sigstore-1.8.6/pkg/signature/kms/aws/doc.go000066400000000000000000000012341463713551000206340ustar00rootroot00000000000000// // 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 aws contains utilities related to AWS KMS. package aws sigstore-1.8.6/pkg/signature/kms/aws/e2e_test.go000066400000000000000000000222031463713551000216000ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build e2e // +build e2e package aws import ( "bytes" "context" "crypto" "crypto/ecdsa" "fmt" "os" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/config" awskms "github.com/aws/aws-sdk-go/service/kms" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" ) type AWSSuite struct { suite.Suite endpoint string } // Address intermittent failure in issue #1110 type Issue1110Error struct{} func (i Issue1110Error) IsErrorRetryable(err error) aws.Ternary { if err != nil && err.Error() == "use of closed network connection" { return aws.BoolTernary(true) } return aws.UnknownTernary } func (suite *AWSSuite) GetProvider(key string) *SignerVerifier { provider, err := LoadSignerVerifier(context.Background(), fmt.Sprintf("awskms://%s/%s", suite.endpoint, key), config.WithRetryer(func() aws.Retryer { return retry.NewStandard(func(opts *retry.StandardOptions) { opts.Retryables = append(opts.Retryables, Issue1110Error{}) }) })) require.NoError(suite.T(), err) require.NotNil(suite.T(), provider) return provider } func (suite *AWSSuite) SetupSuite() { suite.endpoint = os.Getenv("AWS_ENDPOINT") } func (suite *AWSSuite) TestGetProvider() { _ = suite.GetProvider("alias/provider") _ = suite.GetProvider("1234abcd-12ab-34cd-56ef-1234567890ab") } func (suite *AWSSuite) TestInvalidProvider() { provider, err := LoadSignerVerifier(context.Background(), fmt.Sprintf("awskms://%s/nonsense", suite.endpoint)) require.Error(suite.T(), err) require.Nil(suite.T(), provider) } func (suite *AWSSuite) TestCreateKey() { provider := suite.GetProvider("alias/provider") key, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) key2, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) // Subsequent call should produce same key assert.Equal(suite.T(), key, key2) } func (suite *AWSSuite) TestCreateKeyByID() { provider := suite.GetProvider("1234abcd-12ab-34cd-56ef-1234567890ab") // CreateKey can only work with aliases, not IDs key, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Error(suite.T(), err) require.Nil(suite.T(), key) } func (suite *AWSSuite) TestSign() { provider := suite.GetProvider("alias/TestSign") key, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) verifier, _ := signature.LoadECDSAVerifier(key.(*ecdsa.PublicKey), crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *AWSSuite) TestSHA384() { provider := suite.GetProvider("alias/TestSHA384") key, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP384) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) k, err := provider.PublicKey() require.Nil(suite.T(), err) require.NotNil(suite.T(), key) pubKey, ok := k.(*ecdsa.PublicKey) require.True(suite.T(), ok, fmt.Sprintf("expected type ecdsa, got type %T", k)) verifier, _ := signature.LoadECDSAVerifier(pubKey, crypto.SHA384) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *AWSSuite) TestPublicKey() { provider := suite.GetProvider("alias/TestPubKeyVerify") key, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) require.NotNil(suite.T(), sig) require.Nil(suite.T(), err) k, err := provider.PublicKey() require.Nil(suite.T(), err) require.NotNil(suite.T(), key) pubKey, ok := k.(*ecdsa.PublicKey) require.True(suite.T(), ok, fmt.Sprintf("expected type ecdsa, got: %T", k)) verifier, _ := signature.LoadECDSAVerifier(pubKey, crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *AWSSuite) TestVerify() { provider := suite.GetProvider("alias/TestVerify") key, err := provider.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithRemoteVerification(true)) assert.Nil(suite.T(), err) } func (suite *AWSSuite) TestTwoProviders() { provider1 := suite.GetProvider("alias/TestTwoProviders") provider2 := suite.GetProvider("alias/TestTwoProviders") key, err := provider1.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider1.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) err = provider2.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *AWSSuite) TestBadSignature() { provider1 := suite.GetProvider("alias/TestBadSignature1") provider2 := suite.GetProvider("alias/TestBadSignature2") key1, err := provider1.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key1) key2, err := provider2.CreateKey(context.Background(), awskms.CustomerMasterKeySpecEccNistP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key2) data := []byte("mydata") sig, err := provider1.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) err = provider2.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Contains(suite.T(), err.Error(), "invalid signature when validating ASN.1 encoded signature") err = provider2.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithRemoteVerification(true)) assert.Contains(suite.T(), err.Error(), "KMSInvalidSignatureException") } func (suite *AWSSuite) TestKeyTypes() { for _, cmkSpec := range []string{ awskms.CustomerMasterKeySpecRsa2048, awskms.CustomerMasterKeySpecRsa3072, awskms.CustomerMasterKeySpecRsa4096, awskms.CustomerMasterKeySpecEccNistP256, awskms.CustomerMasterKeySpecEccNistP384, awskms.CustomerMasterKeySpecEccNistP521, // awskms.CustomerMasterKeySpecEccSecgP256k1, // unsupported by localstack at the moment } { suite.T().Run(fmt.Sprintf("KeyType-%s", cmkSpec), func(t *testing.T) { provider := suite.GetProvider("alias/" + cmkSpec) key, err := provider.CreateKey(context.Background(), cmkSpec) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) }) } } func (suite *AWSSuite) TestCancelContext() { ctx, cancel := context.WithCancel(context.Background()) cancel() provider := suite.GetProvider("alias/TestCancelContext") key, err := provider.CreateKey(ctx, awskms.CustomerMasterKeySpecEccNistP256) assert.Error(suite.T(), err) assert.Contains(suite.T(), err.Error(), context.Canceled.Error()) assert.Nil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data), options.WithContext(ctx)) assert.Error(suite.T(), err) assert.Contains(suite.T(), err.Error(), context.Canceled.Error()) assert.Nil(suite.T(), sig) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithContext(ctx)) assert.Error(suite.T(), err) assert.Contains(suite.T(), err.Error(), context.Canceled.Error()) } func TestAWS(t *testing.T) { suite.Run(t, new(AWSSuite)) } sigstore-1.8.6/pkg/signature/kms/aws/go.mod000066400000000000000000000037131463713551000206520ustar00rootroot00000000000000module github.com/sigstore/sigstore/pkg/signature/kms/aws replace github.com/sigstore/sigstore => ../../../../ go 1.22.0 require ( github.com/aws/aws-sdk-go v1.54.6 github.com/aws/aws-sdk-go-v2 v1.30.0 github.com/aws/aws-sdk-go-v2/config v1.27.21 github.com/aws/aws-sdk-go-v2/service/kms v1.34.1 github.com/jellydator/ttlcache/v3 v3.2.0 github.com/sigstore/sigstore v1.6.4 github.com/stretchr/testify v1.9.0 ) require ( github.com/aws/aws-sdk-go-v2/credentials v1.17.21 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 // indirect github.com/aws/smithy-go v1.20.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/google/go-containerregistry v0.19.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) sigstore-1.8.6/pkg/signature/kms/aws/go.sum000066400000000000000000000234341463713551000207010ustar00rootroot00000000000000github.com/aws/aws-sdk-go v1.54.6 h1:HEYUib3yTt8E6vxjMWM3yAq5b+qjj/6aKA62mkgux9g= github.com/aws/aws-sdk-go v1.54.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6kAA= github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/config v1.27.21 h1:yPX3pjGCe2hJsetlmGNB4Mngu7UPmvWPzzWCv1+boeM= github.com/aws/aws-sdk-go-v2/config v1.27.21/go.mod h1:4XtlEU6DzNai8RMbjSF5MgGZtYvrhBP/aKZcRtZAVdM= github.com/aws/aws-sdk-go-v2/credentials v1.17.21 h1:pjAqgzfgFhTv5grc7xPHtXCAaMapzmwA7aU+c/SZQGw= github.com/aws/aws-sdk-go-v2/credentials v1.17.21/go.mod h1:nhK6PtBlfHTUDVmBLr1dg+WHCOCK+1Fu/WQyVHPsgNQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12/go.mod h1:FkpvXhA92gb3GE9LD6Og0pHHycTxW7xGpnEh5E7Opwo= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 h1:hb5KgeYfObi5MHkSSZMEudnIvX30iB+E21evI4r6BnQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12/go.mod h1:CroKe/eWJdyfy9Vx4rljP5wTUjNJfb+fPz1uMYUhEGM= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 h1:zSDPny/pVnkqABXYRicYuPf9z2bTqfH13HT3v6UheIk= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14/go.mod h1:3TTcI5JSzda1nw/pkVC9dhgLre0SNBFj2lYS4GctXKI= github.com/aws/aws-sdk-go-v2/service/kms v1.34.1 h1:VsKBn6WADI3Nn3WjBMzeRww9WHXeVLi7zyuSrqjRCBQ= github.com/aws/aws-sdk-go-v2/service/kms v1.34.1/go.mod h1:5F6kXrPBxv0l1t8EO44GuG4W82jGJwaRE0B+suEGnNY= github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 h1:sd0BsnAvLH8gsp2e3cbaIr+9D7T1xugueQ7V/zUAsS4= github.com/aws/aws-sdk-go-v2/service/sso v1.21.1/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 h1:1uEFNNskK/I1KoZ9Q8wJxMz5V9jyBlsiaNrM7vA3YUQ= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4= github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 h1:myX5CxqXE0QMZNja6FA1/FSE3Vu1rVmeUmpJMMzeZg0= github.com/aws/aws-sdk-go-v2/service/sts v1.29.1/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE= github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= 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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= 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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/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= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= 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.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sigstore-1.8.6/pkg/signature/kms/aws/signer.go000066400000000000000000000157251463713551000213700ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package aws import ( "context" "crypto" "fmt" "io" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" ) var awsSupportedAlgorithms = []types.CustomerMasterKeySpec{ types.CustomerMasterKeySpecRsa2048, types.CustomerMasterKeySpecRsa3072, types.CustomerMasterKeySpecRsa4096, types.CustomerMasterKeySpecEccNistP256, types.CustomerMasterKeySpecEccNistP384, types.CustomerMasterKeySpecEccNistP521, } var awsSupportedHashFuncs = []crypto.Hash{ crypto.SHA256, crypto.SHA384, crypto.SHA512, } // SignerVerifier is a signature.SignerVerifier that uses the AWS Key Management Service type SignerVerifier struct { client *awsClient } // LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. // // It also can verify signatures locally using the public key. hashFunc must not be crypto.Hash(0). func LoadSignerVerifier(ctx context.Context, referenceStr string, opts ...func(*config.LoadOptions) error) (*SignerVerifier, error) { a := &SignerVerifier{} var err error a.client, err = newAWSClient(ctx, referenceStr, opts...) if err != nil { return nil, err } return a, nil } // SignMessage signs the provided message using AWS KMS. If the message is provided, // this method will compute the digest according to the hash function specified // when the Signer was created. // // SignMessage recognizes the following Options listed in order of preference: // // - WithContext() // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (a *SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) { var digest []byte var err error ctx := context.Background() for _, opt := range opts { opt.ApplyContext(&ctx) opt.ApplyDigest(&digest) } var signerOpts crypto.SignerOpts signerOpts, err = a.client.getHashFunc(ctx) if err != nil { return nil, fmt.Errorf("getting fetching default hash function: %w", err) } for _, opt := range opts { opt.ApplyCryptoSignerOpts(&signerOpts) } hf := signerOpts.HashFunc() if len(digest) == 0 { digest, hf, err = signature.ComputeDigestForSigning(message, hf, awsSupportedHashFuncs, opts...) if err != nil { return nil, err } } return a.client.sign(ctx, digest, hf) } // PublicKey returns the public key that can be used to verify signatures created by // this signer. If the caller wishes to specify the context to use to obtain // the public key, pass option.WithContext(desiredCtx). // // All other options are ignored if specified. func (a *SignerVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { ctx := context.Background() for _, opt := range opts { opt.ApplyContext(&ctx) } cmk, err := a.client.getCMK(ctx) if err != nil { return nil, err } return cmk.PublicKey, nil } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the SignerVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithContext() // // - WithDigest() // // - WithRemoteVerification() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (a *SignerVerifier) VerifySignature(sig, message io.Reader, opts ...signature.VerifyOption) (err error) { ctx := context.Background() var digest []byte var remoteVerification bool for _, opt := range opts { opt.ApplyContext(&ctx) opt.ApplyDigest(&digest) opt.ApplyRemoteVerification(&remoteVerification) } if !remoteVerification { return a.client.verify(ctx, sig, message, opts...) } var signerOpts crypto.SignerOpts signerOpts, err = a.client.getHashFunc(ctx) if err != nil { return fmt.Errorf("getting hash func: %w", err) } for _, opt := range opts { opt.ApplyCryptoSignerOpts(&signerOpts) } hf := signerOpts.HashFunc() if len(digest) == 0 { digest, _, err = signature.ComputeDigestForVerifying(message, hf, awsSupportedHashFuncs, opts...) if err != nil { return err } } sigBytes, err := io.ReadAll(sig) if err != nil { return fmt.Errorf("reading signature: %w", err) } return a.client.verifyRemotely(ctx, sigBytes, digest) } // CreateKey attempts to create a new key in Vault with the specified algorithm. func (a *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { return a.client.createKey(ctx, algorithm) } type cryptoSignerWrapper struct { ctx context.Context hashFunc crypto.Hash sv *SignerVerifier errFunc func(error) } func (c cryptoSignerWrapper) Public() crypto.PublicKey { pk, err := c.sv.PublicKey(options.WithContext(c.ctx)) if err != nil && c.errFunc != nil { c.errFunc(err) } return pk } func (c cryptoSignerWrapper) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { hashFunc := c.hashFunc if opts != nil { hashFunc = opts.HashFunc() } awsOptions := []signature.SignOption{ options.WithContext(c.ctx), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc), } return c.sv.SignMessage(nil, awsOptions...) } // CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object // that allows the KMS to be used in APIs that only accept the standard golang objects func (a *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { defaultHf, err := a.client.getHashFunc(ctx) if err != nil { return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err) } csw := &cryptoSignerWrapper{ ctx: ctx, sv: a, hashFunc: defaultHf, errFunc: errFunc, } return csw, defaultHf, nil } // SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service func (*SignerVerifier) SupportedAlgorithms() []string { s := make([]string, len(awsSupportedAlgorithms)) for i := range awsSupportedAlgorithms { s[i] = string(awsSupportedAlgorithms[i]) } return s } // DefaultAlgorithm returns the default algorithm for the AWS KMS service func (*SignerVerifier) DefaultAlgorithm() string { return string(types.CustomerMasterKeySpecEccNistP256) } sigstore-1.8.6/pkg/signature/kms/azure/000077500000000000000000000000001463713551000200745ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/kms/azure/README.md000066400000000000000000000066161463713551000213640ustar00rootroot00000000000000# Azure KMS In order to use Azure KMS ([Key Vault](https://docs.microsoft.com/en-us/azure/key-vault/general/basic-concepts)) with the sigstore project you need to have a few things setup in Azure first. The key creation will be handled in sigstore, however the Azure Key Vault and the required permission will have to be configured before. ## Azure Prerequisites - [Resource Group](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal#what-is-a-resource-group) - [Key Vault](https://docs.microsoft.com/en-us/azure/key-vault/general/basic-concepts) - [Key Vault permissions](https://docs.microsoft.com/en-us/azure/key-vault/general/rbac-guide) - [Container Registry](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-intro) _(not required, but used in below examples)_ ## Permissions (Access Policies) Different commands require different Key Vault access policies. For more information check the official [Azure Docs](https://azure.microsoft.com/en-us/services/key-vault/). ## Using Azure KMS with Cosign An Azure KMS key must be provided in the following format: `azurekms://[Key Vault Name].vault.azure.net/[Key Name]` A specific key version can optionally be provided: `azurekms://[Key Vault Name].vault.azure.net/[Key Name]/[Key Version]` ### cosign generate-key-pair Required access policies (keys): `get`, `create` ```shell cosign generate-key-pair --kms azurekms://[Key Vault Name].vault.azure.net/[Key Name] ``` ### cosign sign Required access policies (keys): `get`, `sign` ```shell az acr login --name [Container Registry Name] cosign sign --key azurekms://[Key Vault Name].vault.azure.net/[Key Name] [Container Registry Name].azurecr.io/[Image Name] ``` ### cosign verify Required access policy (keys): `verify` ```shell az acr login --name [Container Registry Name] cosign verify --key azurekms://[Key Vault Name].vault.azure.net/[Key Name] [Container Registry Name].azurecr.io/[Image Name] ``` ## Authentication There are multiple authentication methods supported for Azure Key Vault and by default they will be evaluated in the following order: 1. Client credentials (FromEnvironment) 1. Client certificate (FromEnvironment) 1. Username password (FromEnvironment) 1. MSI (FromEnvironment) 1. CLI (FromCLI) You can force either `FromEnvironment` or `FromCLI` by configuring the environment variable `AZURE_AUTH_METHOD` to either `environment` or `cli`. For backward compatibility, if you configure `AZURE_TENANT_ID`, `AZURE_CLIENT_ID` and `AZURE_CLIENT_SECRET`, `FromEnvironment` will be used. If you would like to use a cloud other than the Azure public cloud, configure `AZURE_ENVIRONMENT`. The following values are accepted: - `AZUREUSGOVERNMENT`, `AZUREUSGOVERNMENTCLOUD` uses the Azure US Government Cloud - `AZURECHINACLOUD` uses Azure China Cloud - `AZURECLOUD`, `AZUREPUBLICCLOUD` uses the public cloud If `AZURE_ENVIRONMENT` is not configured, Azure public cloud is used. ## Integration Testing In addition to unit tests in this module, there is `integration_test.go`, which requires you to provide either environment or CLI credentials. Because the Sigstore project does not use Azure, the tests are not run as part of any CI/CD. These tests are for Azure client developers to test that changes work as expected against their own Azure subscription. Run the integration tests with `go test -tags=integration ./...` in the root of this module. sigstore-1.8.6/pkg/signature/kms/azure/client.go000066400000000000000000000332051463713551000217040ustar00rootroot00000000000000// // 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 azure implement the interface with microsoft azure kms service package azure import ( "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "encoding/json" "errors" "fmt" "net/http" "os" "regexp" "strings" "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/go-jose/go-jose/v3" "github.com/jellydator/ttlcache/v3" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys" "github.com/sigstore/sigstore/pkg/signature" sigkms "github.com/sigstore/sigstore/pkg/signature/kms" ) func init() { sigkms.AddProvider(ReferenceScheme, func(ctx context.Context, keyResourceID string, _ crypto.Hash, opts ...signature.RPCOption) (sigkms.SignerVerifier, error) { return LoadSignerVerifier(ctx, keyResourceID) }) } type kvClient interface { CreateKey(ctx context.Context, name string, parameters azkeys.CreateKeyParameters, options *azkeys.CreateKeyOptions) (azkeys.CreateKeyResponse, error) GetKey(ctx context.Context, name, version string, options *azkeys.GetKeyOptions) (azkeys.GetKeyResponse, error) Sign(ctx context.Context, name, version string, parameters azkeys.SignParameters, options *azkeys.SignOptions) (azkeys.SignResponse, error) Verify(ctx context.Context, name, version string, parameters azkeys.VerifyParameters, options *azkeys.VerifyOptions) (azkeys.VerifyResponse, error) } type azureVaultClient struct { client kvClient keyCache *ttlcache.Cache[string, crypto.PublicKey] vaultURL string keyName string keyVersion string } var ( errAzureReference = errors.New("kms specification should be in the format azurekms://[VAULT_NAME][VAULT_URL]/[KEY_NAME]/[VERSION (optional)]") referenceRegex = regexp.MustCompile(`^azurekms://([^/]+)/([^/]+)(/[a-z0-9]*)?$`) ) const ( // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets ReferenceScheme = "azurekms://" cacheKey = "azure_vault_signer" azureClientID = "AZURE_CLIENT_ID" ) // ValidReference returns a non-nil error if the reference string is invalid func ValidReference(ref string) error { if !referenceRegex.MatchString(ref) { return errAzureReference } return nil } // The key version can be optionally provided // If provided, all key operations will specify this version. // If not provided, the key operations will use the latest key version by default. func parseReference(resourceID string) (vaultURL, keyName, keyVersion string, err error) { if isIDValid := referenceRegex.MatchString(resourceID); !isIDValid { err = fmt.Errorf("invalid azurekms format %q", resourceID) return } fullRef := strings.Split(resourceID, "azurekms://")[1] splitRef := strings.Split(fullRef, "/") vaultURL = fmt.Sprintf("https://%s/", splitRef[0]) keyName = splitRef[1] if len(splitRef) == 3 { keyVersion = splitRef[2] } return } func newAzureKMS(keyResourceID string) (*azureVaultClient, error) { if err := ValidReference(keyResourceID); err != nil { return nil, err } vaultURL, keyName, keyVersion, err := parseReference(keyResourceID) if err != nil { return nil, err } client, err := getKeysClient(vaultURL) if err != nil { return nil, fmt.Errorf("new azure kms client: %w", err) } azClient := &azureVaultClient{ client: client, vaultURL: vaultURL, keyName: keyName, keyVersion: keyVersion, keyCache: ttlcache.New[string, crypto.PublicKey]( ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](), ), } return azClient, nil } type authenticationMethod string const ( unknownAuthenticationMethod = "unknown" environmentAuthenticationMethod = "environment" cliAuthenticationMethod = "cli" ) // getAuthMethod returns the an authenticationMethod to use to get an Azure Authorizer. // If no environment variables are set, unknownAuthMethod will be used. // If the environment variable 'AZURE_AUTH_METHOD' is set to either environment or cli, use it. // If the environment variables 'AZURE_TENANT_ID', 'AZURE_CLIENT_ID' and 'AZURE_CLIENT_SECRET' are set, use environment. func getAuthenticationMethod() authenticationMethod { tenantID := os.Getenv("AZURE_TENANT_ID") clientID := os.Getenv("AZURE_CLIENT_ID") clientSecret := os.Getenv("AZURE_CLIENT_SECRET") authMethod := os.Getenv("AZURE_AUTH_METHOD") if authMethod != "" { switch strings.ToLower(authMethod) { case "environment": return environmentAuthenticationMethod case "cli": return cliAuthenticationMethod } } if tenantID != "" && clientID != "" && clientSecret != "" { return environmentAuthenticationMethod } return unknownAuthenticationMethod } type azureCredential interface { GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) } func getAzClientOpts() azcore.ClientOptions { envName := os.Getenv("AZURE_ENVIRONMENT") switch envName { case "AZUREUSGOVERNMENT", "AZUREUSGOVERNMENTCLOUD": return azcore.ClientOptions{Cloud: cloud.AzureGovernment} case "AZURECHINACLOUD": return azcore.ClientOptions{Cloud: cloud.AzureChina} case "AZURECLOUD", "AZUREPUBLICCLOUD": return azcore.ClientOptions{Cloud: cloud.AzurePublic} default: return azcore.ClientOptions{Cloud: cloud.AzurePublic} } } // getAzureCredential takes an authenticationMethod and returns an Azure credential or an error. // If the method is unknown, Environment will be tested and if it returns an error CLI will be tested. // If the method is specified, the specified method will be used and no other will be tested. // This means the following default order of methods will be used if nothing else is defined: // 1. Client credentials (FromEnvironment) // 2. Client certificate (FromEnvironment) // 3. Username password (FromEnvironment) // 4. MSI (FromEnvironment) // 5. CLI (FromCLI) func getAzureCredential(method authenticationMethod) (azureCredential, error) { clientOpts := getAzClientOpts() switch method { case environmentAuthenticationMethod: envCred, err := azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOpts}) if err == nil { return envCred, nil } o := &azidentity.ManagedIdentityCredentialOptions{ClientOptions: clientOpts} if ID, ok := os.LookupEnv(azureClientID); ok { o.ID = azidentity.ClientID(ID) } msiCred, err := azidentity.NewManagedIdentityCredential(o) if err == nil { return msiCred, nil } return nil, fmt.Errorf("failed to create default azure credential from env auth method: %w", err) case cliAuthenticationMethod: cred, err := azidentity.NewAzureCLICredential(nil) if err != nil { return nil, fmt.Errorf("failed to create default Azure credential from env auth method: %w", err) } return cred, nil case unknownAuthenticationMethod: break default: return nil, fmt.Errorf("you should never reach this") } envCreds, err := azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOpts}) if err == nil { return envCreds, nil } cliCreds, err := azidentity.NewAzureCLICredential(nil) if err != nil { return nil, fmt.Errorf("failed to create default Azure credential from env auth method: %w", err) } return cliCreds, nil } func getKeysClient(vaultURL string) (*azkeys.Client, error) { authMethod := getAuthenticationMethod() cred, err := getAzureCredential(authMethod) if err != nil { return nil, err } client, err := azkeys.NewClient(vaultURL, cred, nil) if err != nil { return nil, err } return client, nil } func (a *azureVaultClient) fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) { keyBundle, err := a.getKey(ctx) if err != nil { return nil, fmt.Errorf("public key: %w", err) } key := keyBundle.Key keyType := key.Kty // Azure Key Vault allows keys to be stored in either default Key Vault storage // or in managed HSMs. If the key is stored in a HSM, the key type is suffixed // with "-HSM". Since this suffix is specific to Azure Key Vault, it needs // be stripped from the key type before attempting to represent the key // with a go-jose/JSONWebKey struct. switch *keyType { case azkeys.KeyTypeECHSM: *key.Kty = azkeys.KeyTypeEC case azkeys.KeyTypeRSAHSM: *key.Kty = azkeys.KeyTypeRSA } jwkJSON, err := json.Marshal(*key) if err != nil { return nil, fmt.Errorf("encoding the jsonWebKey: %w", err) } jwk := jose.JSONWebKey{} err = jwk.UnmarshalJSON(jwkJSON) if err != nil { return nil, fmt.Errorf("decoding the jsonWebKey: %w", err) } return jwk.Key, nil } func (a *azureVaultClient) getKey(ctx context.Context) (azkeys.KeyBundle, error) { resp, err := a.client.GetKey(ctx, a.keyName, a.keyVersion, nil) if err != nil { return azkeys.KeyBundle{}, fmt.Errorf("public key: %w", err) } return resp.KeyBundle, err } func (a *azureVaultClient) public(ctx context.Context) (crypto.PublicKey, error) { var lerr error loader := ttlcache.LoaderFunc[string, crypto.PublicKey]( func(c *ttlcache.Cache[string, crypto.PublicKey], key string) *ttlcache.Item[string, crypto.PublicKey] { ttl := 300 * time.Second var pubKey crypto.PublicKey pubKey, lerr = a.fetchPublicKey(ctx) if lerr == nil { return c.Set(cacheKey, pubKey, ttl) } return nil }, ) item := a.keyCache.Get(cacheKey, ttlcache.WithLoader[string, crypto.PublicKey](loader)) if lerr != nil { return nil, lerr } return item.Value(), nil } func (a *azureVaultClient) createKey(ctx context.Context) (crypto.PublicKey, error) { // check if the key already exists by attempting to fetch it _, err := a.getKey(ctx) // if the error is nil, this means the key already exists // and we can return the public key if err == nil { return a.public(ctx) } // If the returned error is not nil, set the error to the // custom azcore.ResponseError error implementation // this custom error allows us to check the status code // returned by the GetKey operation. If the operation // returned a 404, we know that the key does not exist // and we can create it. var respErr *azcore.ResponseError if ok := errors.As(err, &respErr); !ok { return nil, fmt.Errorf("unexpected error returned by get key operation: %w", err) } // if a non-404 status code is returned, return the error // since this is an unexpected error response if respErr.StatusCode != http.StatusNotFound { return nil, fmt.Errorf("unexpected status code returned by get key operation: %w", err) } // if a 404 was returned, then we can create the key _, err = a.client.CreateKey( ctx, a.keyName, azkeys.CreateKeyParameters{ KeyAttributes: &azkeys.KeyAttributes{ Enabled: to.Ptr(true), }, KeySize: to.Ptr(int32(2048)), KeyOps: []*azkeys.KeyOperation{ to.Ptr(azkeys.KeyOperationSign), to.Ptr(azkeys.KeyOperationVerify), }, Kty: to.Ptr(azkeys.KeyTypeEC), Tags: map[string]*string{ "use": to.Ptr("sigstore"), }, }, nil) if err != nil { return nil, err } return a.public(ctx) } func (a *azureVaultClient) getKeyVaultHashFunc(ctx context.Context) (crypto.Hash, azkeys.SignatureAlgorithm, error) { publicKey, err := a.public(ctx) if err != nil { return 0, "", fmt.Errorf("failed to get public key: %w", err) } switch keyImpl := publicKey.(type) { case *ecdsa.PublicKey: switch keyImpl.Curve { case elliptic.P256(): return crypto.SHA256, azkeys.SignatureAlgorithmES256, nil case elliptic.P384(): return crypto.SHA384, azkeys.SignatureAlgorithmES384, nil case elliptic.P521(): return crypto.SHA512, azkeys.SignatureAlgorithmES512, nil default: return 0, "", fmt.Errorf("unsupported key size: %s", keyImpl.Params().Name) } case *rsa.PublicKey: switch keyImpl.Size() { case 256: return crypto.SHA256, azkeys.SignatureAlgorithmRS256, nil case 384: return crypto.SHA384, azkeys.SignatureAlgorithmRS384, nil case 512: return crypto.SHA512, azkeys.SignatureAlgorithmRS512, nil default: return 0, "", fmt.Errorf("unsupported key size: %d", keyImpl.Size()) } default: return 0, "", fmt.Errorf("unsupported public key type: %T", publicKey) } } func (a *azureVaultClient) sign(ctx context.Context, hash []byte) ([]byte, error) { _, keyVaultAlgo, err := a.getKeyVaultHashFunc(ctx) if err != nil { return nil, fmt.Errorf("failed to get KeyVaultSignatureAlgorithm: %w", err) } params := azkeys.SignParameters{ Algorithm: &keyVaultAlgo, Value: hash, } result, err := a.client.Sign(ctx, a.keyName, a.keyVersion, params, nil) if err != nil { return nil, fmt.Errorf("signing the payload: %w", err) } return result.Result, nil } func (a *azureVaultClient) verify(ctx context.Context, signature, hash []byte) error { _, keyVaultAlgo, err := a.getKeyVaultHashFunc(ctx) if err != nil { return fmt.Errorf("failed to get KeyVaultSignatureAlgorithm: %w", err) } params := azkeys.VerifyParameters{ Algorithm: &keyVaultAlgo, Digest: hash, Signature: signature, } result, err := a.client.Verify(ctx, a.keyName, a.keyVersion, params, nil) if err != nil { return fmt.Errorf("verify: %w", err) } if !*result.Value { return errors.New("failed vault verification") } return nil } sigstore-1.8.6/pkg/signature/kms/azure/client_test.go000066400000000000000000000241331463713551000227430ustar00rootroot00000000000000// // 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 azure import ( "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "errors" "fmt" "net/http" "os" "testing" "github.com/jellydator/ttlcache/v3" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys" ) type testKVClient struct { key azkeys.JSONWebKey } func (c *testKVClient) CreateKey(_ context.Context, _ string, _ azkeys.CreateKeyParameters, _ *azkeys.CreateKeyOptions) (azkeys.CreateKeyResponse, error) { key, err := generatePublicKey("EC") if err != nil { return azkeys.CreateKeyResponse{}, err } c.key = key return azkeys.CreateKeyResponse{ KeyBundle: azkeys.KeyBundle{ Key: &key, }, }, nil } func (c *testKVClient) GetKey(_ context.Context, _, _ string, _ *azkeys.GetKeyOptions) (azkeys.GetKeyResponse, error) { return azkeys.GetKeyResponse{ KeyBundle: azkeys.KeyBundle{ Key: &c.key, }, }, nil } func (c *testKVClient) Sign(_ context.Context, _, _ string, _ azkeys.SignParameters, _ *azkeys.SignOptions) (result azkeys.SignResponse, err error) { return result, nil } func (c *testKVClient) Verify(_ context.Context, _, _ string, _ azkeys.VerifyParameters, _ *azkeys.VerifyOptions) (result azkeys.VerifyResponse, err error) { return result, nil } type keyNotFoundClient struct { testKVClient key azkeys.JSONWebKey getKeyReturnsErr bool getKeyCallThreshold int getKeyCallCount int } func (c *keyNotFoundClient) GetKey(_ context.Context, _, _ string, _ *azkeys.GetKeyOptions) (azkeys.GetKeyResponse, error) { if c.getKeyReturnsErr && c.getKeyCallCount < c.getKeyCallThreshold { c.getKeyCallCount++ return azkeys.GetKeyResponse{}, &azcore.ResponseError{ StatusCode: http.StatusNotFound, RawResponse: &http.Response{}, } } return azkeys.GetKeyResponse{ KeyBundle: azkeys.KeyBundle{ Key: &c.key, }, }, nil } type nonResponseErrClient struct { testKVClient keyCache *ttlcache.Cache[string, crypto.PublicKey] } func (c *nonResponseErrClient) GetKey(_ context.Context, _, _ string, _ *azkeys.GetKeyOptions) (result azkeys.GetKeyResponse, err error) { err = errors.New("unexpected error") return result, err } type non404RespClient struct { testKVClient keyCache *ttlcache.Cache[string, crypto.PublicKey] } func (c *non404RespClient) GetKey(_ context.Context, _, _ string, _ *azkeys.GetKeyOptions) (result azkeys.GetKeyResponse, err error) { err = &azcore.ResponseError{ StatusCode: http.StatusServiceUnavailable, } return result, err } func generatePublicKey(azureKeyType string) (azkeys.JSONWebKey, error) { keyOps := []*azkeys.KeyOperation{to.Ptr(azkeys.KeyOperationSign), to.Ptr(azkeys.KeyOperationVerify)} kid := "https://honk-vault.vault.azure.net/keys/honk-key/abc123" key := azkeys.JSONWebKey{ KID: to.Ptr(azkeys.ID(kid)), Kty: to.Ptr(azkeys.KeyType(azureKeyType)), Crv: to.Ptr(azkeys.CurveName("P-256")), KeyOps: keyOps, } keyType := azkeys.KeyType(azureKeyType) switch keyType { case azkeys.KeyTypeEC, azkeys.KeyTypeECHSM: privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return azkeys.JSONWebKey{}, err } ecdsaPub, ok := privKey.Public().(*ecdsa.PublicKey) if !ok { return azkeys.JSONWebKey{}, fmt.Errorf("failed to cast public key to esdsa public key") } key.X = ecdsaPub.X.Bytes() key.Y = ecdsaPub.Y.Bytes() return key, nil case azkeys.KeyTypeRSA, azkeys.KeyTypeRSAHSM: privKey, err := rsa.GenerateKey(rand.Reader, 256) if err != nil { return azkeys.JSONWebKey{}, err } rsaPub, ok := privKey.Public().(*rsa.PublicKey) if !ok { return azkeys.JSONWebKey{}, fmt.Errorf("failed to cast public key to rsa public key") } key.N = rsaPub.N.Bytes() key.E = []byte(fmt.Sprint(rsaPub.E)) return key, nil default: return azkeys.JSONWebKey{}, fmt.Errorf("invalid key type passed: %s", azureKeyType) } } func TestAzureVaultClientFetchPublicKey(t *testing.T) { type test struct { azureKeyType string expectSuccess bool } tests := []test{ { azureKeyType: "EC", expectSuccess: true, }, { azureKeyType: "EC-HSM", expectSuccess: true, }, { azureKeyType: "RSA", expectSuccess: true, }, { azureKeyType: "RSA-HSM", expectSuccess: true, }, } for _, tc := range tests { key, err := generatePublicKey(tc.azureKeyType) if err != nil { t.Fatalf("unexpected error while generating public key for testing: %v", err) } kvClient := testKVClient{key: key} client := azureVaultClient{ client: &kvClient, } _, err = client.fetchPublicKey(context.Background()) if err != nil && tc.expectSuccess { t.Fatalf("expected error to be nil, actual value: %v", err) } if err == nil && !tc.expectSuccess { t.Fatal("expected error not to be nil") } } } func TestAzureVaultClientCreateKey(t *testing.T) { type test struct { name string client kvClient expectSuccess bool } key, err := generatePublicKey("EC") if err != nil { t.Fatalf("unexpected error while generating public key for testing: %v", err) } tests := []test{ { name: "Successfully create key if it doesn't exist", client: &keyNotFoundClient{ key: key, getKeyReturnsErr: true, getKeyCallThreshold: 1, }, expectSuccess: true, }, { name: "Return public key if it already exists", client: &testKVClient{ key: key, }, expectSuccess: true, }, { name: "Fail to create key due to unknown error", client: &nonResponseErrClient{}, expectSuccess: false, }, { name: "Fail to create key due to non-404 status code error", client: &non404RespClient{}, expectSuccess: false, }, } for _, tc := range tests { client := azureVaultClient{ client: tc.client, keyCache: ttlcache.New[string, crypto.PublicKey]( ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](), ), } _, err = client.createKey(context.Background()) if err != nil && tc.expectSuccess { t.Fatalf("Test '%s' failed. Expected nil error, actual value: %v", tc.name, err) } if err == nil && !tc.expectSuccess { t.Fatalf("Test '%s' failed. Expected non-nil error", tc.name) } } } func TestGetAuthenticationMethod(t *testing.T) { clearEnv := map[string]string{ "AZURE_TENANT_ID": "", "AZURE_CLIENT_ID": "", "AZURE_CLIENT_SECRET": "", "AZURE_AUTH_METHOD": "", } resetEnv := testSetEnv(t, clearEnv) defer resetEnv() cases := []struct { testDescription string environmentVariables map[string]string expectedResult authenticationMethod }{ { testDescription: "No environment variables set", environmentVariables: map[string]string{}, expectedResult: unknownAuthenticationMethod, }, { testDescription: "AZURE_AUTH_METHOD=environment", environmentVariables: map[string]string{ "AZURE_AUTH_METHOD": "environment", }, expectedResult: environmentAuthenticationMethod, }, { testDescription: "AZURE_AUTH_METHOD=cli", environmentVariables: map[string]string{ "AZURE_AUTH_METHOD": "cli", }, expectedResult: cliAuthenticationMethod, }, { testDescription: "Set environment variables AZURE_TENANT_ID, AZURE_CLIENT_ID & AZURE_CLIENT_SECRET", environmentVariables: map[string]string{ "AZURE_TENANT_ID": "foo", "AZURE_CLIENT_ID": "bar", "AZURE_CLIENT_SECRET": "baz", }, expectedResult: environmentAuthenticationMethod, }, } for i, c := range cases { t.Logf("Test #%d: %s", i, c.testDescription) reset := testSetEnv(t, c.environmentVariables) result := getAuthenticationMethod() if result != c.expectedResult { t.Logf("got: %q, want: %q", result, c.expectedResult) t.Fail() } reset() } } func testSetEnv(t *testing.T, s map[string]string) func() { t.Helper() backup := map[string]string{} for k, v := range s { currentEnv := os.Getenv(k) backup[k] = currentEnv if v == "" { os.Unsetenv(k) continue } os.Setenv(k, v) } return func() { for k, v := range backup { if v == "" { os.Unsetenv(k) continue } os.Setenv(k, v) } } } func TestParseReference(t *testing.T) { tests := []struct { in string wantVaultURL string wantKeyName string wantKeyVersion string wantErr bool }{ { in: "azurekms://honk-vault.vault.azure.net/honk-key", wantVaultURL: "https://honk-vault.vault.azure.net/", wantKeyName: "honk-key", wantKeyVersion: "", wantErr: false, }, { in: "azurekms://honk-vault.vault.azure.net/honk-key/123abc", wantVaultURL: "https://honk-vault.vault.azure.net/", wantKeyName: "honk-key", wantKeyVersion: "123abc", wantErr: false, }, { in: "foo://bar", wantErr: true, }, { in: "", wantErr: true, }, { in: "azurekms://wrong-test/test/1/3", wantErr: true, }, } for _, tt := range tests { t.Run(tt.in, func(t *testing.T) { gotVaultURL, gotKeyName, gotKeyVersion, err := parseReference(tt.in) if (err != nil) != tt.wantErr { t.Errorf("parseReference() error = %v, wantErr %v", err, tt.wantErr) return } if gotVaultURL != tt.wantVaultURL { t.Errorf("parseReference() gotVaultURL = %v, want %v", gotVaultURL, tt.wantVaultURL) } if gotKeyName != tt.wantKeyName { t.Errorf("parseReference() gotKeyName = %v, want %v", gotKeyName, tt.wantKeyName) } if gotKeyVersion != tt.wantKeyVersion { t.Errorf("parseReference() gotKeyVersion = %v, want %v", gotKeyVersion, tt.wantKeyVersion) } }) } } sigstore-1.8.6/pkg/signature/kms/azure/doc.go000066400000000000000000000012541463713551000211720ustar00rootroot00000000000000// // 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 azure contains utilities related to Microsoft Azure KMS. package azure sigstore-1.8.6/pkg/signature/kms/azure/go.mod000066400000000000000000000031321463713551000212010ustar00rootroot00000000000000module github.com/sigstore/sigstore/pkg/signature/kms/azure replace github.com/sigstore/sigstore => ../../../../ go 1.22.0 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 github.com/go-jose/go-jose/v3 v3.0.3 github.com/google/go-cmp v0.6.0 github.com/jellydator/ttlcache/v3 v3.2.0 github.com/sigstore/sigstore v1.6.4 golang.org/x/crypto v0.24.0 ) require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.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/go-jose/go-jose/v4 v4.0.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/google/go-containerregistry v0.19.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) sigstore-1.8.6/pkg/signature/kms/azure/go.sum000066400000000000000000000311761463713551000212370ustar00rootroot00000000000000github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI= 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.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o= github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/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.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= 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/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= 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/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/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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 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/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= 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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= 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-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.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.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= 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.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-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.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.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.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/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= sigstore-1.8.6/pkg/signature/kms/azure/integration_test.go000066400000000000000000000144461463713551000240160ustar00rootroot00000000000000//go:build integration // // 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 azure contains utilities related to Microsoft Azure KMS. package azure import ( "bytes" "context" "fmt" "os" "strings" "testing" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" "github.com/google/go-cmp/cmp" ) /* The following environment variables must be set: AZURE_KEY_REF - full azure key reference in the format azurekms://[Key Vault Name].vault.azure.net/[Key Name](/[Key Version]Optional) KEY_NAME - Azure key name VAULT_URL - Azure Vault URL */ func TestMain(m *testing.M) { azureKeyRef := os.Getenv("AZURE_KEY_REF") if azureKeyRef == "" { panic("AZURE_KEY_REF must be set") } os.Exit(m.Run()) } func TestGetAzClientOpts(t *testing.T) { testCases := []struct { env string expectedConfig cloud.Configuration }{{ env: "AZUREUSGOVERNMENT", expectedConfig: cloud.AzureGovernment, }, { env: "AZUREUSGOVERNMENTCLOUD", expectedConfig: cloud.AzureGovernment, }, { env: "AZURECHINACLOUD", expectedConfig: cloud.AzureChina, }, { env: "AZURECLOUD", expectedConfig: cloud.AzurePublic, }, { env: "AZUREPUBLICCLOUD", expectedConfig: cloud.AzurePublic, }, { env: "", expectedConfig: cloud.AzurePublic, }} for _, tc := range testCases { t.Setenv("AZURE_ENVIRONMENT", tc.env) opts := getAzClientOpts() if !cmp.Equal(tc.expectedConfig, opts.Cloud) { t.Errorf("opts.Cloud %v does not match expected config: %v", opts.Cloud, tc.expectedConfig) } } } func TestLoadSignerVerifier(t *testing.T) { azureKeyRef := os.Getenv("AZURE_KEY_REF") azureKeyName := os.Getenv("KEY_NAME") if azureKeyName == "" { t.Fatalf("KEY_NAME must be set") } azureVaultURL := os.Getenv("VAULT_URL") if azureVaultURL == "" { t.Fatalf("VAULT_URL must be set") } azureKeyVersion := os.Getenv("KEY_VERSION") sv, err := LoadSignerVerifier(context.Background(), azureKeyRef) if err != nil { t.Errorf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } if sv == nil { t.Errorf("LoadSignerVerifier failed to create a SignerVerifier instance") } if sv.client.vaultURL != fmt.Sprintf("https://%s/", azureVaultURL) { t.Errorf("expected client.vaultURL to be %s, got %s", azureVaultURL, sv.client.vaultURL) } if sv.client.keyName != azureKeyName { t.Errorf("expected client.keyName to be %s, got %s", azureKeyName, sv.client.keyName) } if sv.client.keyVersion != azureKeyVersion { t.Errorf("expected client.keyVersion to be %s, got %s", azureKeyVersion, sv.client.keyVersion) } } func TestCreateKey(t *testing.T) { azureVaultURL := os.Getenv("VAULT_URL") if azureVaultURL == "" { t.Fatalf("VAULT_URL must be set") } newKeyRef := fmt.Sprintf("azurekms://%s.vault.azure.net/%s", azureVaultURL, "new-test-key") sv, err := LoadSignerVerifier(context.Background(), newKeyRef) if err != nil { t.Fatalf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } publicKey, err := sv.client.createKey(context.Background()) if err != nil { t.Errorf("getKey failed with error: %v", err) } if publicKey == nil { t.Errorf("public key is nil") } if _, ok := publicKey.(*ecdsa.PublicKey); !ok { t.Errorf("expected public key to be of type *ecdsa.PublicKey") } } func TestGetKey(t *testing.T) { azureKeyRef := os.Getenv("AZURE_KEY_REF") sv, err := LoadSignerVerifier(context.Background(), azureKeyRef) if err != nil { t.Fatalf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } keyBundle, err := sv.client.getKey(context.Background()) if err != nil { t.Errorf("getKey failed with error: %v", err) } if keyBundle.Key == nil { t.Errorf("key bundle key is nil") } } func TestPublicKey(t *testing.T) { azureKeyRef := os.Getenv("AZURE_KEY_REF") sv, err := LoadSignerVerifier(context.Background(), azureKeyRef) if err != nil { t.Fatalf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } pubKey, err := sv.PublicKey() if err != nil { t.Errorf("PublicKey failed with error: %v", err) } if pubKey == nil { t.Errorf("PublicKey response is nil") } } func TestGetKeyVaultHashFunc(t *testing.T) { azureKeyRef := os.Getenv("AZURE_KEY_REF") sv, err := LoadSignerVerifier(context.Background(), azureKeyRef) if err != nil { t.Fatalf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } _, _, err = sv.client.getKeyVaultHashFunc(context.Background()) if err != nil { t.Errorf("failed to get crypto hash and signature algorithm associated with key: %v", err) } } func TestSignMessage(t *testing.T) { azureKeyRef := os.Getenv("AZURE_KEY_REF") sv, err := LoadSignerVerifier(context.Background(), azureKeyRef) if err != nil { t.Fatalf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } messageToSign := strings.NewReader("myblob") signed, err := sv.SignMessage(messageToSign) if err != nil { t.Errorf("SignMessage unexpectedly returned non-nil error: %v", err) } if signed == nil || len(signed) == 0 { t.Errorf("SignMessage unexpected returned nil or empty signature") } } func TestVerifySignature(t *testing.T) { azureKeyRef := os.Getenv("AZURE_KEY_REF") sv, err := LoadSignerVerifier(context.Background(), azureKeyRef) if err != nil { t.Fatalf("LoadSignerVerifier unexpectedly returned non-nil error: %v", err) } messageToSign := "myblob" signed, err := sv.SignMessage(strings.NewReader(messageToSign)) if err != nil { t.Errorf("SignMessage unexpectedly returned non-nil error: %v", err) } if signed == nil || len(signed) == 0 { t.Errorf("SignMessage unexpected returned nil or empty signature") } err = sv.VerifySignature(bytes.NewReader(signed), strings.NewReader(messageToSign)) if err != nil { t.Errorf("VerifySignature unexpectedly returned non-nil error: %v", err) } } sigstore-1.8.6/pkg/signature/kms/azure/signer.go000066400000000000000000000156121463713551000217170ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package azure import ( "context" "crypto" "errors" "fmt" "io" "math/big" "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte/asn1" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" ) var azureSupportedHashFuncs = []crypto.Hash{ crypto.SHA256, crypto.SHA384, crypto.SHA512, } //nolint:revive const ( AlgorithmES256 = "ES256" AlgorithmES384 = "ES384" AlgorithmES512 = "ES512" ) var azureSupportedAlgorithms = []string{ AlgorithmES256, AlgorithmES384, AlgorithmES512, } // SignerVerifier creates and verifies digital signatures over a message using Azure KMS service type SignerVerifier struct { defaultCtx context.Context hashFunc crypto.Hash client *azureVaultClient } // LoadSignerVerifier generates signatures using the specified key in Azure Key Vault and hash algorithm. // // It also can verify signatures locally using the public key. hashFunc must not be crypto.Hash(0). func LoadSignerVerifier(defaultCtx context.Context, referenceStr string) (*SignerVerifier, error) { a := &SignerVerifier{ defaultCtx: defaultCtx, } var err error a.client, err = newAzureKMS(referenceStr) if err != nil { return nil, err } return a, nil } // SignMessage signs the provided message using Azure Key Vault. If the message is provided, // this method will compute the digest according to the hash function specified // when the Signer was created. // // SignMessage recognizes the following Options listed in order of preference: // // - WithContext() // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (a *SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) { var digest []byte for _, opt := range opts { opt.ApplyDigest(&digest) } hashFunc, _, err := a.client.getKeyVaultHashFunc(a.defaultCtx) if err != nil { return nil, err } digest, _, err = signature.ComputeDigestForSigning(message, hashFunc, azureSupportedHashFuncs, opts...) if err != nil { return nil, err } rawSig, err := a.client.sign(a.defaultCtx, digest) if err != nil { return nil, err } l := len(rawSig) r, s := &big.Int{}, &big.Int{} r.SetBytes(rawSig[0 : l/2]) s.SetBytes(rawSig[l/2:]) // Convert the concatenated r||s byte string to an ASN.1 sequence // This logic is borrowed from https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/ecdsa/ecdsa.go;l=121 var b cryptobyte.Builder b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { b.AddASN1BigInt(r) b.AddASN1BigInt(s) }) return b.Bytes() } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the SignerVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (a *SignerVerifier) VerifySignature(sig, message io.Reader, opts ...signature.VerifyOption) error { hashFunc, _, err := a.client.getKeyVaultHashFunc(a.defaultCtx) if err != nil { return err } var digest []byte var signerOpts crypto.SignerOpts = hashFunc for _, opt := range opts { opt.ApplyDigest(&digest) } digest, _, err = signature.ComputeDigestForVerifying(message, signerOpts.HashFunc(), azureSupportedHashFuncs, opts...) if err != nil { return err } sigBytes, err := io.ReadAll(sig) if err != nil { return fmt.Errorf("reading signature: %w", err) } // Convert the ASN.1 Sequence to a concatenated r||s byte string // This logic is borrowed from https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/crypto/ecdsa/ecdsa.go;l=339 var ( r, s = &big.Int{}, &big.Int{} inner cryptobyte.String ) input := cryptobyte.String(sigBytes) if !input.ReadASN1(&inner, asn1.SEQUENCE) || !input.Empty() || !inner.ReadASN1Integer(r) || !inner.ReadASN1Integer(s) || !inner.Empty() { return errors.New("parsing signature") } rawSigBytes := []byte{} rawSigBytes = append(rawSigBytes, r.Bytes()...) rawSigBytes = append(rawSigBytes, s.Bytes()...) return a.client.verify(a.defaultCtx, rawSigBytes, digest) } // PublicKey returns the public key that can be used to verify signatures created by // this signer. All options provided in arguments to this method are ignored. func (a *SignerVerifier) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { return a.client.public(a.defaultCtx) } // CreateKey attempts to create a new key in Vault with the specified algorithm. func (a *SignerVerifier) CreateKey(ctx context.Context, _ string) (crypto.PublicKey, error) { return a.client.createKey(ctx) } type cryptoSignerWrapper struct { ctx context.Context hashFunc crypto.Hash sv *SignerVerifier errFunc func(error) } func (c cryptoSignerWrapper) Public() crypto.PublicKey { pk, err := c.sv.PublicKey(options.WithContext(c.ctx)) if err != nil && c.errFunc != nil { c.errFunc(err) } return pk } func (c cryptoSignerWrapper) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { hashFunc := c.hashFunc if opts != nil { hashFunc = opts.HashFunc() } azOptions := []signature.SignOption{ options.WithContext(c.ctx), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc), } return c.sv.SignMessage(nil, azOptions...) } // CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object // that allows the KMS to be used in APIs that only accept the standard golang objects func (a *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { hashFunc, _, err := a.client.getKeyVaultHashFunc(a.defaultCtx) if err != nil { return nil, nil, err } csw := &cryptoSignerWrapper{ ctx: ctx, sv: a, hashFunc: hashFunc, errFunc: errFunc, } return csw, hashFunc, nil } // SupportedAlgorithms returns the list of algorithms supported by the Azure KMS service func (*SignerVerifier) SupportedAlgorithms() []string { return azureSupportedAlgorithms } // DefaultAlgorithm returns the default algorithm for the Azure KMS service func (*SignerVerifier) DefaultAlgorithm() string { return AlgorithmES256 } sigstore-1.8.6/pkg/signature/kms/doc.go000066400000000000000000000012561463713551000200460ustar00rootroot00000000000000// // 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 kms contains utilities related to third-party KMS providers. package kms sigstore-1.8.6/pkg/signature/kms/fake/000077500000000000000000000000001463713551000176545ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/kms/fake/doc.go000066400000000000000000000012461463713551000207530ustar00rootroot00000000000000// // 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 fake contains utilities to help test KMS providers. package fake sigstore-1.8.6/pkg/signature/kms/fake/signer.go000066400000000000000000000116111463713551000214720ustar00rootroot00000000000000// 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 fake implements fake signer to be used in tests package fake import ( "context" "crypto" "io" "github.com/sigstore/sigstore/pkg/signature" sigkms "github.com/sigstore/sigstore/pkg/signature/kms" "github.com/sigstore/sigstore/pkg/signature/options" ) // KmsCtxKey is used to look up the private key in the struct. type KmsCtxKey struct{} // SignerVerifier creates and verifies digital signatures over a message using an in-memory signer type SignerVerifier struct { signer signature.SignerVerifier } // ReferenceScheme is a scheme for fake KMS keys. Do not use in production. const ReferenceScheme = "fakekms://" func init() { sigkms.AddProvider(ReferenceScheme, func(ctx context.Context, _ string, hf crypto.Hash, _ ...signature.RPCOption) (sigkms.SignerVerifier, error) { return LoadSignerVerifier(ctx, hf) }) } // LoadSignerVerifier generates a signer/verifier using the default ECDSA signer or loads // a signer from a provided private key and hash. The context should contain a mapping from // a string "priv" to a crypto.PrivateKey (RSA, ECDSA, or ED25519). func LoadSignerVerifier(ctx context.Context, hf crypto.Hash) (*SignerVerifier, error) { val := ctx.Value(KmsCtxKey{}) if val == nil { signer, _, err := signature.NewDefaultECDSASignerVerifier() if err != nil { return nil, err } sv := &SignerVerifier{ signer: signer, } return sv, nil } signer, err := signature.LoadSignerVerifier(val.(crypto.PrivateKey), hf) if err != nil { return nil, err } sv := &SignerVerifier{ signer: signer, } return sv, nil } // SignMessage signs the provided message using the in-memory signer. func (g *SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) { return g.signer.SignMessage(message, opts...) } // PublicKey returns the public key that can be used to verify signatures created by // this signer. func (g *SignerVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { return g.signer.PublicKey(opts...) } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the SignerVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (g *SignerVerifier) VerifySignature(signature, message io.Reader, opts ...signature.VerifyOption) error { return g.signer.VerifySignature(signature, message, opts...) } // CreateKey returns the signer's public key. func (g *SignerVerifier) CreateKey(_ context.Context, _ string) (crypto.PublicKey, error) { pub, err := g.signer.PublicKey() if err != nil { return nil, err } return pub, nil } type cryptoSignerWrapper struct { ctx context.Context hashFunc crypto.Hash sv *SignerVerifier errFunc func(error) } func (c cryptoSignerWrapper) Public() crypto.PublicKey { pk, err := c.sv.PublicKey(options.WithContext(c.ctx)) if err != nil && c.errFunc != nil { c.errFunc(err) } return pk } func (c cryptoSignerWrapper) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { hashFunc := c.hashFunc if opts != nil { hashFunc = opts.HashFunc() } gcpOptions := []signature.SignOption{ options.WithContext(c.ctx), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc), } return c.sv.SignMessage(nil, gcpOptions...) } // CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object // that allows the KMS to be used in APIs that only accept the standard golang objects func (g *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { csw := &cryptoSignerWrapper{ ctx: ctx, sv: g, hashFunc: crypto.SHA256, errFunc: errFunc, } return csw, crypto.SHA256, nil } // SupportedAlgorithms returns a list with the default algorithm func (g *SignerVerifier) SupportedAlgorithms() (result []string) { return []string{"ecdsa-p256-sha256"} } // DefaultAlgorithm returns the default algorithm for the signer func (g *SignerVerifier) DefaultAlgorithm() string { return "ecdsa-p256-sha256" } sigstore-1.8.6/pkg/signature/kms/fake/signer_test.go000066400000000000000000000076171463713551000225440ustar00rootroot00000000000000// 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 fake import ( "bytes" "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/kms" ) func TestFakeSigner(t *testing.T) { msg := []byte{1, 2, 3, 4, 5} signer, err := kms.Get(context.Background(), "fakekms://key", crypto.SHA256) if err != nil { t.Fatalf("unexpected error getting signer: %v", err) } pub, err := signer.PublicKey() if err != nil { t.Fatalf("unexpected error getting public key") } createdPub, err := signer.CreateKey(context.Background(), "") if err != nil { t.Fatalf("unexpected error creating key: %v", err) } if err := cryptoutils.EqualKeys(createdPub, pub); err != nil { t.Fatalf("expected public keys to be equal: %v", err) } if signer.DefaultAlgorithm() != signer.SupportedAlgorithms()[0] { t.Fatal("expected algorithms to match") } // Test crypto.Signer implementation cryptoSigner, _, err := signer.CryptoSigner(context.Background(), func(_ error) {}) if err != nil { t.Fatalf("unexpected error fetching crypto.Signer: %v", err) } if err := cryptoutils.EqualKeys(cryptoSigner.Public(), pub); err != nil { t.Fatalf("expected public keys to be equal: %v", err) } sha := sha256.New() sha.Write(msg) digest := sha.Sum(nil) sig, err := cryptoSigner.Sign(rand.Reader, digest, nil) if err != nil { t.Fatalf("unexpected error signing with crypto.Signer: %v", err) } if err := signer.VerifySignature(bytes.NewReader(sig), bytes.NewReader(msg)); err != nil { t.Fatalf("unexpected error verifying signature: %v", err) } } func TestFakeSignerWithPrivateKey(t *testing.T) { msg := []byte{1, 2, 3, 4, 5} priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("error generating ecdsa private key: %v", err) } signer, err := kms.Get(context.WithValue(context.TODO(), KmsCtxKey{}, priv), "fakekms://key", crypto.SHA256) if err != nil { t.Fatalf("unexpected error getting signer: %v", err) } pub, err := signer.PublicKey() if err != nil { t.Fatalf("unexpected error getting public key") } // Compare public key to provided key if err := cryptoutils.EqualKeys(priv.Public(), pub); err != nil { t.Fatalf("expected public keys to be equal: %v", err) } createdPub, err := signer.CreateKey(context.Background(), "") if err != nil { t.Fatalf("unexpected error creating key: %v", err) } if err := cryptoutils.EqualKeys(createdPub, pub); err != nil { t.Fatalf("expected public keys to be equal: %v", err) } if signer.DefaultAlgorithm() != signer.SupportedAlgorithms()[0] { t.Fatal("expected algorithms to match") } // Test crypto.Signer implementation cryptoSigner, _, err := signer.CryptoSigner(context.Background(), func(_ error) {}) if err != nil { t.Fatalf("unexpected error fetching crypto.Signer: %v", err) } if err := cryptoutils.EqualKeys(cryptoSigner.Public(), pub); err != nil { t.Fatalf("expected public keys to be equal: %v", err) } sha := sha256.New() sha.Write(msg) digest := sha.Sum(nil) sig, err := cryptoSigner.Sign(rand.Reader, digest, nil) if err != nil { t.Fatalf("unexpected error signing with crypto.Signer: %v", err) } if err := signer.VerifySignature(bytes.NewReader(sig), bytes.NewReader(msg)); err != nil { t.Fatalf("unexpected error verifying signature: %v", err) } } sigstore-1.8.6/pkg/signature/kms/gcp/000077500000000000000000000000001463713551000175175ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/kms/gcp/client.go000066400000000000000000000336501463713551000213330ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package gcp implement the interface with google cloud kms service package gcp import ( "context" "crypto" "crypto/ecdsa" "crypto/rsa" "errors" "fmt" "hash/crc32" "io" "log" "regexp" "time" gcpkms "cloud.google.com/go/kms/apiv1" "cloud.google.com/go/kms/apiv1/kmspb" "google.golang.org/api/option" "google.golang.org/protobuf/types/known/wrapperspb" "github.com/jellydator/ttlcache/v3" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" sigkms "github.com/sigstore/sigstore/pkg/signature/kms" "github.com/sigstore/sigstore/pkg/signature/options" ) func init() { sigkms.AddProvider(ReferenceScheme, func(ctx context.Context, keyResourceID string, _ crypto.Hash, opts ...signature.RPCOption) (sigkms.SignerVerifier, error) { return LoadSignerVerifier(ctx, keyResourceID) }) } //nolint:revive const ( AlgorithmECDSAP256SHA256 = "ecdsa-p256-sha256" AlgorithmECDSAP384SHA384 = "ecdsa-p384-sha384" AlgorithmRSAPKCS1v152048SHA256 = "rsa-pkcs1v15-2048-sha256" AlgorithmRSAPKCS1v153072SHA256 = "rsa-pkcs1v15-3072-sha256" AlgorithmRSAPKCS1v154096SHA256 = "rsa-pkcs1v15-4096-sha256" AlgorithmRSAPKCS1v154096SHA512 = "rsa-pkcs1v15-4096-sha512" AlgorithmRSAPSS2048SHA256 = "rsa-pss-2048-sha256" AlgorithmRSAPSS3072SHA256 = "rsa-pss-3072-sha256" AlgorithmRSAPSS4096SHA256 = "rsa-pss-4096-sha256" AlgorithmRSAPSS4096SHA512 = "rsa-pss-4096-sha512" ) var algorithmMap = map[string]kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm{ AlgorithmECDSAP256SHA256: kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256, AlgorithmECDSAP384SHA384: kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384, AlgorithmRSAPKCS1v152048SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, AlgorithmRSAPKCS1v153072SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256, AlgorithmRSAPKCS1v154096SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256, AlgorithmRSAPKCS1v154096SHA512: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512, AlgorithmRSAPSS2048SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, AlgorithmRSAPSS3072SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, AlgorithmRSAPSS4096SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256, AlgorithmRSAPSS4096SHA512: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512, } type gcpClient struct { defaultCtx context.Context refString string projectID string locationID string keyRing string keyName string version string kvCache *ttlcache.Cache[string, cryptoKeyVersion] kmsClient *gcpkms.KeyManagementClient } func newGCPClient(ctx context.Context, refStr string, opts ...option.ClientOption) (*gcpClient, error) { if err := ValidReference(refStr); err != nil { return nil, err } if ctx == nil { ctx = context.Background() } g := &gcpClient{ defaultCtx: ctx, refString: refStr, kvCache: nil, } var err error g.projectID, g.locationID, g.keyRing, g.keyName, g.version, err = parseReference(refStr) if err != nil { return nil, err } g.kmsClient, err = gcpkms.NewKeyManagementClient(ctx, opts...) if err != nil { return nil, fmt.Errorf("new gcp kms client: %w", err) } g.kvCache = ttlcache.New[string, cryptoKeyVersion]( ttlcache.WithDisableTouchOnHit[string, cryptoKeyVersion](), ) // prime the cache g.kvCache.Get(cacheKey) return g, nil } var ( errKMSReference = errors.New("kms specification should be in the format gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]") re = regexp.MustCompile(`^gcpkms://projects/([^/]+)/locations/([^/]+)/keyRings/([^/]+)/cryptoKeys/([^/]+)(?:/(?:cryptoKeyVersions|versions)/([^/]+))?$`) ) // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets const ReferenceScheme = "gcpkms://" // ValidReference returns a non-nil error if the reference string is invalid func ValidReference(ref string) error { if !re.MatchString(ref) { return errKMSReference } return nil } func parseReference(resourceID string) (projectID, locationID, keyRing, keyName, version string, err error) { v := re.FindStringSubmatch(resourceID) if len(v) != 6 { err = fmt.Errorf("invalid gcpkms format %q", resourceID) return } projectID, locationID, keyRing, keyName, version = v[1], v[2], v[3], v[4], v[5] return } type cryptoKeyVersion struct { CryptoKeyVersion *kmspb.CryptoKeyVersion Verifier signature.Verifier HashFunc crypto.Hash } // use a consistent key for cache lookups const cacheKey = "crypto_key_version" // keyVersionName returns the first key version found for a key in KMS func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, error) { parent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName) parentReq := &kmspb.GetCryptoKeyRequest{ Name: parent, } key, err := g.kmsClient.GetCryptoKey(ctx, parentReq) if err != nil { return nil, err } if key.Purpose != kmspb.CryptoKey_ASYMMETRIC_SIGN { return nil, errors.New("specified key cannot be used to sign") } // if g.version was specified, use it explicitly var kv *kmspb.CryptoKeyVersion if g.version != "" { req := &kmspb.GetCryptoKeyVersionRequest{ Name: parent + fmt.Sprintf("/cryptoKeyVersions/%s", g.version), } kv, err = g.kmsClient.GetCryptoKeyVersion(ctx, req) if err != nil { return nil, err } } else { req := &kmspb.ListCryptoKeyVersionsRequest{ Parent: parent, Filter: "state=ENABLED", OrderBy: "name desc", } iterator := g.kmsClient.ListCryptoKeyVersions(ctx, req) // pick the key version that is enabled with the greatest version value kv, err = iterator.Next() if err != nil { return nil, fmt.Errorf("unable to find an enabled key version in GCP KMS: %w", err) } } // kv is keyVersion to use crv := cryptoKeyVersion{ CryptoKeyVersion: kv, } pubKey, err := g.fetchPublicKey(ctx, kv.Name) if err != nil { return nil, fmt.Errorf("unable to fetch public key while creating signer: %w", err) } // crv.Verifier is set here to enable storing the public key & hash algorithm together, // as well as using the in memory Verifier to perform the verify operations. switch kv.Algorithm { case kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256: crv.Verifier, err = signature.LoadECDSAVerifier(pubKey.(*ecdsa.PublicKey), crypto.SHA256) crv.HashFunc = crypto.SHA256 case kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384: crv.Verifier, err = signature.LoadECDSAVerifier(pubKey.(*ecdsa.PublicKey), crypto.SHA384) crv.HashFunc = crypto.SHA384 case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256, kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256: crv.Verifier, err = signature.LoadRSAPKCS1v15Verifier(pubKey.(*rsa.PublicKey), crypto.SHA256) crv.HashFunc = crypto.SHA256 case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512: crv.Verifier, err = signature.LoadRSAPKCS1v15Verifier(pubKey.(*rsa.PublicKey), crypto.SHA512) crv.HashFunc = crypto.SHA512 case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256: crv.Verifier, err = signature.LoadRSAPSSVerifier(pubKey.(*rsa.PublicKey), crypto.SHA256, nil) crv.HashFunc = crypto.SHA256 case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512: crv.Verifier, err = signature.LoadRSAPSSVerifier(pubKey.(*rsa.PublicKey), crypto.SHA512, nil) crv.HashFunc = crypto.SHA512 default: return nil, errors.New("unknown algorithm specified by KMS") } if err != nil { return nil, fmt.Errorf("initializing internal verifier: %w", err) } return &crv, nil } func (g *gcpClient) fetchPublicKey(ctx context.Context, name string) (crypto.PublicKey, error) { // Build the request. pkreq := &kmspb.GetPublicKeyRequest{Name: name} // Call the API. pk, err := g.kmsClient.GetPublicKey(ctx, pkreq) if err != nil { return nil, fmt.Errorf("public key: %w", err) } return cryptoutils.UnmarshalPEMToPublicKey([]byte(pk.GetPem())) } func (g *gcpClient) getHashFunc() (crypto.Hash, error) { ckv, err := g.getCKV() if err != nil { return 0, err } return ckv.HashFunc, nil } // getCKV gets the latest CryptoKeyVersion from the client's cache, which may trigger an actual // call to GCP if the existing entry in the cache has expired. func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) { var lerr error loader := ttlcache.LoaderFunc[string, cryptoKeyVersion]( func(c *ttlcache.Cache[string, cryptoKeyVersion], key string) *ttlcache.Item[string, cryptoKeyVersion] { var ttl time.Duration var data *cryptoKeyVersion // if we're given an explicit version, cache this value forever if g.version != "" { ttl = time.Second * 0 } else { ttl = time.Second * 300 } data, lerr = g.keyVersionName(context.Background()) if lerr == nil { return c.Set(key, *data, ttl) } return nil }, ) // we get once and use consistently to ensure the cache value doesn't change underneath us item := g.kvCache.Get(cacheKey, ttlcache.WithLoader[string, cryptoKeyVersion](loader)) if item != nil { v := item.Value() return &v, nil } return nil, lerr } func (g *gcpClient) sign(ctx context.Context, digest []byte, alg crypto.Hash, crc uint32) ([]byte, error) { ckv, err := g.getCKV() if err != nil { return nil, err } gcpSignReq := kmspb.AsymmetricSignRequest{ Name: ckv.CryptoKeyVersion.Name, Digest: &kmspb.Digest{}, } if crc != 0 { gcpSignReq.DigestCrc32C = wrapperspb.Int64(int64(crc)) } switch alg { case crypto.SHA256: gcpSignReq.Digest.Digest = &kmspb.Digest_Sha256{ Sha256: digest, } case crypto.SHA384: gcpSignReq.Digest.Digest = &kmspb.Digest_Sha384{ Sha384: digest, } case crypto.SHA512: gcpSignReq.Digest.Digest = &kmspb.Digest_Sha512{ Sha512: digest, } default: return nil, errors.New("unsupported hash function") } resp, err := g.kmsClient.AsymmetricSign(ctx, &gcpSignReq) if err != nil { return nil, fmt.Errorf("calling GCP AsymmetricSign: %w", err) } // Optional, but recommended: perform integrity verification on result. // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: // https://cloud.google.com/kms/docs/data-integrity-guidelines if crc != 0 && !resp.VerifiedDigestCrc32C { return nil, fmt.Errorf("AsymmetricSign: request corrupted in-transit") } if int64(crc32.Checksum(resp.Signature, crc32.MakeTable(crc32.Castagnoli))) != resp.SignatureCrc32C.Value { return nil, fmt.Errorf("AsymmetricSign: response corrupted in-transit") } return resp.Signature, nil } func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { crv, err := g.getCKV() if err != nil { return nil, fmt.Errorf("transient error getting info from KMS: %w", err) } return crv.Verifier.PublicKey(options.WithContext(ctx)) } func (g *gcpClient) verify(sig, message io.Reader, opts ...signature.VerifyOption) error { crv, err := g.getCKV() if err != nil { return fmt.Errorf("transient error getting info from KMS: %w", err) } if err := crv.Verifier.VerifySignature(sig, message, opts...); err != nil { // key could have been rotated, clear cache and try again if we're not pinned to a version if g.version == "" { g.kvCache.Delete(cacheKey) crv, err = g.getCKV() if err != nil { return fmt.Errorf("transient error getting info from KMS: %w", err) } return crv.Verifier.VerifySignature(sig, message, opts...) } return fmt.Errorf("failed to verify for fixed version: %w", err) } return nil } func (g *gcpClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { if err := g.createKeyRing(ctx); err != nil { return nil, fmt.Errorf("creating key ring: %w", err) } getKeyRequest := &kmspb.GetCryptoKeyRequest{ Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName), } if _, err := g.kmsClient.GetCryptoKey(ctx, getKeyRequest); err == nil { return g.public(ctx) } if _, ok := algorithmMap[algorithm]; !ok { return nil, errors.New("unknown algorithm requested") } createKeyRequest := &kmspb.CreateCryptoKeyRequest{ Parent: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", g.projectID, g.locationID, g.keyRing), CryptoKeyId: g.keyName, CryptoKey: &kmspb.CryptoKey{ Purpose: kmspb.CryptoKey_ASYMMETRIC_SIGN, VersionTemplate: &kmspb.CryptoKeyVersionTemplate{ Algorithm: algorithmMap[algorithm], }, }, } if _, err := g.kmsClient.CreateCryptoKey(ctx, createKeyRequest); err != nil { return nil, fmt.Errorf("creating crypto key: %w", err) } return g.public(ctx) } func (g *gcpClient) createKeyRing(ctx context.Context) error { getKeyRingRequest := &kmspb.GetKeyRingRequest{ Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", g.projectID, g.locationID, g.keyRing), } if result, err := g.kmsClient.GetKeyRing(ctx, getKeyRingRequest); err == nil { log.Printf("Key ring %s already exists in GCP KMS, moving on to creating key.\n", result.GetName()) // key ring already exists, no need to create return nil } // try to create key ring createKeyRingRequest := &kmspb.CreateKeyRingRequest{ Parent: fmt.Sprintf("projects/%s/locations/%s", g.projectID, g.locationID), KeyRingId: g.keyRing, } result, err := g.kmsClient.CreateKeyRing(ctx, createKeyRingRequest) log.Printf("Created key ring %s in GCP KMS.\n", result.GetName()) return err } sigstore-1.8.6/pkg/signature/kms/gcp/doc.go000066400000000000000000000012561463713551000206170ustar00rootroot00000000000000// // 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 gcp contains utilities related to Google Cloud Platform KMS. package gcp sigstore-1.8.6/pkg/signature/kms/gcp/gcp_test.go000066400000000000000000000063731463713551000216670ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp import ( "context" "testing" "golang.org/x/oauth2" "google.golang.org/api/option" ) func TestParseReference(t *testing.T) { tests := []struct { in string wantProjectID string wantLocationID string wantKeyRing string wantKeyName string wantKeyVersion string wantErr bool }{ { in: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", wantProjectID: "pp", wantLocationID: "ll", wantKeyRing: "rr", wantKeyName: "kk", wantErr: false, }, { in: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk/versions/1", wantProjectID: "pp", wantLocationID: "ll", wantKeyRing: "rr", wantKeyName: "kk", wantKeyVersion: "1", wantErr: false, }, { in: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk/cryptoKeyVersions/1", wantProjectID: "pp", wantLocationID: "ll", wantKeyRing: "rr", wantKeyName: "kk", wantKeyVersion: "1", wantErr: false, }, { in: "gcpkms://projects/p1/p2/locations/l1/l2/keyRings/r1/r2/cryptoKeys/k1/k2", wantErr: true, }, { in: "foo://bar", wantErr: true, }, { in: "", wantErr: true, }, { in: "gcpkms://projects/p1/p2/locations/l1/l2/keyRings/r1/r2/cryptoKeys/k1/versions", wantErr: true, }, } for _, tt := range tests { t.Run(tt.in, func(t *testing.T) { gotProjectID, gotLocationID, gotKeyRing, gotKeyName, gotKeyVersion, err := parseReference(tt.in) if (err != nil) != tt.wantErr { t.Errorf("parseReference() error = %v, wantErr %v", err, tt.wantErr) return } if gotProjectID != tt.wantProjectID { t.Errorf("parseReference() gotProjectID = %v, want %v", gotProjectID, tt.wantProjectID) } if gotLocationID != tt.wantLocationID { t.Errorf("parseReference() gotLocationID = %v, want %v", gotLocationID, tt.wantLocationID) } if gotKeyRing != tt.wantKeyRing { t.Errorf("parseReference() gotKeyRing = %v, want %v", gotKeyRing, tt.wantKeyRing) } if gotKeyName != tt.wantKeyName { t.Errorf("parseReference() gotKeyName = %v, want %v", gotKeyName, tt.wantKeyName) } if gotKeyVersion != tt.wantKeyVersion { t.Errorf("parseReference() gotKeyVersion = %v, want %v", gotKeyVersion, tt.wantKeyVersion) } }) } } func TestOptionsWork(_ *testing.T) { // Check that we can pass options into LoadSignerVerifier // (this is mostly a compile-time check) ts := oauth2.StaticTokenSource(&oauth2.Token{}) LoadSignerVerifier(context.Background(), "gcpkms://projects/a-project/locations/global/keyRings/a-keyring/cryptoKeys/key-name", option.WithTokenSource(ts)) } sigstore-1.8.6/pkg/signature/kms/gcp/go.mod000066400000000000000000000046771463713551000206430ustar00rootroot00000000000000module github.com/sigstore/sigstore/pkg/signature/kms/gcp replace github.com/sigstore/sigstore => ../../../../ go 1.22.0 require ( cloud.google.com/go/kms v1.18.0 github.com/jellydator/ttlcache/v3 v3.2.0 github.com/sigstore/sigstore v1.6.4 golang.org/x/oauth2 v0.21.0 google.golang.org/api v0.185.0 google.golang.org/protobuf v1.34.2 ) require ( cloud.google.com/go v0.115.0 // indirect cloud.google.com/go/auth v0.5.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.8 // indirect cloud.google.com/go/longrunning v0.5.7 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-containerregistry v0.19.2 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.4 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // 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.52.0 // indirect go.opentelemetry.io/otel v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect go.opentelemetry.io/otel/trace v1.27.0 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect google.golang.org/grpc v1.64.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) sigstore-1.8.6/pkg/signature/kms/gcp/go.sum000066400000000000000000000473101463713551000206570ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= cloud.google.com/go/kms v1.18.0 h1:pqNdaVmZJFP+i8OVLocjfpdTWETTYa20FWOegSCdrRo= cloud.google.com/go/kms v1.18.0/go.mod h1:DyRBeWD/pYBMeyiaXFa/DGNyxMDL3TslIKb8o/JkLkw= cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/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.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/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-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/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/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.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= 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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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/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.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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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= 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.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0= go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= 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.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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/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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.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/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.185.0 h1:ENEKk1k4jW8SmmaT6RE+ZasxmxezCrD5Vw4npvr+pAU= google.golang.org/api v0.185.0/go.mod h1:HNfvIkJGlgrIlrbYkAm9W9IdkmKZjOTVh33YltygGbg= 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-20240617180043-68d350f18fd4 h1:CUiCqkPw1nNrNQzCCG4WA65m0nAmQiwXHpub3dNyruU= google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4/go.mod h1:EvuUDCulqGgV80RvP1BHuom+smhX4qtlhnNatHuroGQ= google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3 h1:QW9+G6Fir4VcRXVH8x3LilNAb6cxBGLa6+GM4hRwexE= google.golang.org/genproto/googleapis/api v0.0.0-20240610135401-a8a62080eff3/go.mod h1:kdrSS/OiLkPrNUpzD4aHgCq2rVuC/YRxok32HXZ4vRE= google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= 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/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= sigstore-1.8.6/pkg/signature/kms/gcp/signer.go000066400000000000000000000133671463713551000213470ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp import ( "context" "crypto" "fmt" "hash/crc32" "io" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" "google.golang.org/api/option" ) var gcpSupportedHashFuncs = []crypto.Hash{ crypto.SHA256, crypto.SHA512, crypto.SHA384, } // SignerVerifier creates and verifies digital signatures over a message using GCP KMS service type SignerVerifier struct { defaultCtx context.Context client *gcpClient } // LoadSignerVerifier generates signatures using the specified key object in GCP KMS and hash algorithm. // // It also can verify signatures locally using the public key. hashFunc must not be crypto.Hash(0). func LoadSignerVerifier(defaultCtx context.Context, referenceStr string, opts ...option.ClientOption) (*SignerVerifier, error) { g := &SignerVerifier{ defaultCtx: defaultCtx, } var err error g.client, err = newGCPClient(defaultCtx, referenceStr, opts...) if err != nil { return nil, err } return g, nil } // SignMessage signs the provided message using GCP KMS. If the message is provided, // this method will compute the digest according to the hash function specified // when the Signer was created. // // SignMessage recognizes the following Options listed in order of preference: // // - WithContext() // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (g *SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) { ctx := context.Background() var digest []byte var signerOpts crypto.SignerOpts var err error signerOpts, err = g.client.getHashFunc() if err != nil { return nil, fmt.Errorf("getting fetching default hash function: %w", err) } for _, opt := range opts { opt.ApplyContext(&ctx) opt.ApplyDigest(&digest) opt.ApplyCryptoSignerOpts(&signerOpts) } digest, hf, err := signature.ComputeDigestForSigning(message, signerOpts.HashFunc(), gcpSupportedHashFuncs, opts...) if err != nil { return nil, err } crc32cHasher := crc32.New(crc32.MakeTable(crc32.Castagnoli)) _, err = crc32cHasher.Write(digest) if err != nil { return nil, err } return g.client.sign(ctx, digest, hf, crc32cHasher.Sum32()) } // PublicKey returns the public key that can be used to verify signatures created by // this signer. If the caller wishes to specify the context to use to obtain // the public key, pass option.WithContext(desiredCtx). // // All other options are ignored if specified. func (g *SignerVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) { ctx := context.Background() for _, opt := range opts { opt.ApplyContext(&ctx) } return g.client.public(ctx) } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the SignerVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (g *SignerVerifier) VerifySignature(signature, message io.Reader, opts ...signature.VerifyOption) error { return g.client.verify(signature, message, opts...) } // CreateKey attempts to create a new key in Vault with the specified algorithm. func (g *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { return g.client.createKey(ctx, algorithm) } type cryptoSignerWrapper struct { ctx context.Context hashFunc crypto.Hash sv *SignerVerifier errFunc func(error) } func (c cryptoSignerWrapper) Public() crypto.PublicKey { pk, err := c.sv.PublicKey(options.WithContext(c.ctx)) if err != nil && c.errFunc != nil { c.errFunc(err) } return pk } func (c cryptoSignerWrapper) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { hashFunc := c.hashFunc if opts != nil { hashFunc = opts.HashFunc() } gcpOptions := []signature.SignOption{ options.WithContext(c.ctx), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc), } return c.sv.SignMessage(nil, gcpOptions...) } // CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object // that allows the KMS to be used in APIs that only accept the standard golang objects func (g *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { defaultHf, err := g.client.getHashFunc() if err != nil { return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err) } csw := &cryptoSignerWrapper{ ctx: ctx, sv: g, hashFunc: defaultHf, errFunc: errFunc, } return csw, defaultHf, nil } // SupportedAlgorithms returns the list of algorithms supported by the GCP KMS service func (g *SignerVerifier) SupportedAlgorithms() (result []string) { for k := range algorithmMap { result = append(result, k) } return } // DefaultAlgorithm returns the default algorithm for the GCP KMS service func (g *SignerVerifier) DefaultAlgorithm() string { return AlgorithmECDSAP256SHA256 } sigstore-1.8.6/pkg/signature/kms/hashivault/000077500000000000000000000000001463713551000211165ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/kms/hashivault/client.go000066400000000000000000000251331463713551000227270ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package hashivault implement the interface with hashivault kms service package hashivault import ( "context" "crypto" "encoding/base64" "encoding/json" "errors" "fmt" "log" "os" "path/filepath" "regexp" "strconv" "time" vault "github.com/hashicorp/vault/api" "github.com/jellydator/ttlcache/v3" "github.com/mitchellh/go-homedir" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" sigkms "github.com/sigstore/sigstore/pkg/signature/kms" ) func init() { sigkms.AddProvider(ReferenceScheme, func(_ context.Context, keyResourceID string, hashFunc crypto.Hash, opts ...signature.RPCOption) (sigkms.SignerVerifier, error) { return LoadSignerVerifier(keyResourceID, hashFunc, opts...) }) } type hashivaultClient struct { client *vault.Client keyPath string transitSecretEnginePath string keyCache *ttlcache.Cache[string, crypto.PublicKey] keyVersion uint64 } var ( errReference = errors.New("kms specification should be in the format hashivault://") referenceRegex = regexp.MustCompile(`^hashivault://(?P\w(([\w-.]+)?\w)?)$`) prefixRegex = regexp.MustCompile("^vault:v[0-9]+:") ) const ( vaultV1DataPrefix = "vault:v1:" // use a consistent key for cache lookups cacheKey = "signer" // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets ReferenceScheme = "hashivault://" ) // ValidReference returns a non-nil error if the reference string is invalid func ValidReference(ref string) error { if !referenceRegex.MatchString(ref) { return errReference } return nil } func parseReference(resourceID string) (keyPath string, err error) { i := referenceRegex.SubexpIndex("path") v := referenceRegex.FindStringSubmatch(resourceID) if len(v) < i+1 { err = fmt.Errorf("invalid vault format %q: %w", resourceID, err) return } keyPath = v[i] return } func newHashivaultClient(address, token, transitSecretEnginePath, keyResourceID string, keyVersion uint64) (*hashivaultClient, error) { if err := ValidReference(keyResourceID); err != nil { return nil, err } keyPath, err := parseReference(keyResourceID) if err != nil { return nil, err } if address == "" { address = os.Getenv("VAULT_ADDR") } if address == "" { return nil, errors.New("VAULT_ADDR is not set") } client, err := vault.NewClient(&vault.Config{ Address: address, }) if err != nil { return nil, fmt.Errorf("new vault client: %w", err) } if token == "" { token = os.Getenv("VAULT_TOKEN") } if token == "" { log.Printf("VAULT_TOKEN is not set, trying to read token from file at path ~/.vault-token") homeDir, err := homedir.Dir() if err != nil { return nil, fmt.Errorf("get home directory: %w", err) } tokenFromFile, err := os.ReadFile(filepath.Join(homeDir, ".vault-token")) if err != nil { return nil, fmt.Errorf("read .vault-token file: %w", err) } token = string(tokenFromFile) } client.SetToken(token) if transitSecretEnginePath == "" { transitSecretEnginePath = os.Getenv("TRANSIT_SECRET_ENGINE_PATH") } if transitSecretEnginePath == "" { transitSecretEnginePath = "transit" } hvClient := &hashivaultClient{ client: client, keyPath: keyPath, transitSecretEnginePath: transitSecretEnginePath, keyCache: ttlcache.New[string, crypto.PublicKey]( ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](), ), keyVersion: keyVersion, } return hvClient, nil } func oidcLogin(_ context.Context, address, path, role, token string) (string, error) { if address == "" { address = os.Getenv("VAULT_ADDR") } if address == "" { return "", errors.New("VAULT_ADDR is not set") } if path == "" { path = "jwt" } client, err := vault.NewClient(&vault.Config{ Address: address, }) if err != nil { return "", fmt.Errorf("new vault client: %w", err) } loginData := map[string]interface{}{ "role": role, "jwt": token, } fullpath := fmt.Sprintf("auth/%s/login", path) resp, err := client.Logical().Write(fullpath, loginData) if err != nil { return "", fmt.Errorf("vault oidc login: %w", err) } return resp.TokenID() } func (h *hashivaultClient) fetchPublicKey(_ context.Context) (crypto.PublicKey, error) { client := h.client.Logical() path := fmt.Sprintf("/%s/keys/%s", h.transitSecretEnginePath, h.keyPath) keyResult, err := client.Read(path) if err != nil { return nil, fmt.Errorf("public key: %w", err) } if keyResult == nil { return nil, fmt.Errorf("could not read data from transit key path: %s", path) } keysData, hasKeys := keyResult.Data["keys"] latestVersion, hasVersion := keyResult.Data["latest_version"] if !hasKeys || !hasVersion { return nil, errors.New("failed to read transit key keys: corrupted response") } keys, ok := keysData.(map[string]interface{}) if !ok { return nil, errors.New("failed to read transit key keys: Invalid keys map") } keyVersion, ok := latestVersion.(json.Number) if !ok { return nil, fmt.Errorf("format of 'latest_version' is not json.Number") } keyData, ok := keys[string(keyVersion)] if !ok { return nil, errors.New("failed to read transit key keys: corrupted response") } keyMap, ok := keyData.(map[string]interface{}) if !ok { return nil, fmt.Errorf("could not parse transit key keys data as map[string]interface{}") } publicKeyPem, ok := keyMap["public_key"] if !ok { return nil, errors.New("failed to read transit key keys: corrupted response") } strPublicKeyPem, ok := publicKeyPem.(string) if !ok { return nil, fmt.Errorf("could not parse public key pem as string") } return cryptoutils.UnmarshalPEMToPublicKey([]byte(strPublicKeyPem)) } func (h *hashivaultClient) public() (crypto.PublicKey, error) { var lerr error loader := ttlcache.LoaderFunc[string, crypto.PublicKey]( func(c *ttlcache.Cache[string, crypto.PublicKey], key string) *ttlcache.Item[string, crypto.PublicKey] { var pubkey crypto.PublicKey pubkey, lerr = h.fetchPublicKey(context.Background()) if lerr == nil { item := c.Set(key, pubkey, 300*time.Second) return item } return nil }, ) item := h.keyCache.Get(cacheKey, ttlcache.WithLoader[string, crypto.PublicKey](loader)) if lerr != nil { return nil, lerr } if item == nil { return nil, fmt.Errorf("unable to retrieve an item from the cache by the provided key") } return item.Value(), nil } func (h hashivaultClient) sign(digest []byte, alg crypto.Hash, opts ...signature.SignOption) ([]byte, error) { client := h.client.Logical() keyVersion := fmt.Sprintf("%d", h.keyVersion) var keyVersionUsedPtr *string for _, opt := range opts { opt.ApplyKeyVersion(&keyVersion) opt.ApplyKeyVersionUsed(&keyVersionUsedPtr) } if keyVersion != "" { if _, err := strconv.ParseUint(keyVersion, 10, 64); err != nil { return nil, fmt.Errorf("parsing requested key version: %w", err) } } signResult, err := client.Write(fmt.Sprintf("/%s/sign/%s%s", h.transitSecretEnginePath, h.keyPath, hashString(alg)), map[string]interface{}{ "input": base64.StdEncoding.Strict().EncodeToString(digest), "prehashed": alg != crypto.Hash(0), "key_version": keyVersion, "signature_algorithm": "pkcs1v15", }) if err != nil { return nil, fmt.Errorf("transit: failed to sign payload: %w", err) } encodedSignature, ok := signResult.Data["signature"] if !ok { return nil, errors.New("transit: response corrupted in-transit") } return vaultDecode(encodedSignature, keyVersionUsedPtr) } func (h hashivaultClient) verify(sig, digest []byte, alg crypto.Hash, opts ...signature.VerifyOption) error { client := h.client.Logical() encodedSig := base64.StdEncoding.EncodeToString(sig) keyVersion := "" for _, opt := range opts { opt.ApplyKeyVersion(&keyVersion) } var vaultDataPrefix string if keyVersion != "" { // keyVersion >= 1 on verification but can be set to 0 on signing kvUint, err := strconv.ParseUint(keyVersion, 10, 64) if err != nil { return fmt.Errorf("parsing requested key version: %w", err) } else if kvUint == 0 { return errors.New("key version must be >= 1") } vaultDataPrefix = fmt.Sprintf("vault:v%d:", kvUint) } else { vaultDataPrefix = os.Getenv("VAULT_KEY_PREFIX") if vaultDataPrefix == "" { if h.keyVersion > 0 { vaultDataPrefix = fmt.Sprintf("vault:v%d:", h.keyVersion) } else { vaultDataPrefix = vaultV1DataPrefix } } } result, err := client.Write(fmt.Sprintf("/%s/verify/%s/%s", h.transitSecretEnginePath, h.keyPath, hashString(alg)), map[string]interface{}{ "input": base64.StdEncoding.EncodeToString(digest), "prehashed": alg != crypto.Hash(0), "signature": fmt.Sprintf("%s%s", vaultDataPrefix, encodedSig), }) if err != nil { return fmt.Errorf("verify: %w", err) } valid, ok := result.Data["valid"] if !ok { return errors.New("corrupted response") } isValid, ok := valid.(bool) if !ok { return fmt.Errorf("received non-bool value from 'valid' key") } if !isValid { return errors.New("failed vault verification") } return nil } // Vault likes to prefix base64 data with a version prefix func vaultDecode(data interface{}, keyVersionUsed *string) ([]byte, error) { encoded, ok := data.(string) if !ok { return nil, errors.New("received non-string data") } if keyVersionUsed != nil { *keyVersionUsed = prefixRegex.FindString(encoded) } return base64.StdEncoding.DecodeString(prefixRegex.ReplaceAllString(encoded, "")) } func hashString(h crypto.Hash) string { var hashStr string switch h { case crypto.SHA224: hashStr = "/sha2-224" case crypto.SHA256: hashStr = "/sha2-256" case crypto.SHA384: hashStr = "/sha2-384" case crypto.SHA512: hashStr = "/sha2-512" default: hashStr = "" } return hashStr } func (h hashivaultClient) createKey(typeStr string) (crypto.PublicKey, error) { client := h.client.Logical() if _, err := client.Write(fmt.Sprintf("/%s/keys/%s", h.transitSecretEnginePath, h.keyPath), map[string]interface{}{ "type": typeStr, }); err != nil { return nil, fmt.Errorf("failed to create transit key: %w", err) } return h.public() } sigstore-1.8.6/pkg/signature/kms/hashivault/doc.go000066400000000000000000000012611463713551000222120ustar00rootroot00000000000000// // 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 hashivault contains utilities related to Hashivault KMS. package hashivault sigstore-1.8.6/pkg/signature/kms/hashivault/e2e_test.go000066400000000000000000000400421463713551000231570ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build e2e // +build e2e package hashivault import ( "bytes" "context" "crypto" "crypto/ecdsa" "crypto/rand" "fmt" "os" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" vault "github.com/hashicorp/vault/api" ) type VaultSuite struct { suite.Suite vaultclient *vault.Client } func (suite *VaultSuite) GetProvider(key string, opts ...signature.RPCOption) *SignerVerifier { provider, err := LoadSignerVerifier(fmt.Sprintf("hashivault://%s", key), crypto.SHA256, opts...) require.NoError(suite.T(), err) require.NotNil(suite.T(), provider) return provider } func (suite *VaultSuite) SetupSuite() { var err error suite.vaultclient, err = vault.NewClient(&vault.Config{ Address: os.Getenv("VAULT_ADDR"), }) require.Nil(suite.T(), err) require.NotNil(suite.T(), suite.vaultclient) err = suite.vaultclient.Sys().Mount("transit", &vault.MountInput{ Type: "transit", }) require.Nil(suite.T(), err) err = suite.vaultclient.Sys().Mount("somerandompath", &vault.MountInput{ Type: "transit", }) require.Nil(suite.T(), err) } func (suite *VaultSuite) TearDownSuite() { var err error if suite.vaultclient == nil { suite.vaultclient, err = vault.NewClient(&vault.Config{ Address: os.Getenv("VAULT_ADDR"), }) require.Nil(suite.T(), err) require.NotNil(suite.T(), suite.vaultclient) } err = suite.vaultclient.Sys().Unmount("transit") require.Nil(suite.T(), err) err = suite.vaultclient.Sys().Unmount("somerandompath") require.Nil(suite.T(), err) } func (suite *VaultSuite) TestProvider() { suite.GetProvider("provider") } func (suite *VaultSuite) TestCreateKey() { provider := suite.GetProvider("createkey") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) } func (suite *VaultSuite) TestSign() { provider := suite.GetProvider("testsign") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) verifier, _ := signature.LoadECDSAVerifier(key.(*ecdsa.PublicKey), crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestSignOpts() { addr := os.Getenv("VAULT_ADDR") token := os.Getenv("VAULT_TOKEN") os.Setenv("VAULT_ADDR", "") os.Setenv("VAULT_TOKEN", "") defer os.Setenv("VAULT_ADDR", addr) defer os.Setenv("VAULT_TOKEN", token) provider := suite.GetProvider("testsign", options.WithRPCAuthOpts(options.RPCAuth{Address: addr, Token: token})) key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) verifier, _ := signature.LoadECDSAVerifier(key.(*ecdsa.PublicKey), crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestSignSpecificKeyVersion() { provider := suite.GetProvider("testsignversion") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) // test without specifying any value (aka use default) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) verifier, _ := signature.LoadECDSAVerifier(key.(*ecdsa.PublicKey), crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) // test with specifying default value sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("0")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test with specifying explicit value sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("1")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test version that doesn't (yet) exist sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("2")) assert.NotNil(suite.T(), err) assert.Nil(suite.T(), sig) // rotate key (now two valid versions) client := suite.vaultclient.Logical() _, err = client.Write("/transit/keys/testsignversion/rotate", nil) assert.Nil(suite.T(), err) // test default version again (implicitly) sig, err = provider.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test default version again (explicitly) sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("0")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test explicit previous version (should still work as we haven't set min_encryption_version yet) sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("1")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test explicit new version sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("2")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test bad value sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("3")) assert.NotNil(suite.T(), err) assert.Nil(suite.T(), sig) // change minimum to v2 _, err = client.Write("/transit/keys/testsignversion/config", map[string]interface{}{ "min_encryption_version": 2, }) assert.Nil(suite.T(), err) // test explicit previous version (should fail as min_encryption_version has been set) sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("1")) assert.NotNil(suite.T(), err) assert.Nil(suite.T(), sig) provider2 := suite.GetProvider("testsignversion", options.WithKeyVersion("2")) sig, err = provider2.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test explicit new version sig, err = provider2.SignMessage(bytes.NewReader(data), options.WithKeyVersion("2")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) } func (suite *VaultSuite) TestVerifySpecificKeyVersion() { provider := suite.GetProvider("testverifyversion") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) // test using v1 data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("1")) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) // test without specifying key value err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) // test with explicitly specifying default value err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("1")) assert.Nil(suite.T(), err) // test version that doesn't (yet) exist err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("2")) assert.NotNil(suite.T(), err) // rotate key (now two valid versions) client := suite.vaultclient.Logical() _, err = client.Write("/transit/keys/testverifyversion/rotate", nil) assert.Nil(suite.T(), err) // test default version again (implicitly) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) // test invalid version (0 is fine for signing, but must be >= 1 for verification) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("0")) assert.NotNil(suite.T(), err) // test explicit previous version (should still as we haven't set min_decryption_version yet) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("1")) assert.Nil(suite.T(), err) // test explicit new version (should fail since it doesn't match the v1 key) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("2")) assert.NotNil(suite.T(), err) // test bad value err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("3")) assert.NotNil(suite.T(), err) // change minimum to v2 _, err = client.Write("/transit/keys/testverifyversion/config", map[string]interface{}{ "min_decryption_version": 2, }) assert.Nil(suite.T(), err) // test explicit previous version (should fail as min_decryption_version has been set) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithKeyVersion("1")) assert.NotNil(suite.T(), err) } func (suite *VaultSuite) TestSignAndRecordKeyVersion() { provider := suite.GetProvider("testrecordsignversion") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) // test for v1 data := []byte("mydata") var versionUsed string sig, err := provider.SignMessage(bytes.NewReader(data), options.ReturnKeyVersionUsed(&versionUsed)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) assert.Contains(suite.T(), versionUsed, "vault:v1:") // rotate client := suite.vaultclient.Logical() _, err = client.Write("/transit/keys/testrecordsignversion/rotate", nil) assert.Nil(suite.T(), err) sig, err = provider.SignMessage(bytes.NewReader(data), options.WithKeyVersion("2"), options.ReturnKeyVersionUsed(&versionUsed)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) assert.Contains(suite.T(), versionUsed, "vault:v2:") } func (suite *VaultSuite) TestSignWithDifferentTransitSecretEnginePath() { provider := suite.GetProvider("testsign") os.Setenv("TRANSIT_SECRET_ENGINE_PATH", "somerandompath") defer os.Setenv("TRANSIT_SECRET_ENGINE_PATH", "transit") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data), options.WithContext(context.Background())) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) verifier, err := signature.LoadECDSAVerifier(key.(*ecdsa.PublicKey), crypto.SHA256) assert.Nil(suite.T(), err) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithContext(context.Background())) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestInvalidPublicKey() { var provider *SignerVerifier var err error assert.NotPanics(suite.T(), func() { provider, _ = LoadSignerVerifier("hashivault://pki_int", crypto.SHA256) _, err = provider.client.fetchPublicKey(context.Background()) }) assert.NotNil(suite.T(), err) } func (suite *VaultSuite) TestSignWithDifferentTransitSecretEnginePathOpts() { provider := suite.GetProvider("testsign", options.WithRPCAuthOpts(options.RPCAuth{Path: "somerandompath"})) key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data), options.WithContext(context.Background())) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) verifier, err := signature.LoadECDSAVerifier(key.(*ecdsa.PublicKey), crypto.SHA256) assert.Nil(suite.T(), err) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data), options.WithContext(context.Background())) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestPubKeyVerify() { provider := suite.GetProvider("testsign") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) k, err := provider.PublicKey() require.NotNil(suite.T(), k) require.Nil(suite.T(), err) pubKey, ok := k.(*ecdsa.PublicKey) require.True(suite.T(), ok) verifier, _ := signature.LoadECDSAVerifier(pubKey, crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestCryptoSigner() { provider := suite.GetProvider("testsign") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) require.Nil(suite.T(), err) require.NotNil(suite.T(), key) data := []byte("mydata") cs, opts, err := provider.CryptoSigner(context.Background(), func(err error) { require.Nil(suite.T(), err) }) hasher := opts.HashFunc().New() _, _ = hasher.Write(data) sig, err := cs.Sign(rand.Reader, hasher.Sum(nil), opts) require.Nil(suite.T(), err) require.NotNil(suite.T(), sig) k := cs.Public() require.NotNil(suite.T(), k) pubKey, ok := k.(*ecdsa.PublicKey) require.True(suite.T(), ok) verifier, _ := signature.LoadECDSAVerifier(pubKey, crypto.SHA256) err = verifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestVerify() { provider := suite.GetProvider("testverify") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) assert.Nil(suite.T(), err) } func (suite *VaultSuite) TestVerifyBadData() { provider := suite.GetProvider("testverify") key, err := provider.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key) data := []byte("mydata") sig, err := provider.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig) dataInvalid := []byte("mydata-invalid") err = provider.VerifySignature(bytes.NewReader(sig), bytes.NewReader(dataInvalid)) assert.Contains(suite.T(), err.Error(), "failed vault verification") } func (suite *VaultSuite) TestBadSignature() { provider1 := suite.GetProvider("testverify1") provider2 := suite.GetProvider("testverify2") key1, err := provider1.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key1) key2, err := provider2.CreateKey(context.Background(), AlgorithmECDSAP256) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), key2) data := []byte("mydata") sig1, err := provider1.SignMessage(bytes.NewReader(data)) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), sig1) err = provider1.VerifySignature(bytes.NewReader(sig1), bytes.NewReader(data)) assert.Nil(suite.T(), err) err = provider2.VerifySignature(bytes.NewReader(sig1), bytes.NewReader(data)) assert.NotNil(suite.T(), err) assert.Contains(suite.T(), err.Error(), "failed vault verification") } func (suite *VaultSuite) TestNoProvider() { provider, err := LoadSignerVerifier("hashi://nonsense", crypto.Hash(0)) require.Error(suite.T(), err) require.Nil(suite.T(), provider) } func (suite *VaultSuite) TestInvalidHost() { provider, err := LoadSignerVerifier("hashivault://keyname", crypto.SHA256, options.WithRPCAuthOpts(options.RPCAuth{Address: "https://unknown.example.com:8200"})) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), provider) _, err = provider.CreateKey(context.Background(), AlgorithmECDSAP256) require.Error(suite.T(), err) } func TestVault(t *testing.T) { suite.Run(t, new(VaultSuite)) } sigstore-1.8.6/pkg/signature/kms/hashivault/go.mod000066400000000000000000000035451463713551000222330ustar00rootroot00000000000000module github.com/sigstore/sigstore/pkg/signature/kms/hashivault replace github.com/sigstore/sigstore => ../../../../ go 1.22.0 require ( github.com/hashicorp/vault/api v1.14.0 github.com/jellydator/ttlcache/v3 v3.2.0 github.com/mitchellh/go-homedir v1.1.0 github.com/sigstore/sigstore v1.6.4 github.com/stretchr/testify v1.9.0 ) require ( github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/google/go-containerregistry v0.19.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect 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/kr/pretty v0.2.1 // indirect github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.2.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) sigstore-1.8.6/pkg/signature/kms/hashivault/go.sum000066400000000000000000000266611463713551000222640ustar00rootroot00000000000000github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/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/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= 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/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= 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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 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/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/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= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/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= sigstore-1.8.6/pkg/signature/kms/hashivault/hashivault_test.go000066400000000000000000000025101463713551000246520ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package hashivault import "testing" func TestParseReference(t *testing.T) { tests := []struct { in string wantKey string wantErr bool }{ { in: "hashivault://cosign", wantKey: "cosign", wantErr: false, }, { in: "hashivault://cosign/nested", wantErr: true, }, { in: "foo://bar", wantErr: true, }, { in: "", wantErr: true, }, } for _, tt := range tests { t.Run(tt.in, func(t *testing.T) { gotKey, err := parseReference(tt.in) if (err != nil) != tt.wantErr { t.Errorf("parseReference() error = %v, wantErr %v", err, tt.wantErr) return } if gotKey != tt.wantKey { t.Errorf("parseReference() gotKey = %v, want %v", gotKey, tt.wantKey) } }) } } sigstore-1.8.6/pkg/signature/kms/hashivault/signer.go000066400000000000000000000154721463713551000227450ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package hashivault import ( "context" "crypto" "errors" "fmt" "io" "strconv" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" ) // Taken from https://www.vaultproject.io/api/secret/transit // nolint:revive const ( AlgorithmECDSAP256 = "ecdsa-p256" AlgorithmECDSAP384 = "ecdsa-p384" AlgorithmECDSAP521 = "ecdsa-p521" AlgorithmED25519 = "ed25519" AlgorithmRSA2048 = "rsa-2048" AlgorithmRSA3072 = "rsa-3072" AlgorithmRSA4096 = "rsa-4096" ) var hvSupportedAlgorithms = []string{ AlgorithmECDSAP256, AlgorithmECDSAP384, AlgorithmECDSAP521, AlgorithmED25519, AlgorithmRSA2048, AlgorithmRSA3072, AlgorithmRSA4096, } var hvSupportedHashFuncs = []crypto.Hash{ crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.Hash(0), } // SignerVerifier creates and verifies digital signatures over a message using Hashicorp Vault KMS service type SignerVerifier struct { hashFunc crypto.Hash client *hashivaultClient } // LoadSignerVerifier generates signatures using the specified key object in Vault and hash algorithm. // // It also can verify signatures (via a remote vall to the Vault instance). hashFunc should be // set to crypto.Hash(0) if the key referred to by referenceStr is an ED25519 signing key. func LoadSignerVerifier(referenceStr string, hashFunc crypto.Hash, opts ...signature.RPCOption) (*SignerVerifier, error) { h := &SignerVerifier{} ctx := context.Background() rpcAuth := options.RPCAuth{} var keyVersion string for _, opt := range opts { opt.ApplyRPCAuthOpts(&rpcAuth) opt.ApplyContext(&ctx) opt.ApplyKeyVersion(&keyVersion) } var keyVersionUint uint64 var err error if keyVersion != "" { keyVersionUint, err = strconv.ParseUint(keyVersion, 10, 64) if err != nil { return nil, fmt.Errorf("parsing key version: %w", err) } } if rpcAuth.OIDC.Token != "" { rpcAuth.Token, err = oidcLogin(ctx, rpcAuth.Address, rpcAuth.OIDC.Path, rpcAuth.OIDC.Role, rpcAuth.OIDC.Token) if err != nil { return nil, err } } h.client, err = newHashivaultClient(rpcAuth.Address, rpcAuth.Token, rpcAuth.Path, referenceStr, keyVersionUint) if err != nil { return nil, err } switch hashFunc { case 0, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512: h.hashFunc = hashFunc default: return nil, errors.New("hash function not supported by Hashivault") } return h, nil } // SignMessage signs the provided message using HashiCorp Vault KMS. If the message is provided, // this method will compute the digest according to the hash function specified // when the HashivaultSigner was created. // // SignMessage recognizes the following Options listed in order of preference: // // - WithDigest() // // All other options are ignored if specified. func (h SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) { var digest []byte var signerOpts crypto.SignerOpts = h.hashFunc for _, opt := range opts { opt.ApplyDigest(&digest) opt.ApplyCryptoSignerOpts(&signerOpts) } digest, hf, err := signature.ComputeDigestForSigning(message, signerOpts.HashFunc(), hvSupportedHashFuncs, opts...) if err != nil { return nil, err } return h.client.sign(digest, hf, opts...) } // PublicKey returns the public key that can be used to verify signatures created by // this signer. All options provided in arguments to this method are ignored. func (h SignerVerifier) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { return h.client.public() } // VerifySignature verifies the signature for the given message. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the SignerVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (h SignerVerifier) VerifySignature(sig, message io.Reader, opts ...signature.VerifyOption) error { var digest []byte var signerOpts crypto.SignerOpts = h.hashFunc for _, opt := range opts { opt.ApplyDigest(&digest) opt.ApplyCryptoSignerOpts(&signerOpts) } digest, hf, err := signature.ComputeDigestForVerifying(message, signerOpts.HashFunc(), hvSupportedHashFuncs, opts...) if err != nil { return err } sigBytes, err := io.ReadAll(sig) if err != nil { return fmt.Errorf("reading signature: %w", err) } return h.client.verify(sigBytes, digest, hf, opts...) } // CreateKey attempts to create a new key in Vault with the specified algorithm. func (h SignerVerifier) CreateKey(_ context.Context, algorithm string) (crypto.PublicKey, error) { return h.client.createKey(algorithm) } type cryptoSignerWrapper struct { ctx context.Context hashFunc crypto.Hash sv *SignerVerifier errFunc func(error) } func (c cryptoSignerWrapper) Public() crypto.PublicKey { pk, err := c.sv.PublicKey(options.WithContext(c.ctx)) if err != nil && c.errFunc != nil { c.errFunc(err) } return pk } func (c cryptoSignerWrapper) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { hashFunc := c.hashFunc if opts != nil { hashFunc = opts.HashFunc() } hvOptions := []signature.SignOption{ options.WithContext(c.ctx), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc), } return c.sv.SignMessage(nil, hvOptions...) } // CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object // that allows the KMS to be used in APIs that only accept the standard golang objects func (h *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { csw := &cryptoSignerWrapper{ ctx: ctx, sv: h, hashFunc: h.hashFunc, errFunc: errFunc, } return csw, h.hashFunc, nil } // SupportedAlgorithms returns the list of algorithms supported by the Hashicorp Vault service func (h *SignerVerifier) SupportedAlgorithms() []string { return hvSupportedAlgorithms } // DefaultAlgorithm returns the default algorithm for the Hashicorp Vault service func (h *SignerVerifier) DefaultAlgorithm() string { return AlgorithmECDSAP256 } sigstore-1.8.6/pkg/signature/kms/kms.go000066400000000000000000000053111463713551000200670ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package kms implements the interface to access various ksm services package kms import ( "context" "crypto" "fmt" "strings" "github.com/sigstore/sigstore/pkg/signature" ) // ProviderNotFoundError indicates that no matching KMS provider was found type ProviderNotFoundError struct { ref string } func (e *ProviderNotFoundError) Error() string { return fmt.Sprintf("no kms provider found for key reference: %s", e.ref) } // ProviderInit is a function that initializes provider-specific SignerVerifier. // // It takes a provider-specific resource ID and hash function, and returns a // SignerVerifier using that resource, or any error that was encountered. type ProviderInit func(context.Context, string, crypto.Hash, ...signature.RPCOption) (SignerVerifier, error) // AddProvider adds the provider implementation into the local cache func AddProvider(keyResourceID string, init ProviderInit) { providersMap[keyResourceID] = init } var providersMap = map[string]ProviderInit{} // Get returns a KMS SignerVerifier for the given resource string and hash function. // If no matching provider is found, Get returns a ProviderNotFoundError. It // also returns an error if initializing the SignerVerifier fails. func Get(ctx context.Context, keyResourceID string, hashFunc crypto.Hash, opts ...signature.RPCOption) (SignerVerifier, error) { for ref, pi := range providersMap { if strings.HasPrefix(keyResourceID, ref) { return pi(ctx, keyResourceID, hashFunc, opts...) } } return nil, &ProviderNotFoundError{ref: keyResourceID} } // SupportedProviders returns list of initialized providers func SupportedProviders() []string { keys := make([]string, 0, len(providersMap)) for key := range providersMap { keys = append(keys, key) } return keys } // SignerVerifier creates and verifies digital signatures over a message using a KMS service type SignerVerifier interface { signature.SignerVerifier CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) SupportedAlgorithms() []string DefaultAlgorithm() string } sigstore-1.8.6/pkg/signature/message.go000066400000000000000000000102511463713551000201260ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" crand "crypto/rand" "errors" "fmt" "io" ) func isSupportedAlg(alg crypto.Hash, supportedAlgs []crypto.Hash) bool { if supportedAlgs == nil { return true } for _, supportedAlg := range supportedAlgs { if alg == supportedAlg { return true } } return false } // ComputeDigestForSigning calculates the digest value for the specified message using a hash function selected by the following process: // // - if a digest value is already specified in a SignOption and the length of the digest matches that of the selected hash function, the // digest value will be returned without any further computation // - if a hash function is given using WithCryptoSignerOpts(opts) as a SignOption, it will be used (if it is in the supported list) // - otherwise defaultHashFunc will be used (if it is in the supported list) func ComputeDigestForSigning(rawMessage io.Reader, defaultHashFunc crypto.Hash, supportedHashFuncs []crypto.Hash, opts ...SignOption) (digest []byte, hashedWith crypto.Hash, err error) { var cryptoSignerOpts crypto.SignerOpts = defaultHashFunc for _, opt := range opts { opt.ApplyDigest(&digest) opt.ApplyCryptoSignerOpts(&cryptoSignerOpts) } hashedWith = cryptoSignerOpts.HashFunc() if !isSupportedAlg(hashedWith, supportedHashFuncs) { return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) } if len(digest) > 0 { if hashedWith != crypto.Hash(0) && len(digest) != hashedWith.Size() { err = errors.New("unexpected length of digest for hash function specified") } return } digest, err = hashMessage(rawMessage, hashedWith) return } // ComputeDigestForVerifying calculates the digest value for the specified message using a hash function selected by the following process: // // - if a digest value is already specified in a SignOption and the length of the digest matches that of the selected hash function, the // digest value will be returned without any further computation // - if a hash function is given using WithCryptoSignerOpts(opts) as a SignOption, it will be used (if it is in the supported list) // - otherwise defaultHashFunc will be used (if it is in the supported list) func ComputeDigestForVerifying(rawMessage io.Reader, defaultHashFunc crypto.Hash, supportedHashFuncs []crypto.Hash, opts ...VerifyOption) (digest []byte, hashedWith crypto.Hash, err error) { var cryptoSignerOpts crypto.SignerOpts = defaultHashFunc for _, opt := range opts { opt.ApplyDigest(&digest) opt.ApplyCryptoSignerOpts(&cryptoSignerOpts) } hashedWith = cryptoSignerOpts.HashFunc() if !isSupportedAlg(hashedWith, supportedHashFuncs) { return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) } if len(digest) > 0 { if hashedWith != crypto.Hash(0) && len(digest) != hashedWith.Size() { err = errors.New("unexpected length of digest for hash function specified") } return } digest, err = hashMessage(rawMessage, hashedWith) return } func hashMessage(rawMessage io.Reader, hashFunc crypto.Hash) ([]byte, error) { if rawMessage == nil { return nil, errors.New("message cannot be nil") } if hashFunc == crypto.Hash(0) { return io.ReadAll(rawMessage) } hasher := hashFunc.New() // avoids reading entire message into memory if _, err := io.Copy(hasher, rawMessage); err != nil { return nil, fmt.Errorf("hashing message: %w", err) } return hasher.Sum(nil), nil } func selectRandFromOpts(opts ...SignOption) io.Reader { rand := crand.Reader for _, opt := range opts { opt.ApplyRand(&rand) } return rand } sigstore-1.8.6/pkg/signature/options.go000066400000000000000000000033631463713551000202030ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "context" "crypto" "crypto/rsa" "io" "github.com/sigstore/sigstore/pkg/signature/options" ) // RPCOption specifies options to be used when performing RPC type RPCOption interface { ApplyContext(*context.Context) ApplyRemoteVerification(*bool) ApplyRPCAuthOpts(opts *options.RPCAuth) ApplyKeyVersion(keyVersion *string) } // PublicKeyOption specifies options to be used when obtaining a public key type PublicKeyOption interface { RPCOption } // MessageOption specifies options to be used when processing messages during signing or verification type MessageOption interface { ApplyDigest(*[]byte) ApplyCryptoSignerOpts(*crypto.SignerOpts) } // SignOption specifies options to be used when signing a message type SignOption interface { RPCOption MessageOption ApplyRand(*io.Reader) ApplyKeyVersionUsed(**string) } // VerifyOption specifies options to be used when verifying a signature type VerifyOption interface { RPCOption MessageOption } // LoadOption specifies options to be used when creating a Signer/Verifier type LoadOption interface { ApplyHash(*crypto.Hash) ApplyED25519ph(*bool) ApplyRSAPSS(**rsa.PSSOptions) } sigstore-1.8.6/pkg/signature/options/000077500000000000000000000000001463713551000176475ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/options/context.go000066400000000000000000000022371463713551000216660ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package options defines options for KMS clients package options import ( "context" ) // RequestContext implements the functional option pattern for including a context during RPC type RequestContext struct { NoOpOptionImpl ctx context.Context } // ApplyContext sets the specified context as the functional option func (r RequestContext) ApplyContext(ctx *context.Context) { *ctx = r.ctx } // WithContext specifies that the given context should be used in RPC to external services func WithContext(ctx context.Context) RequestContext { return RequestContext{ctx: ctx} } sigstore-1.8.6/pkg/signature/options/digest.go000066400000000000000000000024761463713551000214660ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package options // RequestDigest implements the functional option pattern for specifying a digest value type RequestDigest struct { NoOpOptionImpl digest []byte } // ApplyDigest sets the specified digest value as the functional option func (r RequestDigest) ApplyDigest(digest *[]byte) { *digest = r.digest } // WithDigest specifies that the given digest can be used by underlying signature implementations // WARNING: When verifying a digest with ECDSA, it is trivial to craft a valid signature // over a random message given a public key. Do not use this unles you understand the // implications and do not need to protect against malleability. func WithDigest(digest []byte) RequestDigest { return RequestDigest{digest: digest} } sigstore-1.8.6/pkg/signature/options/doc.go000066400000000000000000000012711463713551000207440ustar00rootroot00000000000000// // 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 options contains functional options for the various SignerVerifiers package options sigstore-1.8.6/pkg/signature/options/keyversion.go000066400000000000000000000036561463713551000224060ustar00rootroot00000000000000// // 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 options // RequestKeyVersion implements the functional option pattern for specifying the KMS key version during signing or verification type RequestKeyVersion struct { NoOpOptionImpl keyVersion string } // ApplyKeyVersion sets the KMS's key version as a functional option func (r RequestKeyVersion) ApplyKeyVersion(keyVersion *string) { *keyVersion = r.keyVersion } // WithKeyVersion specifies that a specific KMS key version be used during signing and verification operations; // a value of 0 will use the latest version of the key (default) func WithKeyVersion(keyVersion string) RequestKeyVersion { return RequestKeyVersion{keyVersion: keyVersion} } // RequestKeyVersionUsed implements the functional option pattern for obtaining the KMS key version used during signing type RequestKeyVersionUsed struct { NoOpOptionImpl keyVersionUsed *string } // ApplyKeyVersionUsed requests to store the KMS's key version that was used as a functional option func (r RequestKeyVersionUsed) ApplyKeyVersionUsed(keyVersionUsed **string) { *keyVersionUsed = r.keyVersionUsed } // ReturnKeyVersionUsed specifies that the specific KMS key version that was used during signing should be stored // in the pointer provided func ReturnKeyVersionUsed(keyVersionUsed *string) RequestKeyVersionUsed { return RequestKeyVersionUsed{keyVersionUsed: keyVersionUsed} } sigstore-1.8.6/pkg/signature/options/loadoptions.go000066400000000000000000000046671463713551000225460ustar00rootroot00000000000000// // Copyright 2024 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 options import ( "crypto" "crypto/rsa" ) // RequestHash implements the functional option pattern for setting a Hash // function when loading a signer or verifier type RequestHash struct { NoOpOptionImpl hashFunc crypto.Hash } // ApplyHash sets the hash as requested by the functional option func (r RequestHash) ApplyHash(hash *crypto.Hash) { *hash = r.hashFunc } // WithHash specifies that the given hash function should be used when loading a signer or verifier func WithHash(hash crypto.Hash) RequestHash { return RequestHash{hashFunc: hash} } // RequestED25519ph implements the functional option pattern for specifying // ED25519ph (pre-hashed) should be used when loading a signer or verifier and a // ED25519 key is type RequestED25519ph struct { NoOpOptionImpl useED25519ph bool } // ApplyED25519ph sets the ED25519ph flag as requested by the functional option func (r RequestED25519ph) ApplyED25519ph(useED25519ph *bool) { *useED25519ph = r.useED25519ph } // WithED25519ph specifies that the ED25519ph algorithm should be used when a ED25519 key is used func WithED25519ph() RequestED25519ph { return RequestED25519ph{useED25519ph: true} } // RequestPSSOptions implements the functional option pattern for specifying RSA // PSS should be used when loading a signer or verifier and a RSA key is // detected type RequestPSSOptions struct { NoOpOptionImpl opts *rsa.PSSOptions } // ApplyRSAPSS sets the RSAPSS options as requested by the functional option func (r RequestPSSOptions) ApplyRSAPSS(opts **rsa.PSSOptions) { *opts = r.opts } // WithRSAPSS specifies that the RSAPSS algorithm should be used when a RSA key is used // Note that the RSA PSSOptions contains an hash algorithm, which will override // the hash function specified with WithHash. func WithRSAPSS(opts *rsa.PSSOptions) RequestPSSOptions { return RequestPSSOptions{opts: opts} } sigstore-1.8.6/pkg/signature/options/noop.go000066400000000000000000000044111463713551000211510ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package options import ( "context" "crypto" "crypto/rsa" "io" ) // NoOpOptionImpl implements the RPCOption, SignOption, VerifyOption interfaces as no-ops. type NoOpOptionImpl struct{} // ApplyContext is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyContext(_ *context.Context) {} // ApplyCryptoSignerOpts is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyCryptoSignerOpts(_ *crypto.SignerOpts) {} // ApplyDigest is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyDigest(_ *[]byte) {} // ApplyRand is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyRand(_ *io.Reader) {} // ApplyRemoteVerification is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyRemoteVerification(_ *bool) {} // ApplyRPCAuthOpts is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyRPCAuthOpts(_ *RPCAuth) {} // ApplyKeyVersion is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyKeyVersion(_ *string) {} // ApplyKeyVersionUsed is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyKeyVersionUsed(_ **string) {} // ApplyHash is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyHash(_ *crypto.Hash) {} // ApplyED25519ph is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyED25519ph(_ *bool) {} // ApplyRSAPSS is a no-op required to fully implement the requisite interfaces func (NoOpOptionImpl) ApplyRSAPSS(_ **rsa.PSSOptions) {} sigstore-1.8.6/pkg/signature/options/rand.go000066400000000000000000000022251463713551000211230ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package options import ( crand "crypto/rand" "io" ) // RequestRand implements the functional option pattern for using a specific source of entropy type RequestRand struct { NoOpOptionImpl rand io.Reader } // ApplyRand sets the specified source of entropy as the functional option func (r RequestRand) ApplyRand(rand *io.Reader) { *rand = r.rand } // WithRand specifies that the given source of entropy should be used in signing operations func WithRand(rand io.Reader) RequestRand { r := rand if r == nil { r = crand.Reader } return RequestRand{rand: r} } sigstore-1.8.6/pkg/signature/options/remoteverification.go000066400000000000000000000024471463713551000241030ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package options // RequestRemoteVerification implements the functional option pattern for remotely verifiying signatures when possible type RequestRemoteVerification struct { NoOpOptionImpl remoteVerification bool } // ApplyRemoteVerification sets remote verification as a functional option func (r RequestRemoteVerification) ApplyRemoteVerification(remoteVerification *bool) { *remoteVerification = r.remoteVerification } // WithRemoteVerification specifies that the verification operation should be performed remotely (vs in the process of the caller) func WithRemoteVerification(remoteVerification bool) RequestRemoteVerification { return RequestRemoteVerification{remoteVerification: remoteVerification} } sigstore-1.8.6/pkg/signature/options/rpcauth.go000066400000000000000000000035201463713551000216440ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package options // RPCAuthOpts includes authentication settings for RPC calls type RPCAuthOpts struct { NoOpOptionImpl opts RPCAuth } // RPCAuth provides credentials for RPC calls, empty fields are ignored type RPCAuth struct { Address string // address is the remote server address, e.g. https://vault:8200 Path string // path for the RPC, in vault this is the transit path which default to "transit" Token string // token used for RPC, in vault this is the VAULT_TOKEN value OIDC RPCAuthOIDC } // RPCAuthOIDC is used to perform the RPC login using OIDC instead of a fixed token type RPCAuthOIDC struct { Path string // path defaults to "jwt" for vault Role string // role is required for jwt logins Token string // token is a jwt with vault } // ApplyRPCAuthOpts sets the RPCAuth as a function option func (r RPCAuthOpts) ApplyRPCAuthOpts(opts *RPCAuth) { if r.opts.Address != "" { opts.Address = r.opts.Address } if r.opts.Path != "" { opts.Path = r.opts.Path } if r.opts.Token != "" { opts.Token = r.opts.Token } if r.opts.OIDC.Token != "" { opts.OIDC = r.opts.OIDC } } // WithRPCAuthOpts specifies RPCAuth settings to be used with RPC logins func WithRPCAuthOpts(opts RPCAuth) RPCAuthOpts { return RPCAuthOpts{opts: opts} } sigstore-1.8.6/pkg/signature/options/signeropts.go000066400000000000000000000025111463713551000223720ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package options import ( "crypto" ) // RequestCryptoSignerOpts implements the functional option pattern for supplying crypto.SignerOpts when signing or verifying type RequestCryptoSignerOpts struct { NoOpOptionImpl opts crypto.SignerOpts } // ApplyCryptoSignerOpts sets crypto.SignerOpts as a functional option func (r RequestCryptoSignerOpts) ApplyCryptoSignerOpts(opts *crypto.SignerOpts) { *opts = r.opts } // WithCryptoSignerOpts specifies that provided crypto.SignerOpts be used during signing and verification operations func WithCryptoSignerOpts(opts crypto.SignerOpts) RequestCryptoSignerOpts { var optsToUse crypto.SignerOpts = crypto.SHA256 if opts != nil { optsToUse = opts } return RequestCryptoSignerOpts{opts: optsToUse} } sigstore-1.8.6/pkg/signature/payload/000077500000000000000000000000001463713551000176055ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/payload/doc.go000066400000000000000000000013021463713551000206750ustar00rootroot00000000000000// // 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 payload contains types and utilities related to the Cosign signature format. package payload sigstore-1.8.6/pkg/signature/payload/payload.go000066400000000000000000000116671463713551000216000ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package payload defines a container image package payload import ( "encoding/json" "fmt" "github.com/google/go-containerregistry/pkg/name" ) // CosignSignatureType is the value of `critical.type` in a SimpleContainerImage payload. const CosignSignatureType = "cosign container image signature" // SimpleContainerImage describes the structure of a basic container image signature payload, as defined at: // https://github.com/containers/image/blob/main/docs/containers-signature.5.md#json-data-format type SimpleContainerImage struct { Critical Critical `json:"critical"` // Critical data critical to correctly evaluating the validity of the signature Optional map[string]interface{} `json:"optional"` // Optional optional metadata about the image } // Critical data critical to correctly evaluating the validity of a signature type Critical struct { Identity Identity `json:"identity"` // Identity claimed identity of the image Image Image `json:"image"` // Image identifies the container that the signature applies to Type string `json:"type"` // Type must be 'atomic container signature' } // Identity is the claimed identity of the image type Identity struct { DockerReference string `json:"docker-reference"` // DockerReference is a reference used to refer to or download the image } // Image identifies the container image that the signature applies to type Image struct { DockerManifestDigest string `json:"docker-manifest-digest"` // DockerManifestDigest the manifest digest of the signed container image } // Cosign describes a container image signed using Cosign type Cosign struct { Image name.Digest // ClaimedIdentity is what the signer claims the image to be; usually a registry.com/…/repo:tag, but can also use a digest instead. // ALMOST ALL consumers MUST verify that ClaimedIdentity in the signature is correct given how user refers to the image; // e.g. if the user asks to access a signed image example.com/repo/mysql:3.14, // it is ALMOST ALWAYS necessary to validate that ClaimedIdentity = example.com/repo/mysql:3.14 // // Considerations: // - The user might refer to an image using a digest (example.com/repo/mysql@sha256:…); in that case the registry/…/repo should still match // - If the image is multi-arch, ClaimedIdentity usually refers to the top-level multi-arch image index also on the per-arch images // (possibly even if ClaimedIdentity contains a digest!) // - Older versions of cosign generate signatures where ClaimedIdentity only contains a registry/…/repo ; signature consumers should allow users // to determine whether such images should be accepted (and, long-term, the default SHOULD be to reject them) ClaimedIdentity string Annotations map[string]interface{} } // SimpleContainerImage returns information about a container image in the github.com/containers/image/signature format func (p Cosign) SimpleContainerImage() SimpleContainerImage { dockerReference := p.Image.Repository.Name() if p.ClaimedIdentity != "" { dockerReference = p.ClaimedIdentity } return SimpleContainerImage{ Critical: Critical{ Identity: Identity{ DockerReference: dockerReference, }, Image: Image{ DockerManifestDigest: p.Image.DigestStr(), }, Type: CosignSignatureType, }, Optional: p.Annotations, } } // MarshalJSON marshals the container signature into a []byte of JSON data func (p Cosign) MarshalJSON() ([]byte, error) { return json.Marshal(p.SimpleContainerImage()) } var _ json.Marshaler = Cosign{} // UnmarshalJSON unmarshals []byte of JSON data into a container signature object func (p *Cosign) UnmarshalJSON(data []byte) error { if string(data) == "null" { // JSON "null" is a no-op by convention return nil } var simple SimpleContainerImage if err := json.Unmarshal(data, &simple); err != nil { return err } if simple.Critical.Type != CosignSignatureType { return fmt.Errorf("Cosign signature payload was of an unknown type: %q", simple.Critical.Type) } digestStr := simple.Critical.Identity.DockerReference + "@" + simple.Critical.Image.DockerManifestDigest digest, err := name.NewDigest(digestStr) if err != nil { return fmt.Errorf("could not parse image digest string %q: %w", digestStr, err) } p.Image = digest p.ClaimedIdentity = simple.Critical.Identity.DockerReference p.Annotations = simple.Optional return nil } var _ json.Unmarshaler = (*Cosign)(nil) sigstore-1.8.6/pkg/signature/payload/payload_test.go000066400000000000000000000135621463713551000226330ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package payload import ( "encoding/json" "testing" "github.com/go-test/deep" "github.com/google/go-containerregistry/pkg/name" ) const validDigest = "sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f" func mustParseDigest(t *testing.T, digestStr string) name.Digest { t.Helper() digest, err := name.NewDigest(digestStr) if err != nil { t.Fatalf("could not parse digest %q: %v", digestStr, err) } return digest } func TestMarshalCosign(t *testing.T) { t.Parallel() testCases := []struct { desc string imgPayload Cosign expected string }{ { desc: "no claims", imgPayload: Cosign{ Image: mustParseDigest(t, "example.com/test/image@"+validDigest), }, expected: `{"critical":{"identity":{"docker-reference":"example.com/test/image"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"cosign container image signature"},"optional":null}`, }, { desc: "standard atomic signature", imgPayload: Cosign{ Image: mustParseDigest(t, "example.com/atomic/test/image@"+validDigest), Annotations: map[string]interface{}{ "creator": "atomic", "timestamp": 1458239713, }, }, expected: `{"critical":{"identity":{"docker-reference":"example.com/atomic/test/image"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"cosign container image signature"},"optional":{"creator":"atomic","timestamp":1458239713}}`, }, { desc: "arbitrary claims", imgPayload: Cosign{ Image: mustParseDigest(t, "example.com/cosign/test/image@"+validDigest), Annotations: map[string]interface{}{ "creator": "anyone", "some_struct": map[string]interface{}{ "foo": "bar", "false": true, "nothing": nil, }, "CamelCase WithSpace": 8.314, }, }, expected: `{"critical":{"identity":{"docker-reference":"example.com/cosign/test/image"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"cosign container image signature"},"optional":{"CamelCase WithSpace":8.314,"creator":"anyone","some_struct":{"false":true,"foo":"bar","nothing":null}}}`, }, { desc: "custom identity", imgPayload: Cosign{ Image: mustParseDigest(t, "example.com/test/image@"+validDigest), ClaimedIdentity: "docker.io/library/test:1.2.3", }, expected: `{"critical":{"identity":{"docker-reference":"docker.io/library/test:1.2.3"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"cosign container image signature"},"optional":null}`, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { tc := tc t.Parallel() payload, err := json.Marshal(tc.imgPayload) if err != nil { t.Fatalf("json.Marshal returned error: %v", err) } if tc.expected != string(payload) { t.Errorf("marshaled payload was %q, wanted %q", string(payload), tc.expected) } }) } } func TestUnmarshalCosign(t *testing.T) { t.Parallel() testCases := []struct { desc string payload string expected Cosign expectErr bool }{ { desc: "no claims", payload: `{"critical":{"identity":{"docker-reference":"example.com/test/image"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"cosign container image signature"},"optional":null}`, expected: Cosign{ Image: mustParseDigest(t, "example.com/test/image@"+validDigest), ClaimedIdentity: "example.com/test/image", }, }, { desc: "arbitrary claims", payload: `{"critical":{"identity":{"docker-reference":"example.com/cosign/test/image"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"cosign container image signature"},"optional":{"CamelCase WithSpace":8.314,"creator":"anyone","some_struct":{"false":true,"foo":"bar","nothing":null}}}`, expected: Cosign{ Image: mustParseDigest(t, "example.com/cosign/test/image@"+validDigest), ClaimedIdentity: "example.com/cosign/test/image", Annotations: map[string]interface{}{ "creator": "anyone", "some_struct": map[string]interface{}{ "foo": "bar", "false": true, "nothing": nil, }, "CamelCase WithSpace": 8.314, }, }, }, { desc: "unknown type", payload: `{"critical":{"identity":{"docker-reference":"example.com/atomic/test/image"},"image":{"docker-manifest-digest":"sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f"},"type":"atomic container signature"},"optional":{}}`, expectErr: true, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { tc := tc t.Parallel() var imgPayload Cosign err := json.Unmarshal([]byte(tc.payload), &imgPayload) if err != nil { if !tc.expectErr { t.Fatalf("json.Unmarshal unexpectedly returned an error: %v", err) } return // operation failed successfully } if tc.expectErr { t.Fatalf("json.Unmarshal returned %v, expected an error", imgPayload) } if diff := deep.Equal(tc.expected, imgPayload); diff != nil { t.Errorf("Cosign unmarshalled incorrectly: %v", diff) } }) } } sigstore-1.8.6/pkg/signature/publickey.go000066400000000000000000000014631463713551000204760ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" ) // PublicKeyProvider returns a PublicKey associated with a digital signature type PublicKeyProvider interface { PublicKey(opts ...PublicKeyOption) (crypto.PublicKey, error) } sigstore-1.8.6/pkg/signature/rsapkcs1v15.go000066400000000000000000000166301463713551000205740ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/rand" "crypto/rsa" "errors" "fmt" "io" "github.com/sigstore/sigstore/pkg/signature/options" ) // RSAPKCS1v15Signer is a signature.Signer that uses the RSA PKCS1v15 algorithm type RSAPKCS1v15Signer struct { hashFunc crypto.Hash priv *rsa.PrivateKey } // LoadRSAPKCS1v15Signer calculates signatures using the specified private key and hash algorithm. // // hf must be either SHA256, SHA388, or SHA512. func LoadRSAPKCS1v15Signer(priv *rsa.PrivateKey, hf crypto.Hash) (*RSAPKCS1v15Signer, error) { if priv == nil { return nil, errors.New("invalid RSA private key specified") } if !isSupportedAlg(hf, rsaSupportedHashFuncs) { return nil, errors.New("invalid hash function specified") } return &RSAPKCS1v15Signer{ priv: priv, hashFunc: hf, }, nil } // SignMessage signs the provided message using PKCS1v15. If the message is provided, // this method will compute the digest according to the hash function specified // when the RSAPKCS1v15Signer was created. // // SignMessage recognizes the following Options listed in order of preference: // // - WithRand() // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (r RSAPKCS1v15Signer) SignMessage(message io.Reader, opts ...SignOption) ([]byte, error) { digest, hf, err := ComputeDigestForSigning(message, r.hashFunc, rsaSupportedHashFuncs, opts...) if err != nil { return nil, err } rand := selectRandFromOpts(opts...) return rsa.SignPKCS1v15(rand, r.priv, hf, digest) } // Public returns the public key that can be used to verify signatures created by // this signer. func (r RSAPKCS1v15Signer) Public() crypto.PublicKey { if r.priv == nil { return nil } return r.priv.Public() } // PublicKey returns the public key that can be used to verify signatures created by // this signer. As this value is held in memory, all options provided in arguments // to this method are ignored. func (r RSAPKCS1v15Signer) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return r.Public(), nil } // Sign computes the signature for the specified digest using PKCS1v15. // // If a source of entropy is given in rand, it will be used instead of the default value (rand.Reader // from crypto/rand). // // If opts are specified, they should specify the hash function used to compute digest. If opts are // not specified, this function assumes the hash function provided when the signer was created was // used to create the value specified in digest. func (r RSAPKCS1v15Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { rsaOpts := []SignOption{options.WithDigest(digest), options.WithRand(rand)} if opts != nil { rsaOpts = append(rsaOpts, options.WithCryptoSignerOpts(opts)) } return r.SignMessage(nil, rsaOpts...) } // RSAPKCS1v15Verifier is a signature.Verifier that uses the RSA PKCS1v15 algorithm type RSAPKCS1v15Verifier struct { publicKey *rsa.PublicKey hashFunc crypto.Hash } // LoadRSAPKCS1v15Verifier returns a Verifier that verifies signatures using the specified // RSA public key and hash algorithm. // // hf must be either SHA256, SHA388, or SHA512. func LoadRSAPKCS1v15Verifier(pub *rsa.PublicKey, hashFunc crypto.Hash) (*RSAPKCS1v15Verifier, error) { if pub == nil { return nil, errors.New("invalid RSA public key specified") } if !isSupportedAlg(hashFunc, rsaSupportedHashFuncs) { return nil, errors.New("invalid hash function specified") } return &RSAPKCS1v15Verifier{ publicKey: pub, hashFunc: hashFunc, }, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (r RSAPKCS1v15Verifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return r.publicKey, nil } // VerifySignature verifies the signature for the given message using PKCS1v15. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the RSAPKCS1v15Verifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (r RSAPKCS1v15Verifier) VerifySignature(signature, message io.Reader, opts ...VerifyOption) error { digest, hf, err := ComputeDigestForVerifying(message, r.hashFunc, rsaSupportedVerifyHashFuncs, opts...) if err != nil { return err } if signature == nil { return errors.New("nil signature passed to VerifySignature") } sigBytes, err := io.ReadAll(signature) if err != nil { return fmt.Errorf("reading signature: %w", err) } return rsa.VerifyPKCS1v15(r.publicKey, hf, digest, sigBytes) } // RSAPKCS1v15SignerVerifier is a signature.SignerVerifier that uses the RSA PKCS1v15 algorithm type RSAPKCS1v15SignerVerifier struct { *RSAPKCS1v15Signer *RSAPKCS1v15Verifier } // LoadRSAPKCS1v15SignerVerifier creates a combined signer and verifier. This is a convenience object // that simply wraps an instance of RSAPKCS1v15Signer and RSAPKCS1v15Verifier. func LoadRSAPKCS1v15SignerVerifier(priv *rsa.PrivateKey, hf crypto.Hash) (*RSAPKCS1v15SignerVerifier, error) { signer, err := LoadRSAPKCS1v15Signer(priv, hf) if err != nil { return nil, fmt.Errorf("initializing signer: %w", err) } verifier, err := LoadRSAPKCS1v15Verifier(&priv.PublicKey, hf) if err != nil { return nil, fmt.Errorf("initializing verifier: %w", err) } return &RSAPKCS1v15SignerVerifier{ RSAPKCS1v15Signer: signer, RSAPKCS1v15Verifier: verifier, }, nil } // NewDefaultRSAPKCS1v15SignerVerifier creates a combined signer and verifier using RSA PKCS1v15. // This creates a new RSA key of 2048 bits and uses the SHA256 hashing algorithm. func NewDefaultRSAPKCS1v15SignerVerifier() (*RSAPKCS1v15SignerVerifier, *rsa.PrivateKey, error) { return NewRSAPKCS1v15SignerVerifier(rand.Reader, 2048, crypto.SHA256) } // NewRSAPKCS1v15SignerVerifier creates a combined signer and verifier using RSA PKCS1v15. // This creates a new RSA key of the specified length of bits, entropy source, and hash function. func NewRSAPKCS1v15SignerVerifier(rand io.Reader, bits int, hashFunc crypto.Hash) (*RSAPKCS1v15SignerVerifier, *rsa.PrivateKey, error) { priv, err := rsa.GenerateKey(rand, bits) if err != nil { return nil, nil, err } sv, err := LoadRSAPKCS1v15SignerVerifier(priv, hashFunc) if err != nil { return nil, nil, err } return sv, priv, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (r RSAPKCS1v15SignerVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return r.publicKey, nil } sigstore-1.8.6/pkg/signature/rsapkcs1v15_test.go000066400000000000000000000050671463713551000216350ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/rsa" "encoding/base64" "strings" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) // keys defined in rsapss_test.go func TestRSAPKCS1v15SignerVerifier(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(rsaKey), cryptoutils.SkipPassword) if err != nil { t.Errorf("unexpected error unmarshalling private key: %v", err) } sv, err := LoadRSAPKCS1v15SignerVerifier(privateKey.(*rsa.PrivateKey), crypto.SHA256) if err != nil { t.Errorf("unexpected error creating signer/verifier: %v", err) } message := []byte("sign me") // created with openssl dgst -sign privKey.pem -sha256 sig, _ := base64.StdEncoding.DecodeString("AMpSInspjqXdigO0vACd7KMilwLMnrHqnSitnyY0dNiIQ912I2wEme3sMqAMeWnsJ26BxObqV2iMZiggnmeMwd92+6dWpfc2is7m3IbdrUmwKG8y4WDegXEq+EWOy6qsPoqXFPgn1500MFkwrMASP035Gu6wTPmc92zimKozT91j2MNBSONWlcrP89DYBpSVnX+AUs4CKJUppRH/AeyKtftm8GC2TOGrG83U5JqDNegbp5Sji3ViAbUtbiHfob4o1VDGqlyCLgaB0sthekI0XFucWHJj9xRBFazcSBA7Bw1I+T08SqsjfP9Gz43VkItnZbwXMWdSRV81vEK0UuX/rA==") testingSigner(t, sv, "rsa", crypto.SHA256, message) testingVerifier(t, sv, "rsa", crypto.SHA256, sig, message) publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(pubKey)) if err != nil { t.Errorf("unexpected error unmarshalling public key: %v", err) } v, err := LoadRSAPKCS1v15Verifier(publicKey.(*rsa.PublicKey), crypto.SHA256) if err != nil { t.Errorf("unexpected error creating verifier: %v", err) } testingVerifier(t, v, "rsa", crypto.SHA256, sig, message) } func TestRSAPKCS1v15SignerVerifierUnsupportedHash(t *testing.T) { publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(pubKey)) if err != nil { t.Errorf("unexpected error unmarshalling public key: %v", err) } _, err = LoadRSAPKCS1v15Verifier(publicKey.(*rsa.PublicKey), crypto.SHA1) if !strings.Contains(err.Error(), "invalid hash function specified") { t.Errorf("expected error 'invalid hash function specified', got: %v", err.Error()) } } sigstore-1.8.6/pkg/signature/rsapss.go000066400000000000000000000200511463713551000200140ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/rand" "crypto/rsa" "errors" "fmt" "io" "github.com/sigstore/sigstore/pkg/signature/options" ) // checked on LoadSigner, LoadVerifier, and SignMessage var rsaSupportedHashFuncs = []crypto.Hash{ crypto.SHA256, crypto.SHA384, crypto.SHA512, } // checked on VerifySignature. Supports SHA1 verification. var rsaSupportedVerifyHashFuncs = []crypto.Hash{ crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512, } // RSAPSSSigner is a signature.Signer that uses the RSA PSS algorithm type RSAPSSSigner struct { hashFunc crypto.Hash priv *rsa.PrivateKey pssOpts *rsa.PSSOptions } // LoadRSAPSSSigner calculates signatures using the specified private key and hash algorithm. // // If opts are specified, then they will be stored and used as a default if not overridden // by the value passed to Sign(). // // hf must be either SHA256, SHA388, or SHA512. opts.Hash is ignored. func LoadRSAPSSSigner(priv *rsa.PrivateKey, hf crypto.Hash, opts *rsa.PSSOptions) (*RSAPSSSigner, error) { if priv == nil { return nil, errors.New("invalid RSA private key specified") } if !isSupportedAlg(hf, rsaSupportedHashFuncs) { return nil, errors.New("invalid hash function specified") } return &RSAPSSSigner{ priv: priv, pssOpts: opts, hashFunc: hf, }, nil } // SignMessage signs the provided message using PSS. If the message is provided, // this method will compute the digest according to the hash function specified // when the RSAPSSSigner was created. // // This function recognizes the following Options listed in order of preference: // // - WithRand() // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (r RSAPSSSigner) SignMessage(message io.Reader, opts ...SignOption) ([]byte, error) { digest, hf, err := ComputeDigestForSigning(message, r.hashFunc, rsaSupportedHashFuncs, opts...) if err != nil { return nil, err } rand := selectRandFromOpts(opts...) pssOpts := r.pssOpts if pssOpts == nil { pssOpts = &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, } } pssOpts.Hash = hf return rsa.SignPSS(rand, r.priv, hf, digest, pssOpts) } // Public returns the public key that can be used to verify signatures created by // this signer. func (r RSAPSSSigner) Public() crypto.PublicKey { if r.priv == nil { return nil } return r.priv.Public() } // PublicKey returns the public key that can be used to verify signatures created by // this signer. As this value is held in memory, all options provided in arguments // to this method are ignored. func (r RSAPSSSigner) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return r.Public(), nil } // Sign computes the signature for the specified digest using PSS. // // If a source of entropy is given in rand, it will be used instead of the default value (rand.Reader // from crypto/rand). // // If opts are specified, they must be *rsa.PSSOptions. If opts are not specified, the hash function // provided when the signer was created will be assumed. func (r RSAPSSSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { rsaOpts := []SignOption{options.WithDigest(digest), options.WithRand(rand)} if opts != nil { rsaOpts = append(rsaOpts, options.WithCryptoSignerOpts(opts)) } return r.SignMessage(nil, rsaOpts...) } // RSAPSSVerifier is a signature.Verifier that uses the RSA PSS algorithm type RSAPSSVerifier struct { publicKey *rsa.PublicKey hashFunc crypto.Hash pssOpts *rsa.PSSOptions } // LoadRSAPSSVerifier verifies signatures using the specified public key and hash algorithm. // // hf must be either SHA256, SHA388, or SHA512. opts.Hash is ignored. func LoadRSAPSSVerifier(pub *rsa.PublicKey, hashFunc crypto.Hash, opts *rsa.PSSOptions) (*RSAPSSVerifier, error) { if pub == nil { return nil, errors.New("invalid RSA public key specified") } if !isSupportedAlg(hashFunc, rsaSupportedHashFuncs) { return nil, errors.New("invalid hash function specified") } return &RSAPSSVerifier{ publicKey: pub, hashFunc: hashFunc, pssOpts: opts, }, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (r RSAPSSVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return r.publicKey, nil } // VerifySignature verifies the signature for the given message using PSS. Unless provided // in an option, the digest of the message will be computed using the hash function specified // when the RSAPSSVerifier was created. // // This function returns nil if the verification succeeded, and an error message otherwise. // // This function recognizes the following Options listed in order of preference: // // - WithDigest() // // - WithCryptoSignerOpts() // // All other options are ignored if specified. func (r RSAPSSVerifier) VerifySignature(signature, message io.Reader, opts ...VerifyOption) error { digest, hf, err := ComputeDigestForVerifying(message, r.hashFunc, rsaSupportedVerifyHashFuncs, opts...) if err != nil { return err } if signature == nil { return errors.New("nil signature passed to VerifySignature") } sigBytes, err := io.ReadAll(signature) if err != nil { return fmt.Errorf("reading signature: %w", err) } // rsa.VerifyPSS ignores pssOpts.Hash, so we don't set it pssOpts := r.pssOpts if pssOpts == nil { pssOpts = &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, } } return rsa.VerifyPSS(r.publicKey, hf, digest, sigBytes, pssOpts) } // RSAPSSSignerVerifier is a signature.SignerVerifier that uses the RSA PSS algorithm type RSAPSSSignerVerifier struct { *RSAPSSSigner *RSAPSSVerifier } // LoadRSAPSSSignerVerifier creates a combined signer and verifier using RSA PSS. This is // a convenience object that simply wraps an instance of RSAPSSSigner and RSAPSSVerifier. func LoadRSAPSSSignerVerifier(priv *rsa.PrivateKey, hf crypto.Hash, opts *rsa.PSSOptions) (*RSAPSSSignerVerifier, error) { signer, err := LoadRSAPSSSigner(priv, hf, opts) if err != nil { return nil, fmt.Errorf("initializing signer: %w", err) } verifier, err := LoadRSAPSSVerifier(&priv.PublicKey, hf, opts) if err != nil { return nil, fmt.Errorf("initializing verifier: %w", err) } return &RSAPSSSignerVerifier{ RSAPSSSigner: signer, RSAPSSVerifier: verifier, }, nil } // NewDefaultRSAPSSSignerVerifier creates a combined signer and verifier using RSA PSS. // This creates a new RSA key of 2048 bits and uses the SHA256 hashing algorithm. func NewDefaultRSAPSSSignerVerifier() (*RSAPSSSignerVerifier, *rsa.PrivateKey, error) { return NewRSAPSSSignerVerifier(rand.Reader, 2048, crypto.SHA256) } // NewRSAPSSSignerVerifier creates a combined signer and verifier using RSA PSS. // This creates a new RSA key of the specified length of bits, entropy source, and hash function. func NewRSAPSSSignerVerifier(rand io.Reader, bits int, hashFunc crypto.Hash) (*RSAPSSSignerVerifier, *rsa.PrivateKey, error) { priv, err := rsa.GenerateKey(rand, bits) if err != nil { return nil, nil, err } sv, err := LoadRSAPSSSignerVerifier(priv, hashFunc, &rsa.PSSOptions{Hash: hashFunc}) if err != nil { return nil, nil, err } return sv, priv, nil } // PublicKey returns the public key that is used to verify signatures by // this verifier. As this value is held in memory, all options provided in arguments // to this method are ignored. func (r RSAPSSSignerVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) { return r.publicKey, nil } sigstore-1.8.6/pkg/signature/rsapss_test.go000066400000000000000000000126061463713551000210620ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/rsa" "encoding/base64" "strings" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) const rsaKey = `-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfCoj9PKxSIpOB jVvP7B0l8Q6KXgwSxEBIobMl11nrH2Fv6ufZRWgma7E3rZcjRMygyfia6SB8KBjq OBMHnxX78tp5IDxbPWniA7GGTWZyBsXgfLFH7GVGBh8fiJJtfL4TP/xmMzY47rx8 qvglkQDktdmSEmvfYmof5SIXD/CBI9YDxpXQB9EBcd16QnjwHUKHElOs4lZI9OeP 8TSV8tWyskq1cO4LxPS8WZVTvbq0jp84OwQTpWtJqG/DUQ1QfMjfixt+uauCDA87 iIwBC+rC7aCfaXHpqNayHzToUi2Jc34O6LMyfHgowEjQgnKehClY4Vuy0aJXQvKB mRDqyjO/AgMBAAECggEBAIHOAs3Gis8+WjRSjXVjh882DG1QsJwXZQYgPT+vpiAl YjKdNpOHRkbd9ARgXY5kEuccxDd7p7E6MM3XFpQf7M51ltpZfWboRgAIgD+WOiHw eSbdytr95C6tj11twTJBH+naGk1sTokxv7aaVdKfIjL49oeBexBFmVe4pW9gkmrE 1z1y1a0RohqbZ0kprYPWjz5UhsNqbCzgkdDqS7IrcOwVg6zvKYFjHnqIHqaJXVif FgIfoNt7tz+12FTHI+6OkKoN3YCJueaxneBhITXm6RLOpQWa9qhdUPbkJ9vQNfph Qqke4faaxKY9UDma+GpEHR016AWufZp92pd9wQkDn0kCgYEA7w/ZizAkefHoZhZ8 Isn/fYu4fdtUaVgrnGUVZobiGxWrHRU9ikbAwR7UwbgRSfppGiJdAMq1lyH2irmb 4OHU64rjuYSlIqUWHLQHWmqUbLUvlDojH/vdmH/Zn0AbrLZaimC5UCjK3Eb7sAMq G0tGeDX2JraQvx7KrbC6peTaaaMCgYEA7tgZBiRCQJ7+mNu+gX9x6OXtjsDCh516 vToRLkxWc7LAbC9LKsuEHl4e3vy1PY/nyuv12Ng2dBq4WDXozAmVgz0ok7rRlIFp w8Yj8o/9KuGZkD/7tw/pLsVc9Q3Wf0ACrnAAh7+3dAvn3yg+WHwXzqWIbrseDPt9 ILCfUoNDpzUCgYAKFCX8y0PObFd67lm/cbq2xUw66iNN6ay1BEH5t5gSwkAbksis ar03pyAbJrJ75vXFZ0t6fBFZ1NG7GYYr3fmHEKz3JlN7+W/MN/7TXgjx6FWgLy9J 6ul1w3YeU6qXBn0ctmU5ru6WiNuVmRyOWAcZjFTbXvkNRbQPzJKh6dsXdwKBgA1D FIihxMf/zBVCxl48bF/JPJqbm3GaTfFp4wBWHsrH1yVqrtrOeCSTh1VMZOfpMK60 0W7b+pIR1cCYJbgGpDWoVLN3QSHk2bGUM/TJB/60jilTVC/DA2ikbtfwj8N7E2sK Lw1amN4ptxNOEcAqC8xepqe3XiDMahNBm2cigMQtAoGBAKwrXvss2BKz+/6poJQU A0c7jhMN8M9Y5S2Ockw07lrQeAgfu4q+/8ztm0NeHJbk01IJvJY5Nt7bSgwgNVlo j7vR2BMAc9U73Ju9aeTl/L6GqmZyA+Ojhl5gA5DPZYqNiqi93ydgRaI6n4+o3dI7 5wnr40AmbuKCDvMOvN7nMybL -----END PRIVATE KEY-----` // Extracted from the certificate using: // openssl x509 -pubkey -noout -in test.crt const pubKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3wqI/TysUiKTgY1bz+wd JfEOil4MEsRASKGzJddZ6x9hb+rn2UVoJmuxN62XI0TMoMn4mukgfCgY6jgTB58V +/LaeSA8Wz1p4gOxhk1mcgbF4HyxR+xlRgYfH4iSbXy+Ez/8ZjM2OO68fKr4JZEA 5LXZkhJr32JqH+UiFw/wgSPWA8aV0AfRAXHdekJ48B1ChxJTrOJWSPTnj/E0lfLV srJKtXDuC8T0vFmVU726tI6fODsEE6VrSahvw1ENUHzI34sbfrmrggwPO4iMAQvq wu2gn2lx6ajWsh806FItiXN+DuizMnx4KMBI0IJynoQpWOFbstGiV0LygZkQ6soz vwIDAQAB -----END PUBLIC KEY-----` func TestRSAPSSSignerVerifier(t *testing.T) { opts := &rsa.PSSOptions{ Hash: crypto.SHA256, } privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(rsaKey), cryptoutils.SkipPassword) if err != nil { t.Errorf("unexpected error unmarshalling private key: %v", err) } sv, err := LoadRSAPSSSignerVerifier(privateKey.(*rsa.PrivateKey), crypto.SHA256, opts) if err != nil { t.Errorf("unexpected error creating signer/verifier: %v", err) } message := []byte("sign me") // created with openssl dgst -sign privKey.pem -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -sha256 sig, _ := base64.StdEncoding.DecodeString("UyouJxmgAKdm/Qfi9YA7aK71/eqyLcytmDN8CQqSCgcbGSln7S5fgIAmrwUfGp1tcxKjuNjLScn11+fqawiG9y66740VEC6GfS1hgElC2k3i/v8ly2mlt+4JYs3euzYxtWnxwQr4csc7Jy2V2cjoeQm6GTxkR4E6TRJM8/UxXvjKtp3rxRD8OuyfuGFkI0lU48vjKLgbuZKQqQdWuNUOnsPvtrHxvGRY/F1C0Ig3b7SoTyAjWSXQG42faKsFT+W1L/UdRK+m73TYdxMleI4uIGtl0k0Weui1/gK7Uh2FUP5+/F1ZoQRYk/DMz0M4QPmPsYLGwc8oduoF6JvNMGKymg==") testingSigner(t, sv, "rsa", crypto.SHA256, message) testingVerifier(t, sv, "rsa", crypto.SHA256, sig, message) // test with nil opts (sane defaults) sv, err = LoadRSAPSSSignerVerifier(privateKey.(*rsa.PrivateKey), crypto.SHA256, nil) if err != nil { t.Errorf("unexpected error creating signer/verifier: %v", err) } testingSigner(t, sv, "rsa", crypto.SHA256, message) testingVerifier(t, sv, "rsa", crypto.SHA256, sig, message) publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(pubKey)) if err != nil { t.Errorf("unexpected error unmarshalling public key: %v", err) } v, err := LoadRSAPSSVerifier(publicKey.(*rsa.PublicKey), crypto.SHA256, opts) if err != nil { t.Errorf("unexpected error creating verifier: %v", err) } testingVerifier(t, v, "rsa", crypto.SHA256, sig, message) v, err = LoadRSAPSSVerifier(publicKey.(*rsa.PublicKey), crypto.SHA256, nil) if err != nil { t.Errorf("unexpected error creating verifier with nil opts: %v", err) } testingVerifier(t, v, "rsa", crypto.SHA256, sig, message) } func TestRSAPSSSignerVerifierUnsupportedHash(t *testing.T) { publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(pubKey)) if err != nil { t.Errorf("unexpected error unmarshalling public key: %v", err) } _, err = LoadRSAPSSVerifier(publicKey.(*rsa.PublicKey), crypto.SHA1, nil) if !strings.Contains(err.Error(), "invalid hash function specified") { t.Errorf("expected error 'invalid hash function specified', got: %v", err.Error()) } } sigstore-1.8.6/pkg/signature/signer.go000066400000000000000000000077221463713551000200020ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "errors" "io" "os" "path/filepath" // these ensure we have the implementations loaded _ "crypto/sha256" _ "crypto/sha512" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/options" // these ensure we have the implementations loaded _ "golang.org/x/crypto/sha3" ) // Signer creates digital signatures over a message using a specified key pair type Signer interface { PublicKeyProvider SignMessage(message io.Reader, opts ...SignOption) ([]byte, error) } // SignerOpts implements crypto.SignerOpts but also allows callers to specify // additional options that may be utilized in signing the digest provided. type SignerOpts struct { Hash crypto.Hash Opts []SignOption } // HashFunc returns the hash function for this object func (s SignerOpts) HashFunc() crypto.Hash { return s.Hash } // LoadSigner returns a signature.Signer based on the algorithm of the private key // provided. // // If privateKey is an RSA key, a RSAPKCS1v15Signer will be returned. If a // RSAPSSSigner is desired instead, use the LoadRSAPSSSigner() method directly. func LoadSigner(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (Signer, error) { return LoadSignerWithOpts(privateKey, options.WithHash(hashFunc)) } // LoadSignerWithOpts returns a signature.Signer based on the algorithm of the private key // provided. func LoadSignerWithOpts(privateKey crypto.PrivateKey, opts ...LoadOption) (Signer, error) { var rsaPSSOptions *rsa.PSSOptions var useED25519ph bool hashFunc := crypto.SHA256 for _, o := range opts { o.ApplyED25519ph(&useED25519ph) o.ApplyHash(&hashFunc) o.ApplyRSAPSS(&rsaPSSOptions) } switch pk := privateKey.(type) { case *rsa.PrivateKey: if rsaPSSOptions != nil { return LoadRSAPSSSigner(pk, hashFunc, rsaPSSOptions) } return LoadRSAPKCS1v15Signer(pk, hashFunc) case *ecdsa.PrivateKey: return LoadECDSASigner(pk, hashFunc) case ed25519.PrivateKey: if useED25519ph { return LoadED25519phSigner(pk) } return LoadED25519Signer(pk) } return nil, errors.New("unsupported public key type") } // LoadSignerFromPEMFile returns a signature.Signer based on the algorithm of the private key // in the file. The Signer will use the hash function specified when computing digests. // // If key is an RSA key, a RSAPKCS1v15Signer will be returned. If a // RSAPSSSigner is desired instead, use the LoadRSAPSSSigner() and // cryptoutils.UnmarshalPEMToPrivateKey() methods directly. func LoadSignerFromPEMFile(path string, hashFunc crypto.Hash, pf cryptoutils.PassFunc) (Signer, error) { fileBytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf) if err != nil { return nil, err } return LoadSigner(priv, hashFunc) } // LoadSignerFromPEMFileWithOpts returns a signature.Signer based on the algorithm of the private key // in the file. The Signer will use the hash function specified in the options when computing digests. func LoadSignerFromPEMFileWithOpts(path string, pf cryptoutils.PassFunc, opts ...LoadOption) (Signer, error) { fileBytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf) if err != nil { return nil, err } return LoadSignerWithOpts(priv, opts...) } sigstore-1.8.6/pkg/signature/signer_test.go000066400000000000000000000047701463713551000210410ustar00rootroot00000000000000// Copyright 2024 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 signature import ( "bytes" "crypto" "crypto/ed25519" "encoding/base64" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/options" ) func TestLoadEd25519Signer(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ed25519Priv), cryptoutils.SkipPassword) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPriv, ok := privateKey.(ed25519.PrivateKey) if !ok { t.Fatalf("expected ed25519.PrivateKey") } signer, err := LoadSigner(edPriv, crypto.SHA256) if err != nil { t.Fatalf("unexpected error loading verifier: %v", err) } msg := []byte("sign me") sig, err := signer.SignMessage(bytes.NewReader(msg)) if err != nil { t.Fatalf("unexpected error signing message: %v", err) } expectedSig, _ := base64.StdEncoding.DecodeString("cnafwd8DKq2nQ564eN66ckYV8anVFGFi5vaYiQg2aal7ej/J0/OE0PPdKHLHe9wdzWRMFy5MpurRD/2cGXGLBQ==") if !bytes.Equal(sig, expectedSig) { t.Fatalf("signature was not as expected") } } func TestLoadEd25519phSigner(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ed25519Priv), cryptoutils.SkipPassword) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPriv, ok := privateKey.(ed25519.PrivateKey) if !ok { t.Fatalf("expected ed25519.PrivateKey") } signer, err := LoadSignerWithOpts(edPriv, options.WithED25519ph(), options.WithHash(crypto.SHA512)) if err != nil { t.Fatalf("unexpected error loading verifier: %v", err) } msg := []byte("sign me") sig, err := signer.SignMessage(bytes.NewReader(msg)) if err != nil { t.Fatalf("unexpected error signing message: %v", err) } expectedSig, _ := base64.StdEncoding.DecodeString("9D4pA8jutZnbqKy4fFRl+kDsVUCO50qrOD1lxmsiUFk6NX+7OXUK5BCMkE2KYPRDxjkDFBzbDZEQhaFdDV5tDg==") if !bytes.Equal(sig, expectedSig) { t.Fatalf("signature was not as expected") } } sigstore-1.8.6/pkg/signature/signerverifier.go000066400000000000000000000073031463713551000215310ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "errors" "os" "path/filepath" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/options" ) // SignerVerifier creates and verifies digital signatures over a message using a specified key pair type SignerVerifier interface { Signer Verifier } // LoadSignerVerifier returns a signature.SignerVerifier based on the algorithm of the private key // provided. // // If privateKey is an RSA key, a RSAPKCS1v15SignerVerifier will be returned. If a // RSAPSSSignerVerifier is desired instead, use the LoadRSAPSSSignerVerifier() method directly. func LoadSignerVerifier(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (SignerVerifier, error) { return LoadSignerVerifierWithOpts(privateKey, options.WithHash(hashFunc)) } // LoadSignerVerifierWithOpts returns a signature.SignerVerifier based on the // algorithm of the private key provided and the user's choice. func LoadSignerVerifierWithOpts(privateKey crypto.PrivateKey, opts ...LoadOption) (SignerVerifier, error) { var rsaPSSOptions *rsa.PSSOptions var useED25519ph bool hashFunc := crypto.SHA256 for _, o := range opts { o.ApplyED25519ph(&useED25519ph) o.ApplyHash(&hashFunc) o.ApplyRSAPSS(&rsaPSSOptions) } switch pk := privateKey.(type) { case *rsa.PrivateKey: if rsaPSSOptions != nil { return LoadRSAPSSSignerVerifier(pk, hashFunc, rsaPSSOptions) } return LoadRSAPKCS1v15SignerVerifier(pk, hashFunc) case *ecdsa.PrivateKey: return LoadECDSASignerVerifier(pk, hashFunc) case ed25519.PrivateKey: if useED25519ph { return LoadED25519phSignerVerifier(pk) } return LoadED25519SignerVerifier(pk) } return nil, errors.New("unsupported public key type") } // LoadSignerVerifierFromPEMFile returns a signature.SignerVerifier based on the algorithm of the private key // in the file. The SignerVerifier will use the hash function specified when computing digests. // // If publicKey is an RSA key, a RSAPKCS1v15SignerVerifier will be returned. If a // RSAPSSSignerVerifier is desired instead, use the LoadRSAPSSSignerVerifier() and // cryptoutils.UnmarshalPEMToPrivateKey() methods directly. func LoadSignerVerifierFromPEMFile(path string, hashFunc crypto.Hash, pf cryptoutils.PassFunc) (SignerVerifier, error) { fileBytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf) if err != nil { return nil, err } return LoadSignerVerifier(priv, hashFunc) } // LoadSignerVerifierFromPEMFileWithOpts returns a signature.SignerVerifier based on the algorithm of the private key // in the file. The SignerVerifier will use the hash function specified in the options when computing digests. func LoadSignerVerifierFromPEMFileWithOpts(path string, pf cryptoutils.PassFunc, opts ...LoadOption) (SignerVerifier, error) { fileBytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf) if err != nil { return nil, err } return LoadSignerVerifierWithOpts(priv, opts...) } sigstore-1.8.6/pkg/signature/signerverifier_test.go000066400000000000000000000060511463713551000225670ustar00rootroot00000000000000// Copyright 2024 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 signature import ( "bytes" "crypto" "crypto/ed25519" "crypto/rsa" "encoding/base64" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/options" ) func TestLoadRSAPSSSignerVerifier(t *testing.T) { opts := &rsa.PSSOptions{ Hash: crypto.SHA256, } privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(rsaKey), cryptoutils.SkipPassword) if err != nil { t.Errorf("unexpected error unmarshalling private key: %v", err) } sv, err := LoadSignerVerifierWithOpts(privateKey, options.WithHash(crypto.SHA256), options.WithED25519ph(), options.WithRSAPSS(opts)) if err != nil { t.Errorf("unexpected error creating signer/verifier: %v", err) } message := []byte("sign me") sig, err := sv.SignMessage(bytes.NewReader(message)) if err != nil { t.Fatalf("unexpected error signing message: %v", err) } if err := sv.VerifySignature(bytes.NewReader(sig), bytes.NewReader(message)); err != nil { t.Fatalf("unexpected error verifying calculated signature: %v", err) } expectedSig, _ := base64.StdEncoding.DecodeString("UyouJxmgAKdm/Qfi9YA7aK71/eqyLcytmDN8CQqSCgcbGSln7S5fgIAmrwUfGp1tcxKjuNjLScn11+fqawiG9y66740VEC6GfS1hgElC2k3i/v8ly2mlt+4JYs3euzYxtWnxwQr4csc7Jy2V2cjoeQm6GTxkR4E6TRJM8/UxXvjKtp3rxRD8OuyfuGFkI0lU48vjKLgbuZKQqQdWuNUOnsPvtrHxvGRY/F1C0Ig3b7SoTyAjWSXQG42faKsFT+W1L/UdRK+m73TYdxMleI4uIGtl0k0Weui1/gK7Uh2FUP5+/F1ZoQRYk/DMz0M4QPmPsYLGwc8oduoF6JvNMGKymg==") if err := sv.VerifySignature(bytes.NewReader(expectedSig), bytes.NewReader(message)); err != nil { t.Fatalf("unexpected error verifying expected signature: %v", err) } } func TestConvertED25519ph(t *testing.T) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(ed25519Priv), cryptoutils.SkipPassword) if err != nil { t.Fatalf("unexpected error unmarshalling public key: %v", err) } edPriv, ok := privateKey.(ed25519.PrivateKey) if !ok { t.Fatalf("expected ed25519.PrivateKey") } sv, err := LoadED25519phSignerVerifier(edPriv) if err != nil { t.Fatalf("unexpected error creating signer/verifier: %v", err) } newSV, err := sv.ToED25519SignerVerifier() if err != nil { t.Fatalf("unexpected error converting to ed25519: %v", err) } message := []byte("sign me") sig, _ := base64.StdEncoding.DecodeString("cnafwd8DKq2nQ564eN66ckYV8anVFGFi5vaYiQg2aal7ej/J0/OE0PPdKHLHe9wdzWRMFy5MpurRD/2cGXGLBQ==") testingSigner(t, newSV, "ed25519", crypto.SHA256, message) testingVerifier(t, newSV, "ed25519", crypto.SHA256, sig, message) } sigstore-1.8.6/pkg/signature/ssh/000077500000000000000000000000001463713551000167515ustar00rootroot00000000000000sigstore-1.8.6/pkg/signature/ssh/README.md000066400000000000000000000102601463713551000202270ustar00rootroot00000000000000# SSH File Signatures SSH keys can be used to sign files! Unfortunately this is a pretty recent change to the openssh tooling, so it is not supported by golang.org/x/crypto/ssh yet. This document explains how it works at a high level. ## Keys SSH keys are usually split into public and private files, named `id_rsa.pub` and `id_rsa`, respectively. These files are encoded and formatted a little differently than other signing keys. ### Public Keys These are typically in the "known hosts" format. This looks something like: ``` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDw0ZWP4zZLELSJVenQTQsrFJVBnoP64KTg/UWRU6qOb8HEOdtHJDOyTmo9dvN/yJoTFtWAfQEjaTsMVJzTD0gOk6ncTsp0BUtgXawSCfEUiv7v+2VgSVbUfAv/NL+HEGSCdcORnansIyrZaHwAjR3ei3O+pRWvgjRj3pOH1rWGrxaC5IbsELYzS/HvwAG/uwcxgBv4POvaq6eCEHVbqRjIYjjoYsC+c24sgSQxOyXvDS7j2z9TPHPvepDhVr9y6xnnqhLqZEWmidRrbb35aYkVLJxmGTFy/JW1cewyU2Jb3+sKQOiOwL7DAB39tRyec2ed+EHh6QLW4pcMnoXsWuPyi+G595HiUYmIlqXJ5JPo0Cv/rOJrmWSFceWiDjC/SeODp/AcK0EsN/p3wOp6ac7EzAz9Npri0vwSQX4MUYlya/olKiKCx5GIhTZtXioREPd8v4osx2VrVyDxKX99PVVbxw1FXSe4u+PuOawJzUA4vW41mxUY9zoAsb/fvoNPtrrT9HfC+7Pg6ryBdz+445M8Atc8YjjLeYXkTXWD6KMielRzBFFoIwIgi0bMotq3iQ9IwjQSXPMDQLb+UPg8xqsgRsX3wvyZzdBhxO4Bdomv7JYmySysaGgliHktU8qRse1lpDIXMovPtowywcKL4U3seDKrq7saVO0qdsLavy1o0w== lorenc.d@gmail.com ``` These can be parsed with [ParseKnownHosts](https://pkg.go.dev/golang.org/x/crypto/ssh#ParseKnownHosts) , NOT `ParsePublicKey`. In addition to the key material itself, this can contain the algorithm (`ssh-rsa` here) and a comment (lorenc.d@gmail.com) here. ### Private Keys These are stored in an "armored" PEM format, resembling PGP or x509 keys: ``` -----BEGIN SSH PRIVATE KEY----- -----END SSH PRIVATE KEY----- ``` These can be parsed correctly with [ParsePrivateKey](https://pkg.go.dev/golang.org/x/crypto/ssh#ParsePrivateKey). ## Wire Format The wire format is relatively standard. * Bytes are laid out in order. * Fixed-length fields are laid out at the proper offset with the specified length. * Strings are stored with the size as a prefix. ## Signature These can be generated and validated from the command line with the `ssh-keygen -Y` set of commands: `sign`, `verify`, and `check-novalidate`. To work with them in Go is a little tricker. The signature is stored using a struct packed using the `openssh` wire format. The data that is used in the signing function is also packed in another struct before it is signed. ### Signature Format Signatures are formatted on disk in a PEM-encoded format. The header is `-----BEGIN SSH SIGNATURE-----`, and the end is `-----BEGIN SSH SIGNATURE-----`. The signature contents are base64-encoded. The signature contents are wrapped with extra metadata, then encoded as a struct using the `openssh` wire format. That struct is defined [here](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L34). In Go: ``` type wrappedSig struct { MagicHeader [6]byte Version uint32 PublicKey string Namespace string Reserved string HashAlgorithm string Signature string } ``` The `PublicKey` and `Signature` fields are also stored as openssh-wire-formatted structs. The `MagicHeader` is `SSHSIG`. The `Version` is 1. The `Namespace` is `file` (for this use-case). `Reserved` must be empty. Go can already parse the `PublicKey` and `Signature` fields, and the `Signature` struct contains a `Blob` with the signature data. ### Signed Message In addition to these wrappers, the message to be signed is wrapped with some metadata before it is passed to the signing function. That wrapper is defined [here](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L81). And in Go: ``` type messageWrapper struct { Namespace string Reserved string HashAlgorithm string Hash string } ``` So, the data must first be hashed, then packed in this struct and encoded in the openssh wire format. Then, this resulting data is signed using the desired signature function. The `Namespace` field must be `file` (for this usecase). The `Reserved` field must be empty. The output of this signature function (and the hash) becomes the `Signature.Blob` value, which gets wire-encoded, wrapped, wire-encoded and finally pem-encoded. sigstore-1.8.6/pkg/signature/ssh/armor.go000066400000000000000000000052511463713551000204230ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package ssh implements signing with SSH keys package ssh import ( "encoding/pem" "errors" "fmt" "golang.org/x/crypto/ssh" ) const ( namespace = "file" pemType = "SSH SIGNATURE" ) // Signature encapsulates an SSH Signature object for verification. type Signature struct { signature *ssh.Signature pk ssh.PublicKey hashAlg string } // Armor generates a PEM armored signature block. func Armor(s *ssh.Signature, p ssh.PublicKey) []byte { sig := wrappedSig{ Version: 1, PublicKey: string(p.Marshal()), Namespace: namespace, HashAlgorithm: defaultHashAlgorithm, Signature: string(ssh.Marshal(s)), } copy(sig.MagicHeader[:], magicHeader) enc := pem.EncodeToMemory(&pem.Block{ Type: pemType, Bytes: ssh.Marshal(sig), }) return enc } // Decode parses a PEM armored signature block. func Decode(b []byte) (*Signature, error) { pemBlock, _ := pem.Decode(b) if pemBlock == nil { return nil, errors.New("unable to decode pem file") } if pemBlock.Type != pemType { return nil, fmt.Errorf("wrong pem block type: %s. Expected SSH-SIGNATURE", pemBlock.Type) } // Now we unmarshal it into the Signature block sig := wrappedSig{} if err := ssh.Unmarshal(pemBlock.Bytes, &sig); err != nil { return nil, err } if sig.Version != 1 { return nil, fmt.Errorf("unsupported signature version: %d", sig.Version) } if string(sig.MagicHeader[:]) != magicHeader { return nil, fmt.Errorf("invalid magic header: %s", sig.MagicHeader[:]) } if sig.Namespace != "file" { return nil, fmt.Errorf("invalid signature namespace: %s", sig.Namespace) } if _, ok := supportedHashAlgorithms[sig.HashAlgorithm]; !ok { return nil, fmt.Errorf("unsupported hash algorithm: %s", sig.HashAlgorithm) } // Now we can unpack the Signature and PublicKey blocks sshSig := ssh.Signature{} if err := ssh.Unmarshal([]byte(sig.Signature), &sshSig); err != nil { return nil, err } pk, err := ssh.ParsePublicKey([]byte(sig.PublicKey)) if err != nil { return nil, err } return &Signature{ signature: &sshSig, pk: pk, hashAlg: sig.HashAlgorithm, }, nil } sigstore-1.8.6/pkg/signature/ssh/doc.go000066400000000000000000000012551463713551000200500ustar00rootroot00000000000000// // 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 ssh contains types and utilities related to SSH signatures. package ssh sigstore-1.8.6/pkg/signature/ssh/sign.go000066400000000000000000000064501463713551000202450ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ssh import ( "crypto" "crypto/rand" "crypto/sha256" "crypto/sha512" "fmt" "hash" "io" "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/crypto/ssh" ) // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L81 type messageWrapper struct { Namespace string Reserved string HashAlgorithm string Hash string } // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L34 type wrappedSig struct { MagicHeader [6]byte Version uint32 PublicKey string Namespace string Reserved string HashAlgorithm string Signature string } const ( magicHeader = "SSHSIG" defaultHashAlgorithm = "sha512" ) var supportedHashAlgorithms = map[string]func() hash.Hash{ "sha256": sha256.New, "sha512": sha512.New, } func sign(s ssh.AlgorithmSigner, m io.Reader) (*ssh.Signature, error) { hf := sha512.New() if _, err := io.Copy(hf, m); err != nil { return nil, err } mh := hf.Sum(nil) sp := messageWrapper{ Namespace: "file", HashAlgorithm: defaultHashAlgorithm, Hash: string(mh), } dataMessageWrapper := ssh.Marshal(sp) dataMessageWrapper = append([]byte(magicHeader), dataMessageWrapper...) // ssh-rsa is not supported for RSA keys: // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig#L71 // We can use the default value of "" for other key types though. algo := "" if s.PublicKey().Type() == ssh.KeyAlgoRSA { algo = ssh.KeyAlgoRSASHA512 } sig, err := s.SignWithAlgorithm(rand.Reader, dataMessageWrapper, algo) if err != nil { return nil, err } return sig, nil } // Signer implements signature.Signer for SSH keys. type Signer struct { signer ssh.AlgorithmSigner } // PublicKey returns the public key for a Signer. func (s *Signer) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { return s.signer.PublicKey(), nil } // SignMessage signs the supplied message. func (s *Signer) SignMessage(message io.Reader, _ ...signature.SignOption) ([]byte, error) { b, err := io.ReadAll(message) if err != nil { return nil, err } sig, err := s.signer.Sign(rand.Reader, b) if err != nil { return nil, err } return Armor(sig, s.signer.PublicKey()), nil } var _ signature.Signer = (*Signer)(nil) // Sign signs the supplied message with the private key. func Sign(sshPrivateKey string, data io.Reader) ([]byte, error) { s, err := ssh.ParsePrivateKey([]byte(sshPrivateKey)) if err != nil { return nil, err } as, ok := s.(ssh.AlgorithmSigner) if !ok { return nil, fmt.Errorf("private key %T is not a ssh.AlgorithmSigner", s) } sig, err := sign(as, data) if err != nil { return nil, err } armored := Armor(sig, s.PublicKey()) return armored, nil } sigstore-1.8.6/pkg/signature/ssh/sign_test.go000066400000000000000000000327441463713551000213110ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ssh import ( "bytes" "os" "os/exec" "path/filepath" "strings" "testing" "golang.org/x/crypto/ssh" ) var ( // Generated with "ssh-keygen -C test@rekor.dev -f id_rsa" sshPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn NhAAAAAwEAAQAAAYEA16H5ImoRO7mr41r8Z8JFBdu6jIM+6XU8M0r9F81RuhLYqzr9zw1n LeGCqFxPXNBKm8ZyH2BCsBHsbXbwe85IMHM3SUh8X/9fI0Lpi5/xbqAproFUpNR+UJYv6s 8AaWk5zpN1rmpBrqGFJfGQKJCioDiiwNGmSdVkUNmQmYIANxJMDWYmNe8vUOh6nYEHB+lz fGgDAAzVSXTACW994UkSY47AD05swU4rIT/JWA6BkUrEhO//F0QQhFeROCPJiPRhJXGcFf 9SicffJqR/ELzM1zNYnRXMD0bbdTUwDrIcIFFNBbtcfJVOUUCGumSlt+qjUC7y8cvwbHAu wf5nS6baA7P6LfTYplF2XIAkdWtkN6O1ouoyIHICXMlddDW2vNaJeEXTeKjx51WSM7qPnQ ZKsBtwjLQeEY/OPkIvu88lNNYSD63qMUA12msohjwVFCIgJVvYLIrkViczZ7t3L7lgy1X0 CJI4e1roOfM/r9jTieyDHchEYpZYcw3L1R2qtePlAAAFiHdJQKl3SUCpAAAAB3NzaC1yc2 EAAAGBANeh+SJqETu5q+Na/GfCRQXbuoyDPul1PDNK/RfNUboS2Ks6/c8NZy3hgqhcT1zQ SpvGch9gQrAR7G128HvOSDBzN0lIfF//XyNC6Yuf8W6gKa6BVKTUflCWL+rPAGlpOc6Tda 5qQa6hhSXxkCiQoqA4osDRpknVZFDZkJmCADcSTA1mJjXvL1Doep2BBwfpc3xoAwAM1Ul0 wAlvfeFJEmOOwA9ObMFOKyE/yVgOgZFKxITv/xdEEIRXkTgjyYj0YSVxnBX/UonH3yakfx C8zNczWJ0VzA9G23U1MA6yHCBRTQW7XHyVTlFAhrpkpbfqo1Au8vHL8GxwLsH+Z0um2gOz +i302KZRdlyAJHVrZDejtaLqMiByAlzJXXQ1trzWiXhF03io8edVkjO6j50GSrAbcIy0Hh GPzj5CL7vPJTTWEg+t6jFANdprKIY8FRQiICVb2CyK5FYnM2e7dy+5YMtV9AiSOHta6Dnz P6/Y04nsgx3IRGKWWHMNy9UdqrXj5QAAAAMBAAEAAAGAJyaOcFQnuttUPRxY9ZHNLGofrc Fqm8KgYoO7/iVWMF2Zn0U/rec2E5t9OIpCEozy7uOR9uZoVUV70sgkk6X5b2qL4C9b/aYF JQbSFnq8wCQuTTPIJYE7SfBq1Mwuu/TR/RLC7B74u/cxkJkSXnscO9Dso+ussH0hEJjf6y 8yUM1up4Qjbel2gs8i7BPwLdySDkVoPgsWcpbTAyOODGhTAWZ6soy/rD1AEXJeYTGJDtMv aR+WBihig1TO1g2RWt9bqqiG7PIlljd3ZsjSSU5y3t6ZN/8j5keKD032EtxbZB0WFD3Ar4 FbFwlW+urb2MQ0JyNKOio3nhdjolXYkJa+C6LXdaaml/8BhMR1eLoMe8nS45w76o8mdJWX wsirB8tvjCLY0QBXgGv/1DTsKu/wEFCW2/Y0e50gF7pHAlYFNmKDcgI9OyORRYhFbV4D82 fI8JLQ42ZJkS/0t6xQma8WC88pbHGEuVSB6CE/p25fyYRX+UPTQ79tWFvLV4kNQAaBAAAA wEvyd6H8ePyBXImg8JzGxthufB0eXSfZBrabjf6e6bR2ivpJsHmB64gbMkV6MFV7EWYX1B wYPQxf4gA2Ez7aJvDtfE7uV6pa0WJS3hW1+be8DHEftmLSbTy/TEvDujNb2gqoi7uWQXWJ yYWZlYO65r1a6HucryQ8+78fTuTRbZALO43vNGz0oXH1hPSddkcbNAhZTsD0rQKNwqVTe5 wl+6Cduy/CQwjHLYrY73MyWy1Vh1LXhAdGMPnWZwGIu/dnkgAAAMEA9KuaoGnfnLQkrjeR tO4RCRS2quNRvm4L6i4vHgTDsYtoSlR1ujge7SGOOmIPS4XVjZN5zzCOA7+EDVnuz3WWmx hmkjpG1YxzmJGaWoYdeo3a6UgJtisfMp8eUKqjJT1mhsCliCWtaOQNRoQieDQmgwZzSX/v ZiGsOIKa6cR37eKvOJSjVrHsAUzdtYrmi8P2gvAUFWyzXobAtpzHcWrwWkOEIm04G0OGXb J46hfIX3f45E5EKXvFzexGgVOD2I7hAAAAwQDhniYAizfW9YfG7UJWekkl42xMP7Cb8b0W SindSIuE8bFTukV1yxbmNZp/f0pKvn/DWc2n0I0bwSGZpy8BCY46RKKB2DYQavY/tGcC1N AynKuvbtWs11A0mTXmq3WwHVXQDozMwJ2nnHpm0UHspPuHqkYpurlP+xoFsocaQ9QwITyp lL4qHtXBEzaT8okkcGZBHdSx3gk4TzCsEDOP7ZZPLq42lpKMK10zFPTMd0maXtJDYKU/b4 gAATvvPoylyYUAAAAOdGVzdEByZWtvci5kZXYBAgMEBQ== -----END OPENSSH PRIVATE KEY----- ` sshPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U= test@rekor.dev ` // Generated with "ssh-keygen -C other-test@rekor.dev -f id_rsa" otherSSHPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn NhAAAAAwEAAQAAAYEAw/WCSWC9TEvCQOwO+T68EvNa3OSIv1Y0+sT8uSvyjPyEO0+p0t8C g/zy67vOxiQpU5jN6MItjXAjMmeCm8GKMt6gk+cDoaAev/ZfjuzSL7RayExpmhBleh2X3G KLkkXF9ABFNchlTqSLOZiEjDoNpbFv16KT1sE6CqW8DjxXQkQk9JK65hLH+BxeWMNCEJVa Cma4X04aJmC7zJAi5yGeeT0SKVqMohavF90O6XiYFCQHuwXPPyHfocqgudmXnozz+6D6ax JKZMwQsNp3WKumOjlzWnxBCCB1l2jN6Rag8aJ2277iMFXRwjTL/8jaEsW4KkysDf0GjV2/ iqbr0q5b0arDYbv7CrGBR+uH0wGz/Zog1x5iZANObhZULpDrLVJidEMc27HXBb7PMsNDy7 BGYRB1yc0d0y83p8mUqvOlWSArxn1WnAZO04pAgTrclrhEh4ZXOkn2Sn82eu3DpQ8inkol Y4IfnhIfbOIeemoUNq1tOUquhow9GLRM6INieHLBAAAFkPPnA1jz5wNYAAAAB3NzaC1yc2 EAAAGBAMP1gklgvUxLwkDsDvk+vBLzWtzkiL9WNPrE/Lkr8oz8hDtPqdLfAoP88uu7zsYk KVOYzejCLY1wIzJngpvBijLeoJPnA6GgHr/2X47s0i+0WshMaZoQZXodl9xii5JFxfQART XIZU6kizmYhIw6DaWxb9eik9bBOgqlvA48V0JEJPSSuuYSx/gcXljDQhCVWgpmuF9OGiZg u8yQIuchnnk9EilajKIWrxfdDul4mBQkB7sFzz8h36HKoLnZl56M8/ug+msSSmTMELDad1 irpjo5c1p8QQggdZdozekWoPGidtu+4jBV0cI0y//I2hLFuCpMrA39Bo1dv4qm69KuW9Gq w2G7+wqxgUfrh9MBs/2aINceYmQDTm4WVC6Q6y1SYnRDHNux1wW+zzLDQ8uwRmEQdcnNHd MvN6fJlKrzpVkgK8Z9VpwGTtOKQIE63Ja4RIeGVzpJ9kp/Nnrtw6UPIp5KJWOCH54SH2zi HnpqFDatbTlKroaMPRi0TOiDYnhywQAAAAMBAAEAAAGAYycx4oEhp55Zz1HijblxnsEmQ8 kbbH1pV04fdm7HTxFis0Qu8PVIp5JxNFiWWunnQ1Z5MgI23G9WT+XST4+RpwXBCLWGv9xu UsGOPpqUC/FdUiZf9MXBIxYgRjJS3xORA1KzsnAQ2sclb2I+B1pEl4d9yQWJesvQ25xa2H Utzej/LgWkrk/ogSGRl6ZNImj/421wc0DouGyP+gUgtATt0/jT3LrlmAqUVCXVqssLYH2O r9JTuGUibBJEW2W/c0lsM0jaHa5bGAdL3nhDuF1Q6KFB87mZoNw8c2znYoTzQ3FyWtIEZI V/9oWrkS7V6242SKSR9tJoEzK0jtrKC/FZwBiI4hPcwoqY6fZbT1701i/n50xWEfEUOLVm d6VqNKyAbIaZIPN0qfZuD+xdrHuM3V6k/rgFxGl4XTrp/N4AsruiQs0nRQKNTw3fHE0zPq UTxSeMvjywRCepxhBFCNh8NHydapclHtEPEGdTVHohL3krJehstPO/IuRyKLfSVtL1AAAA wQCmGA8k+uW6mway9J3jp8mlMhhp3DCX6DAcvalbA/S5OcqMyiTM3c/HD5OJ6OYFDldcqu MPEgLRL2HfxL29LsbQSzjyOIrfp5PLJlo70P5lXS8u2QPbo4/KQJmQmsIX18LDyU2zRtNA C2WfBiHSZV+guLhmHms9S5gQYKt2T5OnY/W0tmnInx9lmFCMC+XKS1iSQ2o433IrtCPQJp IXZd59OQpO9QjJABgJIDtXxFIXt45qpXduDPJuggrhg81stOwAAADBAPX73u/CY+QUPts+ LV185Z4mZ2y+qu2ZMCAU3BnpHktGZZ1vFN1Xq9o8KdnuPZ+QJRdO8eKMWpySqrIdIbTYLm 9nXmVH0uNECIEAvdU+wgKeR+BSHxCRVuTF4YSygmNadgH/z+oRWLgOblGo2ywFBoXsIAKQ paNu1MFGRUmhz67+dcpkkBUDRU9loAgBKexMo8D9vkR0YiHLOUjCrtmEZRNm0YRZt0gQhD ZSD1fOH0fZDcCVNpGP2zqAKos4EGLnkwAAAMEAy/AuLtPKA2u9oCA8e18ZnuQRAi27FBVU rU2D7bMg1eS0IakG8v0gE9K6WdYzyArY1RoKB3ZklK5VmJ1cOcWc2x3Ejc5jcJgc8cC6lZ wwjpE8HfWL1kIIYgPdcexqFc+l6MdgH6QMKU3nLg1LsM4v5FEldtk/2dmnw620xnFfstpF VxSZNdKrYfM/v9o6sRaDRqSfH1dG8BvkUxPznTAF+JDxBENcKXYECcq9f6dcl1w5IEnNTD Wry/EKQvgvOUjbAAAAFG90aGVyLXRlc3RAcmVrb3IuZGV2AQIDBAUG -----END OPENSSH PRIVATE KEY----- ` otherSSHPublicKey = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDD9YJJYL1MS8JA7A75PrwS81rc5Ii/VjT6xPy5K/KM/IQ7T6nS3wKD/PLru87GJClTmM3owi2NcCMyZ4KbwYoy3qCT5wOhoB6/9l+O7NIvtFrITGmaEGV6HZfcYouSRcX0AEU1yGVOpIs5mISMOg2lsW/XopPWwToKpbwOPFdCRCT0krrmEsf4HF5Yw0IQlVoKZrhfThomYLvMkCLnIZ55PRIpWoyiFq8X3Q7peJgUJAe7Bc8/Id+hyqC52ZeejPP7oPprEkpkzBCw2ndYq6Y6OXNafEEIIHWXaM3pFqDxonbbvuIwVdHCNMv/yNoSxbgqTKwN/QaNXb+KpuvSrlvRqsNhu/sKsYFH64fTAbP9miDXHmJkA05uFlQukOstUmJ0QxzbsdcFvs8yw0PLsEZhEHXJzR3TLzenyZSq86VZICvGfVacBk7TikCBOtyWuESHhlc6SfZKfzZ67cOlDyKeSiVjgh+eEh9s4h56ahQ2rW05Sq6GjD0YtEzog2J4csE= other-test@rekor.dev ` // Generated with ssh-keygen -C test@rekor.dev -t ed25519 -f id_ed25519 ed25519PrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACBB45zRHxPPFtabwS3Vd6Lb9vMe+tIHZj2qN5VQ+bgLfQAAAJgyRa3cMkWt 3AAAAAtzc2gtZWQyNTUxOQAAACBB45zRHxPPFtabwS3Vd6Lb9vMe+tIHZj2qN5VQ+bgLfQ AAAED7y4N/DsVnRQiBZNxEWdsJ9RmbranvtQ3X9jnb6gFed0HjnNEfE88W1pvBLdV3otv2 8x760gdmPao3lVD5uAt9AAAADnRlc3RAcmVrb3IuZGV2AQIDBAUGBw== -----END OPENSSH PRIVATE KEY----- ` ed25519PublicKey = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEHjnNEfE88W1pvBLdV3otv28x760gdmPao3lVD5uAt9 test@rekor.dev ` ) func TestFromOpenSSH(t *testing.T) { otherPub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(otherSSHPublicKey)) if err != nil { t.Fatal(err) } // pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshPublicKey)) // if err != nil { // t.Fatal(err) // } for _, tt := range []struct { name string pub string priv string }{ { name: "rsa", pub: sshPublicKey, priv: sshPrivateKey, }, { name: "ed25519", pub: ed25519PublicKey, priv: ed25519PrivateKey, }, } { if _, err := exec.LookPath("ssh-keygen"); err != nil { t.Skip("skip TestFromOpenSSH: missing ssh-keygen in PATH") } t.Run(tt.name, func(t *testing.T) { tt := tt // Test that a signature from the cli can validate here. td := t.TempDir() data := []byte("hello, ssh world") dataPath := write(t, data, td, "data") privPath := write(t, []byte(tt.priv), td, "id") write(t, []byte(tt.pub), td, "id.pub") sigPath := dataPath + ".sig" run(t, nil, "ssh-keygen", "-Y", "sign", "-n", "file", "-f", privPath, dataPath) sigBytes, err := os.ReadFile(sigPath) if err != nil { t.Fatal(err) } pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(tt.pub)) if err != nil { t.Fatal(err) } if err := Verify(bytes.NewReader(data), sigBytes, pub); err != nil { t.Error(err) } // It should not verify if we check against another public key if err := Verify(bytes.NewReader(data), sigBytes, otherPub); err == nil { t.Error("expected error with incorrect key") } // It should not verify if the data is tampered if err := Verify(strings.NewReader("bad data"), sigBytes, pub); err == nil { t.Error("expected error with incorrect data") } }) } } func TestToOpenSSH(t *testing.T) { for _, tt := range []struct { name string pub string priv string }{ { name: "rsa", pub: sshPublicKey, priv: sshPrivateKey, }, { name: "ed25519", pub: ed25519PublicKey, priv: ed25519PrivateKey, }, } { if _, err := exec.LookPath("ssh-keygen"); err != nil { t.Skip("skip TestToOpenSSH: missing ssh-keygen in PATH") } t.Run(tt.name, func(t *testing.T) { tt := tt // Test that a signature from here can validate in the CLI. td := t.TempDir() data := []byte("hello, ssh world") write(t, data, td, "data") armored, err := Sign(tt.priv, bytes.NewReader(data)) if err != nil { t.Fatal(err) } sigPath := write(t, armored, td, "oursig") // Create an allowed_signers file with two keys to check against. allowedSigner := "test@rekor.dev " + tt.pub + "\n" allowedSigner += "othertest@rekor.dev " + otherSSHPublicKey + "\n" allowedSigners := write(t, []byte(allowedSigner), td, "allowed_signer") // We use the correct principal here so it should work. run(t, data, "ssh-keygen", "-Y", "verify", "-f", allowedSigners, "-I", "test@rekor.dev", "-n", "file", "-s", sigPath) // Just to be sure, check against the other public key as well. runErr(t, data, "ssh-keygen", "-Y", "verify", "-f", allowedSigners, "-I", "othertest@rekor.dev", "-n", "file", "-s", sigPath) // It should error if we run it against other data data = []byte("other data!") runErr(t, data, "ssh-keygen", "-Y", "check-novalidate", "-n", "file", "-s", sigPath) }) } } func TestRoundTrip(t *testing.T) { data := []byte("my good data to be signed!") // Create one extra signature for all the tests. otherSig, err := Sign(otherSSHPrivateKey, bytes.NewReader(data)) if err != nil { t.Fatal(err) } otherPub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(otherSSHPublicKey)) if err != nil { t.Fatal(err) } for _, tt := range []struct { name string pub string priv string }{ { name: "rsa", pub: sshPublicKey, priv: sshPrivateKey, }, { name: "ed25519", pub: ed25519PublicKey, priv: ed25519PrivateKey, }, } { t.Run(tt.name, func(t *testing.T) { tt := tt sig, err := Sign(tt.priv, bytes.NewReader(data)) if err != nil { t.Fatal(err) } pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(tt.pub)) if err != nil { t.Fatal(err) } // Check the signature against that data and public key if err := Verify(bytes.NewReader(data), sig, pub); err != nil { t.Error(err) } // Now check it against invalid data. if err := Verify(strings.NewReader("invalid data!"), sig, pub); err == nil { t.Error("expected error!") } // Now check it against the wrong key. if err := Verify(bytes.NewReader(data), sig, otherPub); err == nil { t.Error("expected error!") } // Now check it against an invalid signature data. if err := Verify(bytes.NewReader(data), []byte("invalid signature!"), pub); err == nil { t.Error("expected error!") } // Once more, use the wrong signature and check it against the original (wrong public key) if err := Verify(bytes.NewReader(data), otherSig, pub); err == nil { t.Error("expected error!") } // It should work against the correct public key. if err := Verify(bytes.NewReader(data), otherSig, otherPub); err != nil { t.Error(err) } }) } } func write(t *testing.T, d []byte, fp ...string) string { p := filepath.Join(fp...) if err := os.WriteFile(p, d, 0o600); err != nil { t.Fatal(err) } return p } func run(t *testing.T, stdin []byte, args ...string) { t.Helper() /* #nosec */ cmd := exec.Command(args[0], args[1:]...) cmd.Stdin = bytes.NewReader(stdin) out, err := cmd.CombinedOutput() t.Logf("cmd %v: %s", cmd, string(out)) if err != nil { t.Fatal(err) } } func runErr(t *testing.T, stdin []byte, args ...string) { t.Helper() /* #nosec */ cmd := exec.Command(args[0], args[1:]...) cmd.Stdin = bytes.NewReader(stdin) out, err := cmd.CombinedOutput() t.Logf("cmd %v: %s", cmd, string(out)) if err == nil { t.Fatal("expected error") } } sigstore-1.8.6/pkg/signature/ssh/verify.go000066400000000000000000000033411463713551000206050ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ssh import ( "io" "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/crypto/ssh" ) // Verify verifies the supplied signature against the specified key. func Verify(message io.Reader, armoredSignature []byte, pubKey ssh.PublicKey) error { decodedSignature, err := Decode(armoredSignature) if err != nil { return err } // Hash the message so we can verify it against the signature. h := supportedHashAlgorithms[decodedSignature.hashAlg]() if _, err := io.Copy(h, message); err != nil { return err } hm := h.Sum(nil) toVerify := messageWrapper{ Namespace: "file", HashAlgorithm: decodedSignature.hashAlg, Hash: string(hm), } signedMessage := ssh.Marshal(toVerify) signedMessage = append([]byte(magicHeader), signedMessage...) return pubKey.Verify(signedMessage, decodedSignature.signature) } var _ signature.Verifier = (*Signer)(nil) // VerifySignature verifies a suppled signature. func (s *Signer) VerifySignature(signature, message io.Reader, _ ...signature.VerifyOption) error { b, err := io.ReadAll(signature) if err != nil { return err } return Verify(message, b, s.signer.PublicKey()) } sigstore-1.8.6/pkg/signature/sv_test.go000066400000000000000000000142351463713551000201770ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "bytes" "context" "crypto" crand "crypto/rand" "crypto/rsa" "crypto/x509" "strings" "testing" "github.com/sigstore/sigstore/pkg/signature/options" ) func testingSigner(t *testing.T, s Signer, alg string, hashFunc crypto.Hash, message []byte) { // nolint: unparam t.Helper() isPreHashed := alg != "ed25519" var digest []byte if isPreHashed { hasher := hashFunc.New() _, _ = hasher.Write(message) digest = hasher.Sum(nil) } if _, err := s.SignMessage(nil); err == nil { t.Error("didn't error out for nil message") } // if nil is passed for rand, default (crypto/rand.Reader) should be used if _, err := s.SignMessage(bytes.NewReader(message), options.WithRand(nil)); err != nil && isPreHashed { t.Errorf("unexpected error passing nil Rand: %v", err) } if _, err := s.SignMessage(bytes.NewReader(message), options.WithRand(crand.Reader)); err != nil { t.Errorf("unexpected error passing valid Rand: %v", err) } if _, err := s.SignMessage(bytes.NewReader(message), options.WithRand(crand.Reader), options.WithDigest(digest)); err != nil { t.Errorf("unexpected error passing valid Rand and Digest: %v", err) } if _, err := s.SignMessage(bytes.NewReader(message), options.WithRand(crand.Reader), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc)); err != nil { t.Errorf("unexpected error passing valid Rand and Digest and Opts: %v", err) } if _, err := s.SignMessage(bytes.NewReader(message), options.WithDigest(digest)); err != nil { t.Errorf("unexpected error passing valid Digest: %v", err) } if _, err := s.SignMessage(bytes.NewReader(message), options.WithDigest(digest), options.WithCryptoSignerOpts(crypto.Hash(0))); err == nil && isPreHashed { t.Error("no error passing invalid opts") } if _, err := s.SignMessage(bytes.NewReader(message), options.WithDigest(digest), options.WithCryptoSignerOpts(crypto.SHA384)); err == nil && isPreHashed { t.Error("no error passing mismatched Digest and opts") } if _, err := s.SignMessage(bytes.NewReader(message), options.WithCryptoSignerOpts(nil)); err != nil && alg != "ed25519ph" { t.Errorf("unexpected error passing nil options: %v", err) } cs, ok := s.(crypto.Signer) if !ok { t.Fatalf("expected crypto.Signer") } if _, err := cs.Sign(nil, nil, nil); err == nil { t.Errorf("no error passing nil for all args to Sign: %v", err) } if !isPreHashed { if _, err := cs.Sign(nil, message, crypto.Hash(0)); err != nil { t.Errorf("unexpected error passing nil Rand, message and crypto.Hash(0) to Sign: %v", err) } } if _, err := cs.Sign(nil, digest, nil); err != nil && isPreHashed { t.Errorf("unexpected error passing nil for Rand and Opts to Sign: %v", err) } if _, err := cs.Sign(nil, digest, &rsa.PSSOptions{Hash: hashFunc}); err != nil && isPreHashed { t.Errorf("unexpected error passing nil for Rand and valid Opts to Sign: %v", err) } if _, err := cs.Sign(crand.Reader, digest, &rsa.PSSOptions{Hash: hashFunc}); err != nil && isPreHashed { t.Errorf("unexpected error passing valid Rand and valid Opts to Sign: %v", err) } if _, err := cs.Sign(crand.Reader, digest, nil); err != nil && isPreHashed { t.Errorf("unexpected error passing valid Rand and nil Opts to Sign: %v", err) } if k := cs.Public(); k == nil { t.Error("Public() returned empty key") } if k, err := s.PublicKey(); k == nil || err != nil { t.Errorf("PublicKey() returned empty key or err: %v", err) } if k, err := s.PublicKey(options.WithContext(context.Background())); k == nil || err != nil { t.Errorf("PublicKey(context.Background()) returned empty key or err: %v", err) } } func assertPublicKeyIsx509Marshalable(t *testing.T, pub crypto.PublicKey) { t.Helper() if _, err := x509.MarshalPKIXPublicKey(pub); err != nil { t.Errorf("x509.MarshalPKIXPublicKey(%T) returned error: %v", pub, err) } } func testingVerifier(t *testing.T, v Verifier, alg string, hashFunc crypto.Hash, signature, message []byte) { // nolint: unparam t.Helper() isPreHashed := alg != "ed25519" var digest []byte if isPreHashed { hasher := hashFunc.New() _, _ = hasher.Write(message) digest = hasher.Sum(nil) } if err := v.VerifySignature(bytes.NewReader(signature), nil); err == nil { t.Error("no error when passing nil as message") } if err := v.VerifySignature(nil, bytes.NewReader(message)); err == nil { t.Error("no error when passing nil as signature") } if err := v.VerifySignature(strings.NewReader("not the sig"), bytes.NewReader(message)); err == nil { t.Error("no error when passing incorrect signature") } if err := v.VerifySignature(bytes.NewReader(signature), bytes.NewReader(message)); err != nil { t.Errorf("unexpected error when verifying valid bytes.NewReader(message): %v", err) } if err := v.VerifySignature(bytes.NewReader(signature), bytes.NewReader(message), options.WithDigest(digest)); err != nil { t.Errorf("unexpected error when using valid bytes.NewReader(message) with digest: %v", err) } if err := v.VerifySignature(bytes.NewReader(signature), bytes.NewReader(message), options.WithDigest(digest), options.WithCryptoSignerOpts(hashFunc)); err != nil { t.Errorf("unexpected error when using valid bytes.NewReader(message) with digest & opts: %v", err) } var alternativeHash crypto.Hash if hashFunc == crypto.SHA512 { alternativeHash = crypto.SHA256 } else { alternativeHash = crypto.SHA512 } if err := v.VerifySignature(bytes.NewReader(signature), bytes.NewReader(message), options.WithDigest(digest), options.WithCryptoSignerOpts(alternativeHash)); err == nil && isPreHashed { t.Error("no error when using mismatched hashFunc with digest & opts") } } sigstore-1.8.6/pkg/signature/util.go000066400000000000000000000040151463713551000174600ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "bytes" "encoding/json" "fmt" "github.com/google/go-containerregistry/pkg/name" sigpayload "github.com/sigstore/sigstore/pkg/signature/payload" ) // SignImage signs a container manifest using the specified signer object func SignImage(signer SignerVerifier, image name.Digest, optionalAnnotations map[string]interface{}) (payload, signature []byte, err error) { imgPayload := sigpayload.Cosign{ Image: image, Annotations: optionalAnnotations, } payload, err = json.Marshal(imgPayload) if err != nil { return nil, nil, fmt.Errorf("failed to marshal payload to JSON: %w", err) } signature, err = signer.SignMessage(bytes.NewReader(payload)) if err != nil { return nil, nil, fmt.Errorf("failed to sign payload: %w", err) } return payload, signature, nil } // VerifyImageSignature verifies a signature over a container manifest func VerifyImageSignature(signer SignerVerifier, payload, signature []byte) (image name.Digest, annotations map[string]interface{}, err error) { if err := signer.VerifySignature(bytes.NewReader(signature), bytes.NewReader(payload)); err != nil { return name.Digest{}, nil, fmt.Errorf("signature verification failed: %w", err) } var imgPayload sigpayload.Cosign if err := json.Unmarshal(payload, &imgPayload); err != nil { return name.Digest{}, nil, fmt.Errorf("could not deserialize image payload: %w", err) } return imgPayload.Image, imgPayload.Annotations, nil } sigstore-1.8.6/pkg/signature/util_test.go000066400000000000000000000047651463713551000205330ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "testing" "github.com/go-test/deep" "github.com/google/go-containerregistry/pkg/name" ) const validDigest = "sha256:d34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33fd34db33f" func mustParseDigest(t *testing.T, digestStr string) name.Digest { t.Helper() digest, err := name.NewDigest(digestStr) if err != nil { t.Fatalf("could not parse digest %q: %v", digestStr, err) } return digest } func TestProviderRoundtrip(t *testing.T) { ecdsaSV, _, err := NewDefaultECDSASignerVerifier() if err != nil { t.Fatalf("Could not generate ecdsa SignerVerifier for test: %v", err) } rsaSV, _, err := NewDefaultRSAPSSSignerVerifier() if err != nil { t.Fatalf("Could not generate rsa SignerVerifier for test: %v", err) } testCases := []struct { desc string sv SignerVerifier digest name.Digest claims map[string]interface{} }{ { desc: "ECDSA", sv: ecdsaSV, digest: mustParseDigest(t, "example.com/ecdsa@"+validDigest), claims: map[string]interface{}{ "creator": "ECDSA", "optional": "extras", }, }, { desc: "RSA", sv: rsaSV, digest: mustParseDigest(t, "example.com/rsa@"+validDigest), claims: map[string]interface{}{ "creator": "RSA", "Floaty McFloatface": 6.022e23, }, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { payload, sig, err := SignImage(tc.sv, tc.digest, tc.claims) if err != nil { t.Fatalf("SignImage returned error: %v", err) } rtDigest, rtClaims, err := VerifyImageSignature(tc.sv, payload, sig) if err != nil { t.Fatalf("VerifyImageSignature returned error: %v", err) } if tc.digest.Name() != rtDigest.Name() { t.Errorf("got digest %q, wanted %q", rtDigest.Name(), tc.digest.Name()) } if diff := deep.Equal(tc.claims, rtClaims); diff != nil { t.Errorf("claims were altered during the roundtrip: %v", diff) } }) } } sigstore-1.8.6/pkg/signature/verifier.go000066400000000000000000000110021463713551000203100ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package signature import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "errors" "io" "os" "path/filepath" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/options" ) // Verifier verifies the digital signature using a specified public key type Verifier interface { PublicKeyProvider VerifySignature(signature, message io.Reader, opts ...VerifyOption) error } // LoadVerifier returns a signature.Verifier based on the algorithm of the public key // provided that will use the hash function specified when computing digests. // // If publicKey is an RSA key, a RSAPKCS1v15Verifier will be returned. If a // RSAPSSVerifier is desired instead, use the LoadRSAPSSVerifier() method directly. func LoadVerifier(publicKey crypto.PublicKey, hashFunc crypto.Hash) (Verifier, error) { return LoadVerifierWithOpts(publicKey, options.WithHash(hashFunc)) } // LoadVerifierWithOpts returns a signature.Verifier based on the algorithm of the public key // provided that will use the hash function specified when computing digests. func LoadVerifierWithOpts(publicKey crypto.PublicKey, opts ...LoadOption) (Verifier, error) { var rsaPSSOptions *rsa.PSSOptions var useED25519ph bool hashFunc := crypto.SHA256 for _, o := range opts { o.ApplyED25519ph(&useED25519ph) o.ApplyHash(&hashFunc) o.ApplyRSAPSS(&rsaPSSOptions) } switch pk := publicKey.(type) { case *rsa.PublicKey: if rsaPSSOptions != nil { return LoadRSAPSSVerifier(pk, hashFunc, rsaPSSOptions) } return LoadRSAPKCS1v15Verifier(pk, hashFunc) case *ecdsa.PublicKey: return LoadECDSAVerifier(pk, hashFunc) case ed25519.PublicKey: if useED25519ph { return LoadED25519phVerifier(pk) } return LoadED25519Verifier(pk) } return nil, errors.New("unsupported public key type") } // LoadUnsafeVerifier returns a signature.Verifier based on the algorithm of the public key // provided that will use SHA1 when computing digests for RSA and ECDSA signatures. // // If publicKey is an RSA key, a RSAPKCS1v15Verifier will be returned. If a // RSAPSSVerifier is desired instead, use the LoadRSAPSSVerifier() method directly. func LoadUnsafeVerifier(publicKey crypto.PublicKey) (Verifier, error) { switch pk := publicKey.(type) { case *rsa.PublicKey: if pk == nil { return nil, errors.New("invalid RSA public key specified") } return &RSAPKCS1v15Verifier{ publicKey: pk, hashFunc: crypto.SHA1, }, nil case *ecdsa.PublicKey: if pk == nil { return nil, errors.New("invalid ECDSA public key specified") } return &ECDSAVerifier{ publicKey: pk, hashFunc: crypto.SHA1, }, nil case ed25519.PublicKey: return LoadED25519Verifier(pk) } return nil, errors.New("unsupported public key type") } // LoadVerifierFromPEMFile returns a signature.Verifier based on the contents of a // file located at path. The Verifier wil use the hash function specified when computing digests. // // If the publickey is an RSA key, a RSAPKCS1v15Verifier will be returned. If a // RSAPSSVerifier is desired instead, use the LoadRSAPSSVerifier() and cryptoutils.UnmarshalPEMToPublicKey() methods directly. func LoadVerifierFromPEMFile(path string, hashFunc crypto.Hash) (Verifier, error) { fileBytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } pubKey, err := cryptoutils.UnmarshalPEMToPublicKey(fileBytes) if err != nil { return nil, err } return LoadVerifier(pubKey, hashFunc) } // LoadVerifierFromPEMFileWithOpts returns a signature.Verifier based on the contents of a // file located at path. The Verifier wil use the hash function specified in the options when computing digests. func LoadVerifierFromPEMFileWithOpts(path string, opts ...LoadOption) (Verifier, error) { fileBytes, err := os.ReadFile(filepath.Clean(path)) if err != nil { return nil, err } pubKey, err := cryptoutils.UnmarshalPEMToPublicKey(fileBytes) if err != nil { return nil, err } return LoadVerifierWithOpts(pubKey, opts...) } sigstore-1.8.6/pkg/signature/verifier_test.go000066400000000000000000000027421463713551000213620ustar00rootroot00000000000000// 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 signature import ( "crypto" "crypto/rand" "crypto/rsa" "testing" ) func TestLoadUnsafeVerifier(t *testing.T) { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("unexpected error generating key: %v", err) } verifier, err := LoadUnsafeVerifier(key.Public()) if err != nil { t.Fatalf("unexpected error loading verifier: %v", err) } pubKey, _ := verifier.PublicKey() if !key.PublicKey.Equal(pubKey) { t.Fatalf("public keys were not equal") } } func TestLoadVerifier(t *testing.T) { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("unexpected error generating key: %v", err) } verifier, err := LoadVerifier(key.Public(), crypto.SHA256) if err != nil { t.Fatalf("unexpected error loading verifier: %v", err) } pubKey, _ := verifier.PublicKey() if !key.PublicKey.Equal(pubKey) { t.Fatalf("public keys were not equal") } } sigstore-1.8.6/pkg/tuf/000077500000000000000000000000001463713551000147515ustar00rootroot00000000000000sigstore-1.8.6/pkg/tuf/client.go000066400000000000000000000467471463713551000166000ustar00rootroot00000000000000// // 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 tuf import ( "bytes" "context" "embed" "encoding/json" "errors" "fmt" "io" "io/fs" "net/url" "os" "path" "path/filepath" "runtime" "strconv" "strings" "sync" "time" "github.com/theupdateframework/go-tuf/client" tuf_leveldbstore "github.com/theupdateframework/go-tuf/client/leveldbstore" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/util" ) const ( // DefaultRemoteRoot is the default remote TUF root location. DefaultRemoteRoot = "https://tuf-repo-cdn.sigstore.dev" // defaultRemoteGCSBucket is the name of the GCS bucket that holds sigstore's public good production TUF root defaultRemoteGCSBucket = "sigstore-tuf-root" // defaultRemoteRootNoCDN is the URL of the GCS HTTP endpoint for the DefaultRootGCSBucket content defaultRemoteRootNoCDN = "https://sigstore-tuf-root.storage.googleapis.com" // defaultRemoteRootNoCDNAlt is an alternate URL to the GCS HTTP endpoint for the DefaultRootGCSBucket content defaultRemoteRootNoCDNAlt = "https://storage.googleapis.com/sigstore-tuf-root" // TufRootEnv is the name of the environment variable that locates an alternate local TUF root location. TufRootEnv = "TUF_ROOT" // SigstoreNoCache is the name of the environment variable that, if set, configures this code to only store root data in memory. SigstoreNoCache = "SIGSTORE_NO_CACHE" ) var ( // singletonTUF holds a single instance of TUF that will get reused on // subsequent invocations of initializeTUF singletonTUF *TUF singletonTUFOnce = new(sync.Once) singletonTUFErr error // initMu locks concurrent calls to initializeTUF initMu sync.Mutex ) // getRemoteRoot is a var for testing. var getRemoteRoot = func() string { return DefaultRemoteRoot } type TUF struct { sync.Mutex client *client.Client targets targetImpl local client.LocalStore remote client.RemoteStore embedded fs.FS mirror string // location of mirror } // Mirror returns the mirror configured; note if the object was configured with a legacy reference // to the GCS HTTP endpoint for sigstore's public good trust root, this will return DefaultRemoteRoot // which is a CDN fronting that DefaultRemoteGCSBucket func (t *TUF) Mirror() string { switch t.mirror { case defaultRemoteGCSBucket, defaultRemoteRootNoCDN, defaultRemoteRootNoCDNAlt: return DefaultRemoteRoot default: return t.mirror } } // JSON output representing the configured root status type RootStatus struct { Local string `json:"local"` Remote string `json:"remote"` Metadata map[string]MetadataStatus `json:"metadata"` Targets []string `json:"targets"` } type MetadataStatus struct { Version int `json:"version"` Size int `json:"len"` Expiration string `json:"expiration"` Error string `json:"error"` } type TargetFile struct { Target []byte Status StatusKind } type customMetadata struct { Usage UsageKind `json:"usage"` Status StatusKind `json:"status"` URI string `json:"uri"` } type sigstoreCustomMetadata struct { Sigstore customMetadata `json:"sigstore"` } type signedMeta struct { Type string `json:"_type"` Expires time.Time `json:"expires"` Version int64 `json:"version"` } // RemoteCache contains information to cache on the location of the remote // repository. type remoteCache struct { Mirror string `json:"mirror"` } func resetForTests() { singletonTUFOnce = new(sync.Once) } func getExpiration(metadata []byte) (*time.Time, error) { s := &data.Signed{} if err := json.Unmarshal(metadata, s); err != nil { return nil, err } sm := &signedMeta{} if err := json.Unmarshal(s.Signed, sm); err != nil { return nil, err } return &sm.Expires, nil } func getVersion(metadata []byte) (int64, error) { s := &data.Signed{} if err := json.Unmarshal(metadata, s); err != nil { return 0, err } sm := &signedMeta{} if err := json.Unmarshal(s.Signed, sm); err != nil { return 0, err } return sm.Version, nil } var isExpiredTimestamp = func(metadata []byte) bool { expiration, err := getExpiration(metadata) if err != nil { return true } return time.Until(*expiration) <= 0 } func getMetadataStatus(b []byte) (*MetadataStatus, error) { expires, err := getExpiration(b) if err != nil { return nil, err } version, err := getVersion(b) if err != nil { return nil, err } return &MetadataStatus{ Size: len(b), Expiration: expires.Format(time.RFC822), Version: int(version), }, nil } func (t *TUF) getRootStatus() (*RootStatus, error) { local := rootCacheDir() if noCache() { local = "in-memory" } status := &RootStatus{ Local: local, Remote: t.Mirror(), Metadata: make(map[string]MetadataStatus), Targets: []string{}, } // Get targets targets, err := t.client.Targets() if err != nil { return nil, err } for t := range targets { status.Targets = append(status.Targets, t) } // Get metadata expiration trustedMeta, err := t.local.GetMeta() if err != nil { return nil, fmt.Errorf("getting trusted meta: %w", err) } for role, md := range trustedMeta { mdStatus, err := getMetadataStatus(md) if err != nil { status.Metadata[role] = MetadataStatus{Error: err.Error()} continue } status.Metadata[role] = *mdStatus } return status, nil } func getRoot(meta map[string]json.RawMessage, fallback fs.FS) (json.RawMessage, error) { if trustedRoot, ok := meta["root.json"]; ok { return trustedRoot, nil } // On first initialize, there will be no root in the TUF DB, so read from embedded. rd, ok := fallback.(fs.ReadFileFS) if !ok { return nil, errors.New("fs.ReadFileFS unimplemented for embedded repo") } trustedRoot, err := rd.ReadFile(path.Join("repository", "root.json")) if err != nil { return nil, err } return trustedRoot, nil } // GetRootStatus gets the current root status for info logging func GetRootStatus(ctx context.Context) (*RootStatus, error) { t, err := NewFromEnv(ctx) if err != nil { return nil, err } return t.getRootStatus() } // initializeTUF creates a TUF client using the following params: // * embed: indicates using the embedded metadata and in-memory file updates. // When this is false, this uses a filesystem cache. // * mirror: provides a reference to a remote GCS or HTTP mirror. // * root: provides an external initial root.json. When this is not provided, this // defaults to the embedded root.json. // * embedded: An embedded filesystem that provides a trusted root and pre-downloaded // targets in a targets/ subfolder. // * forceUpdate: indicates checking the remote for an update, even when the local // timestamp.json is up to date. func initializeTUF(mirror string, root []byte, embedded fs.FS, forceUpdate bool) (*TUF, error) { initMu.Lock() defer initMu.Unlock() // TODO: If a temporary error occurs for a long-running process, this singleton will // never retry singletonTUFOnce.Do(func() { t := &TUF{ mirror: mirror, embedded: embedded, } t.targets = newFileImpl() t.local, singletonTUFErr = newLocalStore() if singletonTUFErr != nil { return } t.remote, singletonTUFErr = remoteFromMirror(t.Mirror()) if singletonTUFErr != nil { return } t.client = client.NewClient(t.local, t.remote) trustedMeta, err := t.local.GetMeta() if err != nil { singletonTUFErr = fmt.Errorf("getting trusted meta: %w", err) return } // If the caller does not supply a root, then either use the root in the local store // or default to the embedded one. if root == nil { root, err = getRoot(trustedMeta, t.embedded) if err != nil { singletonTUFErr = fmt.Errorf("getting trusted root: %w", err) return } } if err := t.client.Init(root); err != nil { singletonTUFErr = fmt.Errorf("unable to initialize client, local cache may be corrupt: %w", err) return } singletonTUF = t }) if singletonTUFErr != nil { return nil, singletonTUFErr } trustedMeta, err := singletonTUF.local.GetMeta() if err != nil { return nil, fmt.Errorf("getting trusted meta: %w", err) } // We may already have an up-to-date local store! Check to see if it needs to be updated. trustedTimestamp, ok := trustedMeta["timestamp.json"] if ok && !isExpiredTimestamp(trustedTimestamp) && !forceUpdate { // We're golden so stash the TUF object for later use return singletonTUF, nil } // Update if local is not populated or out of date. if err := singletonTUF.updateMetadataAndDownloadTargets(); err != nil { return nil, fmt.Errorf("updating local metadata and targets: %w", err) } return singletonTUF, nil } // TODO: Remove ctx arg. func NewFromEnv(_ context.Context) (*TUF, error) { // Check for the current remote mirror. mirror := getRemoteRoot() b, err := os.ReadFile(cachedRemote(rootCacheDir())) if err == nil { remoteInfo := remoteCache{} if err := json.Unmarshal(b, &remoteInfo); err == nil { mirror = remoteInfo.Mirror } } // Initializes a new TUF object from the local cache or defaults. return initializeTUF(mirror, nil, getEmbedded(), false) } func Initialize(_ context.Context, mirror string, root []byte) error { // Initialize the client. Force an update with remote. tuf, err := initializeTUF(mirror, root, getEmbedded(), true) if err != nil { return err } // Store the remote for later if we are caching. if !noCache() { remoteInfo := &remoteCache{Mirror: tuf.Mirror()} b, err := json.Marshal(remoteInfo) if err != nil { return err } if err := os.WriteFile(cachedRemote(rootCacheDir()), b, 0o600); err != nil { return fmt.Errorf("storing remote: %w", err) } } return nil } // Checks if the testTarget matches the valid target file metadata. func isValidTarget(testTarget []byte, validMeta data.TargetFileMeta) (bool, error) { localMeta, err := util.GenerateTargetFileMeta( bytes.NewReader(testTarget), "sha256", "sha512") if err != nil { return false, err } if err := util.TargetFileMetaEqual(localMeta, validMeta); err != nil { return false, err } return true, nil } func (t *TUF) GetTarget(name string) ([]byte, error) { t.Lock() defer t.Unlock() // Get valid target metadata. Does a local verification. validMeta, err := t.client.Target(name) if err != nil { return nil, fmt.Errorf("error verifying local metadata; local cache may be corrupt: %w", err) } targetBytes, err := t.targets.Get(name) if err != nil { return nil, err } if valid, err := isValidTarget(targetBytes, validMeta); !valid { return nil, fmt.Errorf("cache contains invalid target; local cache may be corrupt: %w", err) } return targetBytes, nil } // Get target files by a custom usage metadata tag. If there are no files found, // use the fallback target names to fetch the targets by name. func (t *TUF) GetTargetsByMeta(usage UsageKind, fallbacks []string) ([]TargetFile, error) { t.Lock() targets, err := t.client.Targets() t.Unlock() if err != nil { return nil, fmt.Errorf("error getting targets: %w", err) } var matchedTargets []TargetFile for name, targetMeta := range targets { // Skip any targets that do not include custom metadata. if targetMeta.Custom == nil { continue } var scm sigstoreCustomMetadata err := json.Unmarshal(*targetMeta.Custom, &scm) if err != nil { fmt.Fprintf(os.Stderr, "**Warning** Custom metadata not configured properly for target %s, skipping target\n", name) continue } if scm.Sigstore.Usage == usage { target, err := t.GetTarget(name) if err != nil { return nil, fmt.Errorf("error getting target %s by usage: %w", name, err) } matchedTargets = append(matchedTargets, TargetFile{Target: target, Status: scm.Sigstore.Status}) } } if len(matchedTargets) == 0 { for _, fallback := range fallbacks { target, err := t.GetTarget(fallback) if err != nil { fmt.Fprintf(os.Stderr, "**Warning** Missing fallback target %s, skipping\n", fallback) continue } matchedTargets = append(matchedTargets, TargetFile{Target: target, Status: Active}) } } if len(matchedTargets) == 0 { return matchedTargets, fmt.Errorf("no matching targets by custom metadata, fallbacks not found: %s", strings.Join(fallbacks, ", ")) } return matchedTargets, nil } // updateClient() updates the TUF client and also caches new metadata, if needed. func (t *TUF) updateClient() (data.TargetFiles, error) { targets, err := t.client.Update() if err != nil { return nil, fmt.Errorf("error updating to TUF remote mirror: %w", err) } // Success! Cache new metadata, if needed. if noCache() { return targets, nil } // Sync the on-disk cache with the metadata from the in-memory store. tufDB := filepath.FromSlash(filepath.Join(rootCacheDir(), "tuf.db")) diskLocal, err := tuf_leveldbstore.FileLocalStore(tufDB) defer func() { if diskLocal != nil { diskLocal.Close() } }() if err != nil { return nil, fmt.Errorf("creating cached local store: %w", err) } if err := syncLocalMeta(t.local, diskLocal); err != nil { return nil, err } // Return updated targets. return targets, nil } func (t *TUF) updateMetadataAndDownloadTargets() error { // Download updated targets and cache new metadata and targets in ${TUF_ROOT}. // NOTE: This only returns *updated* targets. targetFiles, err := t.updateClient() if err != nil { return err } // Download **newly** updated targets. // TODO: Consider lazily downloading these -- be careful with embedded targets if so. for name, targetMeta := range targetFiles { if err := maybeDownloadRemoteTarget(name, targetMeta, t); err != nil { return err } } return nil } type targetDestination struct { buf *bytes.Buffer } func (t *targetDestination) Write(b []byte) (int, error) { return t.buf.Write(b) } func (t *targetDestination) Delete() error { t.buf = &bytes.Buffer{} return nil } func maybeDownloadRemoteTarget(name string, meta data.TargetFileMeta, t *TUF) error { // If we already have the target locally, don't bother downloading from remote storage. if cachedTarget, err := t.targets.Get(name); err == nil { // If the target we have stored matches the meta, use that. if valid, _ := isValidTarget(cachedTarget, meta); valid { return nil } } // Check if we already have the target in the embedded store. w := bytes.Buffer{} rd, ok := t.embedded.(fs.ReadFileFS) if !ok { return errors.New("fs.ReadFileFS unimplemented for embedded repo") } b, err := rd.ReadFile(path.Join("repository", "targets", name)) if err == nil { // Unfortunately go:embed appears to somehow replace our line endings on windows, we need to switch them back. // It should theoretically be safe to do this everywhere - but the files only seem to get mutated on Windows so // let's only change them back there. if runtime.GOOS == "windows" { b = bytes.ReplaceAll(b, []byte("\r\n"), []byte("\n")) } if valid, _ := isValidTarget(b, meta); valid { if _, err := io.Copy(&w, bytes.NewReader(b)); err != nil { return fmt.Errorf("using embedded target: %w", err) } } } // Nope -- no local matching target, go download it. if w.Len() == 0 { dest := targetDestination{buf: &w} if err := t.client.Download(name, &dest); err != nil { return fmt.Errorf("downloading target: %w", err) } } // Set the target in the cache. if err := t.targets.Set(name, w.Bytes()); err != nil { return err } return nil } func rootCacheDir() string { rootDir := os.Getenv(TufRootEnv) if rootDir == "" { home, err := os.UserHomeDir() if err != nil { home = "" } return filepath.FromSlash(filepath.Join(home, ".sigstore", "root")) } return rootDir } func cachedRemote(cacheRoot string) string { return filepath.FromSlash(filepath.Join(cacheRoot, "remote.json")) } func cachedTargetsDir(cacheRoot string) string { return filepath.FromSlash(filepath.Join(cacheRoot, "targets")) } func syncLocalMeta(from, to client.LocalStore) error { // Copy trusted metadata in the from LocalStore into the to LocalStore. tufLocalStoreMeta, err := from.GetMeta() if err != nil { return fmt.Errorf("getting metadata to sync: %w", err) } for k, v := range tufLocalStoreMeta { if err := to.SetMeta(k, v); err != nil { return fmt.Errorf("syncing local store for metadata %s", k) } } return nil } // Local store implementations func newLocalStore() (client.LocalStore, error) { local := client.MemoryLocalStore() if noCache() { return local, nil } // Otherwise populate the in-memory local store with data fetched from the cache. tufDB := filepath.FromSlash(filepath.Join(rootCacheDir(), "tuf.db")) diskLocal, err := tuf_leveldbstore.FileLocalStore(tufDB) defer func() { if diskLocal != nil { diskLocal.Close() } }() if err != nil { return nil, fmt.Errorf("creating cached local store: %w", err) } // Populate the in-memory local store with data fetched from the cache. if err := syncLocalMeta(diskLocal, local); err != nil { return nil, err } return local, nil } //go:embed repository var embeddedRootRepo embed.FS // getEmbedded is a var for testing. var getEmbedded = func() fs.FS { return embeddedRootRepo } // Target Implementations type targetImpl interface { Set(string, []byte) error Get(string) ([]byte, error) } func newFileImpl() targetImpl { memTargets := &memoryCache{} if noCache() { return memTargets } // Otherwise use a disk-cache with in-memory cached targets. return &diskCache{ base: cachedTargetsDir(rootCacheDir()), memory: memTargets, } } // In-memory cache for targets type memoryCache struct { targets map[string][]byte } func (m *memoryCache) Set(p string, b []byte) error { if m.targets == nil { m.targets = map[string][]byte{} } m.targets[p] = b return nil } func (m *memoryCache) Get(p string) ([]byte, error) { if m.targets == nil { return nil, fmt.Errorf("no cached targets available, cannot retrieve %s", p) } b, ok := m.targets[p] if !ok { return nil, fmt.Errorf("missing cached target %s", p) } return b, nil } // On-disk cache for targets type diskCache struct { // Base directory for accessing targets. base string // An in-memory map of targets that are kept in sync. memory *memoryCache } func (d *diskCache) Get(p string) ([]byte, error) { // Read from the in-memory cache first. if b, err := d.memory.Get(p); err == nil { return b, nil } fp := filepath.FromSlash(filepath.Join(d.base, p)) return os.ReadFile(fp) } func (d *diskCache) Set(p string, b []byte) error { if err := d.memory.Set(p, b); err != nil { return err } fp := filepath.FromSlash(filepath.Join(d.base, p)) if err := os.MkdirAll(filepath.Dir(fp), 0o700); err != nil { return fmt.Errorf("creating targets dir: %w", err) } return os.WriteFile(fp, b, 0o600) } func noCache() bool { b, err := strconv.ParseBool(os.Getenv(SigstoreNoCache)) if err != nil { return false } return b } func remoteFromMirror(mirror string) (client.RemoteStore, error) { // This is for compatibility with specifying a GCS bucket remote. u, parseErr := url.ParseRequestURI(mirror) if parseErr != nil { return client.HTTPRemoteStore(fmt.Sprintf("https://%s.storage.googleapis.com", mirror), nil, nil) } if u.Scheme != "file" { return client.HTTPRemoteStore(mirror, nil, nil) } // Use local filesystem for remote. return client.NewFileRemoteStore(os.DirFS(u.Path), "") } sigstore-1.8.6/pkg/tuf/client_test.go000066400000000000000000000571571463713551000176340ustar00rootroot00000000000000// // 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 tuf import ( "bytes" "context" "encoding/json" "fmt" "io/fs" "net/http" "net/http/httptest" "os" "path" "path/filepath" "reflect" "sort" "strings" "sync" "testing" "testing/fstest" "time" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/data" "github.com/theupdateframework/go-tuf/verify" ) // These are the expected targets from the Sigstore root. // This may not be the total complete list to ensure that targets // can be added during new ceremonies. var targets = []string{ "artifact.pub", "fulcio_v1.crt.pem", "ctfe.pub", "rekor.pub", "ctfe_2022.pub", "fulcio.crt.pem", "fulcio_intermediate_v1.crt.pem", "trusted_root.json", } func TestNewFromEnv(t *testing.T) { td := t.TempDir() t.Setenv("TUF_ROOT", td) ctx := context.Background() // Make sure nothing is expired tuf, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, targets) resetForTests() // Now try with expired targets forceExpiration(t, true) tuf, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, targets) resetForTests() if err := Initialize(ctx, DefaultRemoteRoot, nil); err != nil { t.Error() } if l := dirLen(t, td); l == 0 { t.Errorf("expected filesystem writes, got %d entries", l) } // And go from there! tuf, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, targets) resetForTests() } func TestLegacyURLToCDN(t *testing.T) { td := t.TempDir() t.Setenv("TUF_ROOT", td) remoteInfo := &remoteCache{Mirror: defaultRemoteRootNoCDN} b, err := json.Marshal(remoteInfo) if err != nil { t.Fatal(err) } if err := os.WriteFile(cachedRemote(td), b, 0o600); err != nil { t.Fatalf("storing remote: %v", err) } // First initialization, populate the cache. tuf, err := NewFromEnv(context.Background()) if err != nil { t.Fatal(err) } if tuf.Mirror() != DefaultRemoteRoot { t.Fatal("legacy prod GCS HTTP endpoint was not mapped to CDN") } } func TestAltLegacyURLToCDN(t *testing.T) { td := t.TempDir() t.Setenv("TUF_ROOT", td) remoteInfo := &remoteCache{Mirror: defaultRemoteRootNoCDNAlt} b, err := json.Marshal(remoteInfo) if err != nil { t.Fatal(err) } if err := os.WriteFile(cachedRemote(td), b, 0o600); err != nil { t.Fatalf("storing remote: %v", err) } // First initialization, populate the cache. tuf, err := NewFromEnv(context.Background()) if err != nil { t.Fatal(err) } if tuf.Mirror() != DefaultRemoteRoot { t.Fatal("legacy prod GCS HTTP endpoint was not mapped to CDN") } } func TestCDNRewriteforMirror(t *testing.T) { tuf := &TUF{ mirror: defaultRemoteGCSBucket, } if tuf.Mirror() != DefaultRemoteRoot { t.Fatal("reference to default remote GCS bucket was not redirected to CDN") } tuf.mirror = defaultRemoteRootNoCDN if tuf.Mirror() != DefaultRemoteRoot { t.Fatal("reference to default remote GCS HTTP endpoint was not redirected to CDN") } tuf.mirror = defaultRemoteRootNoCDNAlt if tuf.Mirror() != DefaultRemoteRoot { t.Fatal("reference to alternate remote GCS HTTP endpoint was not redirected to CDN") } } func TestLegacyBucketToCDN(t *testing.T) { td := t.TempDir() t.Setenv("TUF_ROOT", td) remoteInfo := &remoteCache{Mirror: defaultRemoteGCSBucket} b, err := json.Marshal(remoteInfo) if err != nil { t.Fatal(err) } if err := os.WriteFile(cachedRemote(td), b, 0o600); err != nil { t.Fatalf("storing remote: %v", err) } // First initialization, populate the cache. tuf, err := NewFromEnv(context.Background()) if err != nil { t.Fatal(err) } if tuf.Mirror() != DefaultRemoteRoot { t.Fatal("legacy prod bucket was not mapped to CDN") } } func TestNoCache(t *testing.T) { ctx := context.Background() // Once more with NO_CACHE t.Setenv("SIGSTORE_NO_CACHE", "true") td := t.TempDir() t.Setenv("TUF_ROOT", td) // First initialization, populate the cache. tuf, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, targets) resetForTests() // Force expiration so we have some content to download forceExpiration(t, true) tuf, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, targets) resetForTests() // No filesystem writes when using SIGSTORE_NO_CACHE. if l := dirLen(t, td); l != 0 { t.Errorf("expected no filesystem writes, got %d entries", l) } resetForTests() } func TestCache(t *testing.T) { ctx := context.Background() // Once more with cache. t.Setenv("SIGSTORE_NO_CACHE", "false") td := t.TempDir() t.Setenv("TUF_ROOT", td) // Make sure nothing is in that directory to start with if l := dirLen(t, td); l != 0 { t.Errorf("expected no filesystem writes, got %d entries", l) } // First initialization, populate the cache. Expect disk writes. tuf, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, targets) resetForTests() cachedDirLen := dirLen(t, td) if cachedDirLen == 0 { t.Errorf("expected filesystem writes, got %d entries", cachedDirLen) } // Nothing should get downloaded if everything is up to date. forceExpiration(t, false) _, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } resetForTests() if l := dirLen(t, td); cachedDirLen != l { t.Errorf("expected no filesystem writes, got %d entries", l-cachedDirLen) } // Forcing expiration, but expect no disk writes because all targets up to date. forceExpiration(t, true) tuf, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } if l := dirLen(t, td); l != cachedDirLen { t.Errorf("expected filesystem writes, got %d entries", l) } checkTargetsAndMeta(t, tuf, targets) resetForTests() } func TestCustomRoot(t *testing.T) { ctx := context.Background() // Create a remote repository. td := t.TempDir() remote, r := newTufRepo(t, td, "foo") // Serve remote repository. s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) defer s.Close() // Initialize with custom root. tufRoot := t.TempDir() t.Setenv("TUF_ROOT", tufRoot) meta, err := remote.GetMeta() if err != nil { t.Error(err) } rootBytes, ok := meta["root.json"] if !ok { t.Error(err) } if err := Initialize(ctx, s.URL, rootBytes); err != nil { t.Error(err) } if l := dirLen(t, tufRoot); l == 0 { t.Errorf("expected filesystem writes, got %d entries", l) } // Successfully get target. tufObj, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } if b, err := tufObj.GetTarget("foo.txt"); err != nil || !bytes.Equal(b, []byte("foo")) { t.Fatal(err) } resetForTests() // Force expiration on the first timestamp and internal go-tuf verification. forceExpirationVersion(t, 1) oldIsExpired := verify.IsExpired verify.IsExpired = func(time time.Time) bool { return true } // This should cause an error that remote metadata is expired. if _, err = NewFromEnv(ctx); err == nil { t.Errorf("expected expired timestamp from the remote") } // Let internal TUF verification succeed normally now. verify.IsExpired = oldIsExpired // Update remote targets, issue a timestamp v2. updateTufRepo(t, td, r, "foo1") // Use newTuf and successfully get updated metadata using the cached remote location. resetForTests() tufObj, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } if b, err := tufObj.GetTarget("foo.txt"); err != nil || !bytes.Equal(b, []byte("foo1")) { t.Fatal(err) } resetForTests() } func TestCustomRootFileRemoteStore(t *testing.T) { ctx := context.Background() // Create a remote repository. td := t.TempDir() remote, r := newTufRepo(t, td, "foo") // Initialize with custom root. tufRoot := t.TempDir() t.Setenv("TUF_ROOT", tufRoot) meta, err := remote.GetMeta() if err != nil { t.Error(err) } rootBytes, ok := meta["root.json"] if !ok { t.Error(err) } // Tack on repository to the end of the td above since that's where // newTufRepo creates the repository. fileURI := fmt.Sprintf("file://%s", filepath.Join(td, "repository")) if err := Initialize(ctx, fileURI, rootBytes); err != nil { t.Error(err) } if l := dirLen(t, tufRoot); l == 0 { t.Errorf("expected filesystem writes, got %d entries", l) } // Successfully get target. tufObj, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } if b, err := tufObj.GetTarget("foo.txt"); err != nil || !bytes.Equal(b, []byte("foo")) { t.Fatal(err) } resetForTests() // Force expiration on the first timestamp and internal go-tuf verification. forceExpirationVersion(t, 1) oldIsExpired := verify.IsExpired verify.IsExpired = func(time time.Time) bool { return true } // This should cause an error that remote metadata is expired. if _, err = NewFromEnv(ctx); err == nil { t.Errorf("expected expired timestamp from the remote") } // Let internal TUF verification succeed normally now. verify.IsExpired = oldIsExpired // Update remote targets, issue a timestamp v2. updateTufRepo(t, td, r, "foo1") // Use newTuf and successfully get updated metadata using the cached remote location. resetForTests() tufObj, err = NewFromEnv(ctx) if err != nil { t.Fatal(err) } if b, err := tufObj.GetTarget("foo.txt"); err != nil || !bytes.Equal(b, []byte("foo1")) { t.Fatal(err) } resetForTests() } func TestGetTargetsByMeta(t *testing.T) { ctx := context.Background() // Create a remote repository. td := t.TempDir() remote, _ := newTufCustomRepo(t, td, "foo") // Serve remote repository. s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) defer s.Close() // Initialize with custom root. tufRoot := t.TempDir() t.Setenv("TUF_ROOT", tufRoot) meta, err := remote.GetMeta() if err != nil { t.Error(err) } rootBytes, ok := meta["root.json"] if !ok { t.Error(err) } if err := Initialize(ctx, s.URL, rootBytes); err != nil { t.Error(err) } if l := dirLen(t, tufRoot); l == 0 { t.Errorf("expected filesystem writes, got %d entries", l) } tufObj, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } defer resetForTests() // Fetch a target with no custom metadata. targets, err := tufObj.GetTargetsByMeta(UnknownUsage, []string{"fooNoCustom.txt"}) if err != nil { t.Fatal(err) } if len(targets) != 1 { t.Fatalf("expected one target without custom metadata, got %d targets", len(targets)) } if !bytes.Equal(targets[0].Target, []byte("foo")) { t.Fatalf("target metadata mismatched, expected: %s, got: %s", "foo", string(targets[0].Target)) } if targets[0].Status != Active { t.Fatalf("target without custom metadata not active, got: %v", targets[0].Status) } // Fetch multiple targets with no custom metadata. targets, err = tufObj.GetTargetsByMeta(UnknownUsage, []string{"fooNoCustom.txt", "fooNoCustomOther.txt"}) if err != nil { t.Fatal(err) } if len(targets) != 2 { t.Fatalf("expected two targets without custom metadata, got %d targets", len(targets)) } if targets[0].Status != Active || targets[1].Status != Active { t.Fatalf("target without custom metadata not active, got: %v and %v", targets[0].Status, targets[1].Status) } // Specify multiple fallbacks with no custom metadata. targets, err = tufObj.GetTargetsByMeta(UnknownUsage, []string{"fooNoCustom.txt", "fooNoCustomOtherMissingTarget.txt"}) if err != nil { t.Fatal(err) } if len(targets) != 1 { t.Fatalf("expected one targets without custom metadata, got %d targets", len(targets)) } if targets[0].Status != Active { t.Fatalf("target without custom metadata not active, got: %v and %v", targets[0].Status, targets[1].Status) } // Fetch targets with custom metadata. targets, err = tufObj.GetTargetsByMeta(Fulcio, []string{"fooNoCustom.txt"}) if err != nil { t.Fatal(err) } if len(targets) != 2 { t.Fatalf("expected two targets without custom metadata, got %d targets", len(targets)) } targetBytes := []string{string(targets[0].Target), string(targets[1].Target)} expectedTB := []string{"foo", "foo"} if !reflect.DeepEqual(targetBytes, expectedTB) { t.Fatalf("target metadata mismatched, expected: %v, got: %v", expectedTB, targetBytes) } targetStatuses := []StatusKind{targets[0].Status, targets[1].Status} sort.Slice(targetStatuses, func(i, j int) bool { return targetStatuses[i] < targetStatuses[j] }) expectedTS := []StatusKind{Active, Expired} if !reflect.DeepEqual(targetStatuses, expectedTS) { t.Fatalf("unexpected target status with custom metadata, expected %v, got: %v", expectedTS, targetStatuses) } // Error when fetching target that does not exist. _, err = tufObj.GetTargetsByMeta(UsageKind(UnknownStatus), []string{"unknown.txt"}) expectedErr := "file not found: unknown.txt" if !strings.Contains(err.Error(), "not found: unknown.txt") { t.Fatalf("unexpected error fetching missing metadata, expected: %s, got: %s", expectedErr, err.Error()) } } func makeMapFS(repo string) (fs fstest.MapFS) { fs = make(fstest.MapFS) _ = filepath.Walk(repo, func(fpath string, info os.FileInfo, err error) error { if err != nil { return err } rel, _ := filepath.Rel(repo, fpath) if info.IsDir() { fs[path.Join("repository", rel)] = &fstest.MapFile{Mode: os.ModeDir} } else { b, _ := os.ReadFile(fpath) fs[path.Join("repository", rel)] = &fstest.MapFile{Data: b} } return nil }) return } // Regression test for failure to fetch a target that does not exist in the embedded // repository on an update. The new target exists on the remote before the TUF object // is initialized. func TestUpdatedTargetNamesEmbedded(t *testing.T) { td := t.TempDir() // Set the TUF_ROOT so we don't interact with other tests and local TUF roots. t.Setenv("TUF_ROOT", td) origEmbedded := getEmbedded origDefaultRemote := getRemoteRoot // Create an "expired" embedded repository that does not contain newTarget. ctx := context.Background() store, r := newTufCustomRepo(t, td, "foo") repository := filepath.FromSlash(filepath.Join(td, "repository")) mapfs := makeMapFS(repository) getEmbedded = func() fs.FS { return mapfs } oldIsExpired := isExpiredTimestamp isExpiredTimestamp = func(metadata []byte) bool { m, _ := store.GetMeta() timestampExpires, _ := getExpiration(m["timestamp.json"]) metadataExpires, _ := getExpiration(metadata) return metadataExpires.Sub(*timestampExpires) <= 0 } defer func() { getEmbedded = origEmbedded getRemoteRoot = origDefaultRemote isExpiredTimestamp = oldIsExpired }() // Assert that the embedded repository does not contain the newTarget. newTarget := "fooNew.txt" rd, ok := getEmbedded().(fs.ReadFileFS) if !ok { t.Fatal("fs.ReadFileFS unimplemented for embedded repo") } if _, err := rd.ReadFile(path.Join("repository", "targets", newTarget)); err == nil { t.Fatal("embedded repository should not contain new target") } // Serve an updated remote repository with the newTarget. addNewCustomTarget(t, td, r, map[string]string{newTarget: "newdata"}) s := httptest.NewServer(http.FileServer(http.Dir(repository))) defer s.Close() getRemoteRoot = func() string { return s.URL } // Initialize. tufObj, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } defer resetForTests() // Try to retrieve the newly added target. targets, err := tufObj.GetTargetsByMeta(Fulcio, []string{"fooNoCustom.txt"}) if err != nil { t.Fatal(err) } if len(targets) != 3 { t.Fatalf("expected three target without custom metadata, got %d targets", len(targets)) } targetBytes := []string{string(targets[0].Target), string(targets[1].Target), string(targets[2].Target)} expectedTB := []string{"foo", "foo", "newdata"} if !cmp.Equal(targetBytes, expectedTB, cmpopts.SortSlices(func(a, b string) bool { return a < b })) { t.Fatalf("target data mismatched, expected: %v, got: %v", expectedTB, targetBytes) } } func checkTargetsAndMeta(t *testing.T, tuf *TUF, expected []string) { // Check the targets t.Helper() for _, target := range expected { if _, err := tuf.GetTarget(target); err != nil { t.Fatal(err) } } // An invalid target if _, err := tuf.GetTarget("invalid"); err == nil { t.Error("expected error reading target, got nil") } // Check root status. _, err := tuf.getRootStatus() if err != nil { t.Fatal(err) } } func dirLen(t *testing.T, td string) int { t.Helper() de, err := os.ReadDir(td) if err != nil { t.Fatal(err) } return len(de) } func forceExpiration(t *testing.T, expire bool) { oldIsExpiredTimestamp := isExpiredTimestamp isExpiredTimestamp = func(_ []byte) bool { return expire } t.Cleanup(func() { isExpiredTimestamp = oldIsExpiredTimestamp }) } func forceExpirationVersion(t *testing.T, version int64) { oldIsExpiredTimestamp := isExpiredTimestamp isExpiredTimestamp = func(metadata []byte) bool { s := &data.Signed{} if err := json.Unmarshal(metadata, s); err != nil { return true } sm := &data.Timestamp{} if err := json.Unmarshal(s.Signed, sm); err != nil { return true } return sm.Version <= version } t.Cleanup(func() { isExpiredTimestamp = oldIsExpiredTimestamp }) } // newTufCustomRepo initializes a TUF repository with root, targets, snapshot, and timestamp roles // 4 targets are created to exercise various code paths, including two targets with no custom metadata, // one target with custom metadata marked as active, and another with custom metadata marked as expired. func newTufCustomRepo(t *testing.T, td, targetData string) (tuf.LocalStore, *tuf.Repo) { scmActive, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Active}}) if err != nil { t.Error(err) } scmExpired, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Expired}}) if err != nil { t.Error(err) } remote := tuf.FileSystemStore(td, nil) r, err := tuf.NewRepo(remote) if err != nil { t.Error(err) } if err := r.Init(false); err != nil { t.Error(err) } for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { if _, err := r.GenKey(role); err != nil { t.Error(err) } } for name, scm := range map[string]json.RawMessage{ "fooNoCustom.txt": nil, "fooNoCustomOther.txt": nil, "fooActive.txt": scmActive, "fooExpired.txt": scmExpired, } { targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", name)) if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil { t.Error(err) } if err := os.WriteFile(targetPath, []byte(targetData), 0o600); err != nil { t.Error(err) } if err := r.AddTarget(name, scm); err != nil { t.Error(err) } } if err := r.Snapshot(); err != nil { t.Error(err) } if err := r.Timestamp(); err != nil { t.Error(err) } if err := r.Commit(); err != nil { t.Error(err) } return remote, r } func addNewCustomTarget(t *testing.T, td string, r *tuf.Repo, targetData map[string]string) { scmActive, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Active}}) if err != nil { t.Error(err) } for name, data := range targetData { targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", name)) if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil { t.Error(err) } if err := os.WriteFile(targetPath, []byte(data), 0o600); err != nil { t.Error(err) } if err := r.AddTarget(name, scmActive); err != nil { t.Error(err) } } if err := r.Snapshot(); err != nil { t.Error(err) } if err := r.Timestamp(); err != nil { t.Error(err) } if err := r.Commit(); err != nil { t.Error(err) } } func newTufRepo(t *testing.T, td, targetData string) (tuf.LocalStore, *tuf.Repo) { remote := tuf.FileSystemStore(td, nil) r, err := tuf.NewRepo(remote) if err != nil { t.Error(err) } if err := r.Init(false); err != nil { t.Error(err) } for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { if _, err := r.GenKey(role); err != nil { t.Error(err) } } targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", "foo.txt")) if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil { t.Error(err) } if err := os.WriteFile(targetPath, []byte(targetData), 0o600); err != nil { t.Error(err) } if err := r.AddTarget("foo.txt", nil); err != nil { t.Error(err) } if err := r.Snapshot(); err != nil { t.Error(err) } if err := r.Timestamp(); err != nil { t.Error(err) } if err := r.Commit(); err != nil { t.Error(err) } return remote, r } func updateTufRepo(t *testing.T, td string, r *tuf.Repo, targetData string) { targetPath := filepath.FromSlash(filepath.Join(td, "staged", "targets", "foo.txt")) if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil { t.Error(err) } if err := os.WriteFile(targetPath, []byte(targetData), 0o600); err != nil { t.Error(err) } if err := r.AddTarget("foo.txt", nil); err != nil { t.Error(err) } if err := r.Snapshot(); err != nil { t.Error(err) } if err := r.Timestamp(); err != nil { t.Error(err) } if err := r.Commit(); err != nil { t.Error(err) } } func TestConcurrentAccessNewFromEnv(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func() { defer wg.Done() tufObj, err := NewFromEnv(context.Background()) if err != nil { t.Errorf("Failed to construct NewFromEnv: %s", err) } if tufObj == nil { t.Error("Got back nil tufObj") } time.Sleep(1 * time.Second) }() } wg.Wait() resetForTests() } func TestConcurrentAccessInitialize(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func() { defer wg.Done() err := Initialize(context.Background(), DefaultRemoteRoot, nil) if err != nil { t.Errorf("Failed to construct NewFromEnv: %s", err) } time.Sleep(1 * time.Second) }() } wg.Wait() resetForTests() } // Test to validate that sigstore TUF client can cache targets that // are located in sub-folders. func TestTargetsSubfolder(t *testing.T) { ctx := context.Background() // Create a remote repository. td := t.TempDir() remote, r := newTufCustomRepo(t, td, "foo") newTarget := "subfolder/fooNew.txt" addNewCustomTarget(t, td, r, map[string]string{newTarget: "newdata"}) // Serve remote repository. s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) defer s.Close() // Initialize with custom root. tufRoot := t.TempDir() // Set the TUF_ROOT so we don't interact with other tests and local TUF roots. t.Setenv("TUF_ROOT", tufRoot) meta, err := remote.GetMeta() if err != nil { t.Error(err) } rootBytes, ok := meta["root.json"] if !ok { t.Error(err) } if err := Initialize(ctx, s.URL, rootBytes); err != nil { t.Error(err) } defer resetForTests() tuf, err := NewFromEnv(ctx) if err != nil { t.Fatal(err) } checkTargetsAndMeta(t, tuf, []string{newTarget}) } func Test_remoteFromMirror(t *testing.T) { // test GCS mirror mirror := "test-bucket" _, err := remoteFromMirror(mirror) if err != nil { t.Fatalf("unexpected error with GCS mirror: %v", err) } // test HTTP mirror mirror = "https://tuf-repo-cdn.sigstage.dev" _, err = remoteFromMirror(mirror) if err != nil { t.Fatalf("unexpected error with GCS mirror: %v", err) } // test local mirror tufRoot := t.TempDir() os.Mkdir(fmt.Sprintf("%s/targets", tufRoot), 0o0750) mirror = fmt.Sprintf("file://%s", tufRoot) _, err = remoteFromMirror(mirror) if err != nil { t.Fatalf("unexpected error with GCS mirror: %v", err) } } sigstore-1.8.6/pkg/tuf/repository/000077500000000000000000000000001463713551000171705ustar00rootroot00000000000000sigstore-1.8.6/pkg/tuf/repository/root.json000066400000000000000000000151561463713551000210560ustar00rootroot00000000000000{ "signed": { "_type": "root", "spec_version": "1.0", "version": 9, "expires": "2024-09-12T06:53:10Z", "keys": { "1e1d65ce98b10addad4764febf7dda2d0436b3d3a3893579c0dddaea20e54849": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n" } }, "230e212616274a4195cdc28e9fce782c20e6c720f1a811b40f98228376bdd3ac": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n" } }, "3c344aa068fd4cc4e87dc50b612c02431fbc771e95003993683a2b0bf260cf0e": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n" } }, "923bb39e60dd6fa2c31e6ea55473aa93b64dd4e53e16fbe42f6a207d3f97de2d": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n" } }, "e2f59acb9488519407e18cbfc9329510be03c04aca9929d2f0301343fec85523": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n" } }, "ec81669734e017996c5b85f3d02c3de1dd4637a152019fe1af125d2f9368b95e": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n" } }, "fdfa83a07b5a83589b87ded41f77f39d232ad91f7cce52868dacd06ba089849f": { "keytype": "ecdsa", "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n" } } }, "roles": { "root": { "keyids": [ "3c344aa068fd4cc4e87dc50b612c02431fbc771e95003993683a2b0bf260cf0e", "ec81669734e017996c5b85f3d02c3de1dd4637a152019fe1af125d2f9368b95e", "1e1d65ce98b10addad4764febf7dda2d0436b3d3a3893579c0dddaea20e54849", "e2f59acb9488519407e18cbfc9329510be03c04aca9929d2f0301343fec85523", "fdfa83a07b5a83589b87ded41f77f39d232ad91f7cce52868dacd06ba089849f" ], "threshold": 3 }, "snapshot": { "keyids": [ "230e212616274a4195cdc28e9fce782c20e6c720f1a811b40f98228376bdd3ac" ], "threshold": 1 }, "targets": { "keyids": [ "3c344aa068fd4cc4e87dc50b612c02431fbc771e95003993683a2b0bf260cf0e", "ec81669734e017996c5b85f3d02c3de1dd4637a152019fe1af125d2f9368b95e", "1e1d65ce98b10addad4764febf7dda2d0436b3d3a3893579c0dddaea20e54849", "e2f59acb9488519407e18cbfc9329510be03c04aca9929d2f0301343fec85523", "fdfa83a07b5a83589b87ded41f77f39d232ad91f7cce52868dacd06ba089849f" ], "threshold": 3 }, "timestamp": { "keyids": [ "923bb39e60dd6fa2c31e6ea55473aa93b64dd4e53e16fbe42f6a207d3f97de2d" ], "threshold": 1 } }, "consistent_snapshot": true }, "signatures": [ { "keyid": "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", "sig": "30450221008b78f894c3cfed3bd486379c4e0e0dfb3e7dd8cbc4d5598d2818eea1ba3c7550022029d3d06e89d04d37849985dc46c0e10dc5b1fc68dc70af1ec9910303a1f3ee2f" }, { "keyid": "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", "sig": "30450221009e6b90b935e09b837a90d4402eaa27d5ea26eb7891948ba0ed7090841248f436022003dc2251c4d4a7999b91e9ad0868765ae09ac7269279f2a7899bafef7a2d9260" }, { "keyid": "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", "sig": "30440220099e907dcf90b7b6e109fd1d6e442006fccbb48894aaaff47ab824b03fb35d0d02202aa0a06c21a4233f37900a48bc8777d3b47f59e3a38616ce631a04df57f96736" }, { "keyid": "3c344aa068fd4cc4e87dc50b612c02431fbc771e95003993683a2b0bf260cf0e", "sig": "30450221008b78f894c3cfed3bd486379c4e0e0dfb3e7dd8cbc4d5598d2818eea1ba3c7550022029d3d06e89d04d37849985dc46c0e10dc5b1fc68dc70af1ec9910303a1f3ee2f" }, { "keyid": "ec81669734e017996c5b85f3d02c3de1dd4637a152019fe1af125d2f9368b95e", "sig": "30450221009e6b90b935e09b837a90d4402eaa27d5ea26eb7891948ba0ed7090841248f436022003dc2251c4d4a7999b91e9ad0868765ae09ac7269279f2a7899bafef7a2d9260" }, { "keyid": "e2f59acb9488519407e18cbfc9329510be03c04aca9929d2f0301343fec85523", "sig": "304502200e5613b901e0f3e08eceabddc73f98b50ddf892e998d0b369c6e3d451ac48875022100940cf92d1f43ee2e5cdbb22572bb52925ed3863a688f7ffdd4bd2e2e56f028b3" }, { "keyid": "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de", "sig": "304502202cff44f2215d7a47b28b8f5f580c2cfbbd1bfcfcbbe78de323045b2c0badc5e9022100c743949eb3f4ea5a4b9ae27ac6eddea1f0ff9bfd004f8a9a9d18c6e4142b6e75" }, { "keyid": "1e1d65ce98b10addad4764febf7dda2d0436b3d3a3893579c0dddaea20e54849", "sig": "30440220099e907dcf90b7b6e109fd1d6e442006fccbb48894aaaff47ab824b03fb35d0d02202aa0a06c21a4233f37900a48bc8777d3b47f59e3a38616ce631a04df57f96736" }, { "keyid": "fdfa83a07b5a83589b87ded41f77f39d232ad91f7cce52868dacd06ba089849f", "sig": "304502202cff44f2215d7a47b28b8f5f580c2cfbbd1bfcfcbbe78de323045b2c0badc5e9022100c743949eb3f4ea5a4b9ae27ac6eddea1f0ff9bfd004f8a9a9d18c6e4142b6e75" }, { "keyid": "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", "sig": "304502200e5613b901e0f3e08eceabddc73f98b50ddf892e998d0b369c6e3d451ac48875022100940cf92d1f43ee2e5cdbb22572bb52925ed3863a688f7ffdd4bd2e2e56f028b3" } ] }sigstore-1.8.6/pkg/tuf/repository/targets/000077500000000000000000000000001463713551000206415ustar00rootroot00000000000000sigstore-1.8.6/pkg/tuf/repository/targets/artifact.pub000066400000000000000000000002611463713551000231450ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhyQCx0E9wQWSFI9ULGwy3BuRklnt IqozONbbdbqz11hlRJy9c7SG+hdcFl9jE9uE/dwtuwU2MqU9T/cN0YkWww== -----END PUBLIC KEY-----sigstore-1.8.6/pkg/tuf/repository/targets/ctfe.pub000066400000000000000000000002611463713551000222710ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3Pyu dDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w== -----END PUBLIC KEY-----sigstore-1.8.6/pkg/tuf/repository/targets/ctfe_2022.pub000066400000000000000000000002621463713551000227370ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNK AaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw== -----END PUBLIC KEY----- sigstore-1.8.6/pkg/tuf/repository/targets/fulcio.crt.pem000066400000000000000000000013501463713551000234130ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== -----END CERTIFICATE-----sigstore-1.8.6/pkg/tuf/repository/targets/fulcio_intermediate_v1.crt.pem000066400000000000000000000014251463713551000265560ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7 7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS 0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP mygUY7Ii2zbdCdliiow= -----END CERTIFICATE-----sigstore-1.8.6/pkg/tuf/repository/targets/fulcio_v1.crt.pem000066400000000000000000000013441463713551000240240ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ -----END CERTIFICATE-----sigstore-1.8.6/pkg/tuf/repository/targets/rekor.pub000066400000000000000000000002621463713551000224730ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwr kBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw== -----END PUBLIC KEY----- sigstore-1.8.6/pkg/tuf/repository/targets/trusted_root.json000066400000000000000000000155461463713551000243040ustar00rootroot00000000000000{ "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", "tlogs": [ { "baseUrl": "https://rekor.sigstore.dev", "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "2021-01-12T11:53:27.000Z" } }, "logId": { "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" } } ], "certificateAuthorities": [ { "subject": { "organization": "sigstore.dev", "commonName": "sigstore" }, "uri": "https://fulcio.sigstore.dev", "certChain": { "certificates": [ { "rawBytes": "MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIxMDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSyA7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0JcastaRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJxVe/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uupHr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==" } ] }, "validFor": { "start": "2021-03-07T03:20:29.000Z", "end": "2022-12-31T23:59:59.999Z" } }, { "subject": { "organization": "sigstore.dev", "commonName": "sigstore" }, "uri": "https://fulcio.sigstore.dev", "certChain": { "certificates": [ { "rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow=" }, { "rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ" } ] }, "validFor": { "start": "2022-04-13T20:06:15.000Z" } } ], "ctlogs": [ { "baseUrl": "https://ctfe.sigstore.dev/test", "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "2021-03-14T00:00:00.000Z", "end": "2022-10-31T23:59:59.999Z" } }, "logId": { "keyId": "CGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3I=" } }, { "baseUrl": "https://ctfe.sigstore.dev/2022", "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "2022-10-20T00:00:00.000Z" } }, "logId": { "keyId": "3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4=" } } ], "timestampAuthorities": [ { "subject": { "organization": "GitHub, Inc.", "commonName": "Internal Services Root" }, "certChain": { "certificates": [ { "rawBytes": "MIIB3DCCAWKgAwIBAgIUchkNsH36Xa04b1LqIc+qr9DVecMwCgYIKoZIzj0EAwMwMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMB4XDTIzMDQxNDAwMDAwMFoXDTI0MDQxMzAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgVGltZXN0YW1waW5nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUD5ZNbSqYMd6r8qpOOEX9ibGnZT9GsuXOhr/f8U9FJugBGExKYp40OULS0erjZW7xV9xV52NnJf5OeDq4e5ZKqNWMFQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaW1RudOgVt0leqY0WKYbuPr47wAwCgYIKoZIzj0EAwMDaAAwZQIwbUH9HvD4ejCZJOWQnqAlkqURllvu9M8+VqLbiRK+zSfZCZwsiljRn8MQQRSkXEE5AjEAg+VxqtojfVfu8DhzzhCx9GKETbJHb19iV72mMKUbDAFmzZ6bQ8b54Zb8tidy5aWe" }, { "rawBytes": "MIICEDCCAZWgAwIBAgIUX8ZO5QXP7vN4dMQ5e9sU3nub8OgwCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTI4MDQxMjAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEvMLY/dTVbvIJYANAuszEwJnQE1llftynyMKIMhh48HmqbVr5ygybzsLRLVKbBWOdZ21aeJz+gZiytZetqcyF9WlER5NEMf6JV7ZNojQpxHq4RHGoGSceQv/qvTiZxEDKo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaW1RudOgVt0leqY0WKYbuPr47wAwHwYDVR0jBBgwFoAU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaQAwZgIxAK1B185ygCrIYFlIs3GjswjnwSMG6LY8woLVdakKDZxVa8f8cqMs1DhcxJ0+09w95QIxAO+tBzZk7vjUJ9iJgD4R6ZWTxQWKqNm74jO99o+o9sv4FI/SZTZTFyMn0IJEHdNmyA==" }, { "rawBytes": "MIIB9DCCAXqgAwIBAgIUa/JAkdUjK4JUwsqtaiRJGWhqLSowCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTMzMDQxMTAwMDAwMFowODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEf9jFAXxz4kx68AHRMOkFBhflDcMTvzaXz4x/FCcXjJ/1qEKon/qPIGnaURskDtyNbNDOpeJTDDFqt48iMPrnzpx6IZwqemfUJN4xBEZfza+pYt/iyod+9tZr20RRWSv/o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaAAwZQIxALZLZ8BgRXzKxLMMN9VIlO+e4hrBnNBgF7tz7Hnrowv2NetZErIACKFymBlvWDvtMAIwZO+ki6ssQ1bsZo98O8mEAf2NZ7iiCgDDU0Vwjeco6zyeh0zBTs9/7gV6AHNQ53xD" } ] }, "validFor": { "start": "2023-04-14T00:00:00.000Z" } } ] } sigstore-1.8.6/pkg/tuf/status_type.go000066400000000000000000000026501463713551000176670ustar00rootroot00000000000000// 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 tuf import ( "fmt" "strings" ) type StatusKind int const ( UnknownStatus StatusKind = iota Active Expired ) var toStatusString = map[StatusKind]string{ UnknownStatus: "Unknown", Active: "Active", Expired: "Expired", } func (s StatusKind) String() string { return toStatusString[s] } func (s StatusKind) MarshalText() ([]byte, error) { str := s.String() if len(str) == 0 { return nil, fmt.Errorf("error while marshalling, int(StatusKind)=%d not valid", int(s)) } return []byte(s.String()), nil } func (s *StatusKind) UnmarshalText(text []byte) error { switch strings.ToLower(string(text)) { case "unknown": *s = UnknownStatus case "active": *s = Active case "expired": *s = Expired default: return fmt.Errorf("error while unmarshalling, StatusKind=%v not valid", string(text)) } return nil } sigstore-1.8.6/pkg/tuf/status_type_test.go000066400000000000000000000054741463713551000207350ustar00rootroot00000000000000// 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 tuf import ( "encoding/json" "fmt" "reflect" "strings" "testing" ) func TestMarshalStatusType(t *testing.T) { statuses := []StatusKind{UnknownStatus, Active, Expired} bytes, err := json.Marshal(statuses) if err != nil { t.Fatalf("expected no error marshalling struct, got: %v", err) } expected := `["Unknown","Active","Expired"]` if string(bytes) != expected { t.Fatalf("error while marshalling, expected: %s, got: %s", expected, bytes) } } func TestMarshalInvalidStatusType(t *testing.T) { invalidStatus := 42 statuses := []StatusKind{StatusKind(invalidStatus)} bytes, err := json.Marshal(statuses) if bytes != nil { t.Fatalf("expected error marshalling struct, got: %v", bytes) } expectedErr := fmt.Sprintf("error while marshalling, int(StatusKind)=%d not valid", invalidStatus) if !strings.Contains(err.Error(), expectedErr) { t.Fatalf("expected error marshalling struct, expected: %v, got: %v", expectedErr, err) } } func TestUnmarshalStatusType(t *testing.T) { var statuses []StatusKind j := json.RawMessage(`["expired", "active", "unknown"]`) err := json.Unmarshal(j, &statuses) if err != nil { t.Fatalf("expected no error unmarshalling struct, got: %v", err) } if !reflect.DeepEqual(statuses, []StatusKind{Expired, Active, UnknownStatus}) { t.Fatalf("expected [Expired, Active, Unknown], got: %v", statuses) } } func TestUnmarshalStatusTypeCapitalization(t *testing.T) { // Any capitalization is allowed. var statuses []StatusKind j := json.RawMessage(`["eXpIrEd", "aCtIvE", "uNkNoWn"]`) err := json.Unmarshal(j, &statuses) if err != nil { t.Fatalf("expected no error unmarshalling struct, got: %v", err) } if !reflect.DeepEqual(statuses, []StatusKind{Expired, Active, UnknownStatus}) { t.Fatalf("expected [Expired, Active, Unknown], got: %v", statuses) } } func TestUnmarshalInvalidStatusType(t *testing.T) { var statuses []StatusKind invalidStatus := "invalid" j := json.RawMessage(fmt.Sprintf(`["%s"]`, invalidStatus)) err := json.Unmarshal(j, &statuses) expectedErr := fmt.Sprintf("error while unmarshalling, StatusKind=%s not valid", invalidStatus) if !strings.Contains(err.Error(), expectedErr) { t.Fatalf("expected error unmarshalling struct, expected: %v, got: %v", expectedErr, err) } } sigstore-1.8.6/pkg/tuf/testutils.go000066400000000000000000000070311463713551000173410ustar00rootroot00000000000000// // 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 tuf import ( "context" "crypto/x509" "encoding/json" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" "github.com/theupdateframework/go-tuf" ) type TestSigstoreRoot struct { Rekor signature.Verifier FulcioCertificate *x509.Certificate // TODO: Include a CTFE key if/when cosign verifies SCT. } // This creates a new sigstore TUF repo whose signers can be used to create dynamic // signed Rekor entries. func NewSigstoreTufRepo(t *testing.T, root TestSigstoreRoot) (tuf.LocalStore, *tuf.Repo) { td := t.TempDir() ctx := context.Background() remote := tuf.FileSystemStore(td, nil) r, err := tuf.NewRepo(remote) if err != nil { t.Error(err) } if err := r.Init(false); err != nil { t.Error(err) } for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { if _, err := r.GenKey(role); err != nil { t.Error(err) } } targetsPath := filepath.Join(td, "staged", "targets") if err := os.MkdirAll(filepath.Dir(targetsPath), 0o755); err != nil { t.Error(err) } // Add the rekor key target pk, err := root.Rekor.PublicKey(options.WithContext(ctx)) if err != nil { t.Error(err) } b, err := x509.MarshalPKIXPublicKey(pk) if err != nil { t.Error(err) } rekorPath := "rekor.pub" rekorData := cryptoutils.PEMEncode(cryptoutils.PublicKeyPEMType, b) if err := os.WriteFile(filepath.Join(targetsPath, rekorPath), rekorData, 0o600); err != nil { t.Error(err) } scmRekor, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Rekor, Status: Active}}) if err != nil { t.Error(err) } if err := r.AddTarget("rekor.pub", scmRekor); err != nil { t.Error(err) } // Add Fulcio Certificate information. fulcioPath := "fulcio.crt.pem" fulcioData := cryptoutils.PEMEncode(cryptoutils.CertificatePEMType, root.FulcioCertificate.Raw) if err := os.WriteFile(filepath.Join(targetsPath, fulcioPath), fulcioData, 0o600); err != nil { t.Error(err) } scmFulcio, err := json.Marshal(&sigstoreCustomMetadata{Sigstore: customMetadata{Usage: Fulcio, Status: Active}}) if err != nil { t.Error(err) } if err := r.AddTarget(fulcioPath, scmFulcio); err != nil { t.Error(err) } if err := r.Snapshot(); err != nil { t.Error(err) } if err := r.Timestamp(); err != nil { t.Error(err) } if err := r.Commit(); err != nil { t.Error(err) } // Serve remote repository. s := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(td, "repository")))) defer s.Close() // Initialize with custom root. tufRoot := t.TempDir() t.Setenv("TUF_ROOT", tufRoot) meta, err := remote.GetMeta() if err != nil { t.Error(err) } rootBytes, ok := meta["root.json"] if !ok { t.Error(err) } resetForTests() if err := Initialize(ctx, s.URL, rootBytes); err != nil { t.Error(err) } t.Cleanup(func() { resetForTests() }) return remote, r } sigstore-1.8.6/pkg/tuf/usage_type.go000066400000000000000000000027731463713551000174560ustar00rootroot00000000000000// 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 tuf import ( "fmt" "strings" ) type UsageKind int const ( UnknownUsage UsageKind = iota Fulcio Rekor CTFE TSA ) var toUsageString = map[UsageKind]string{ UnknownUsage: "Unknown", Fulcio: "Fulcio", Rekor: "Rekor", CTFE: "CTFE", TSA: "TSA", } func (u UsageKind) String() string { return toUsageString[u] } func (u UsageKind) MarshalText() ([]byte, error) { str := u.String() if len(str) == 0 { return nil, fmt.Errorf("error while marshalling, int(UsageKind)=%d not valid", int(u)) } return []byte(u.String()), nil } func (u *UsageKind) UnmarshalText(text []byte) error { switch strings.ToLower(string(text)) { case "unknown": *u = UnknownUsage case "fulcio": *u = Fulcio case "rekor": *u = Rekor case "ctfe": *u = CTFE case "tsa": *u = TSA default: return fmt.Errorf("error while unmarshalling, UsageKind=%v not valid", string(text)) } return nil } sigstore-1.8.6/pkg/tuf/usage_type_test.go000066400000000000000000000055441463713551000205140ustar00rootroot00000000000000// 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 tuf import ( "encoding/json" "fmt" "reflect" "strings" "testing" ) func TestMarshalUsageType(t *testing.T) { usages := []UsageKind{UnknownUsage, Fulcio, Rekor, CTFE, TSA} bytes, err := json.Marshal(usages) if err != nil { t.Fatalf("expected no error marshalling struct, got: %v", err) } expected := `["Unknown","Fulcio","Rekor","CTFE","TSA"]` if string(bytes) != expected { t.Fatalf("error while marshalling, expected: %s, got: %s", expected, bytes) } } func TestMarshalInvalidUsageType(t *testing.T) { invalidUsage := 42 usages := []UsageKind{UsageKind(invalidUsage)} bytes, err := json.Marshal(usages) if bytes != nil { t.Fatalf("expected error marshalling struct, got: %v", bytes) } expectedErr := fmt.Sprintf("error while marshalling, int(UsageKind)=%d not valid", invalidUsage) if !strings.Contains(err.Error(), expectedErr) { t.Fatalf("expected error marshalling struct, expected: %v, got: %v", expectedErr, err) } } func TestUnmarshalUsageType(t *testing.T) { var usages []UsageKind j := json.RawMessage(`["fulcio", "rekor", "ctfe", "tsa", "unknown"]`) err := json.Unmarshal(j, &usages) if err != nil { t.Fatalf("expected no error unmarshalling struct, got: %v", err) } if !reflect.DeepEqual(usages, []UsageKind{Fulcio, Rekor, CTFE, TSA, UnknownUsage}) { t.Fatalf("expected [Fulcio, Rekor, CTFE, TSA, UnknownUsage], got: %v", usages) } } func TestUnmarshalUsageTypeCapitalization(t *testing.T) { // Any capitalization is allowed. var usages []UsageKind j := json.RawMessage(`["fUlCiO", "rEkOr", "cTfE", "tSa", "uNkNoWn"]`) err := json.Unmarshal(j, &usages) if err != nil { t.Fatalf("expected no error unmarshalling struct, got: %v", err) } if !reflect.DeepEqual(usages, []UsageKind{Fulcio, Rekor, CTFE, TSA, UnknownUsage}) { t.Fatalf("expected [Fulcio, Rekor, CTFE, TSA, UnknownUsage], got: %v", usages) } } func TestUnmarshalInvalidUsageType(t *testing.T) { var usages []UsageKind invalidUsage := "invalid" j := json.RawMessage(fmt.Sprintf(`["%s"]`, invalidUsage)) err := json.Unmarshal(j, &usages) expectedErr := fmt.Sprintf("error while unmarshalling, UsageKind=%s not valid", invalidUsage) if !strings.Contains(err.Error(), expectedErr) { t.Fatalf("expected error unmarshalling struct, expected: %v, got: %v", expectedErr, err) } } sigstore-1.8.6/test/000077500000000000000000000000001463713551000143515ustar00rootroot00000000000000sigstore-1.8.6/test/cert_utils.go000066400000000000000000000130621463713551000170570ustar00rootroot00000000000000// 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 test contains test utilities package test import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "math/big" "net" "net/url" "time" ) /* To use: rootCert, rootKey, _ := GenerateRootCa() subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) leafCert, _, _ := GenerateLeafCert("subject", "oidc-issuer", 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.ExtKeyUsageCodeSigning, }, } _, err := leafCert.Verify(opts) */ func createCertificate(template, 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 } return x509.ParseCertificate(certBytes) } // GenerateRootCa generates a test root CA func GenerateRootCa() (*x509.Certificate, *ecdsa.PrivateKey, error) { rootTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-5 * time.Hour), 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 } // GenerateSubordinateCa generates a test intermediate CA func GenerateSubordinateCa(rootTemplate *x509.Certificate, rootPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { subTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore-sub", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-2 * time.Minute), NotAfter: time.Now().Add(2 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, 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 } // GenerateLeafCert generates a test leaf certificate func GenerateLeafCert(subject, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer, exts ...pkix.Extension) (*x509.Certificate, *ecdsa.PrivateKey, error) { exts = append(exts, pkix.Extension{ // OID for OIDC Issuer extension Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, Critical: false, Value: []byte(oidcIssuer), }) certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), EmailAddresses: []string{subject}, NotBefore: time.Now().Add(-1 * time.Minute), NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, ExtraExtensions: exts, } 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 } // GenerateLeafCertWithSubjectAlternateNames generates a test leaf certificate with the specified SANs func GenerateLeafCertWithSubjectAlternateNames(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), EmailAddresses: emailAddresses, DNSNames: dnsNames, IPAddresses: ipAddresses, URIs: uris, NotBefore: time.Now().Add(-1 * time.Minute), NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, ExtraExtensions: []pkix.Extension{{ // OID for OIDC Issuer extension Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, Critical: false, Value: []byte(oidcIssuer), }}, } 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 } sigstore-1.8.6/test/e2e/000077500000000000000000000000001463713551000150245ustar00rootroot00000000000000sigstore-1.8.6/test/e2e/dex-config.yml000066400000000000000000000016771463713551000176050ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. issuer: http://127.0.0.1:5556/auth storage: type: memory # Configuration for the HTTP endpoints. web: http: 0.0.0.0:5556 logger: level: debug oauth2: responseTypes: [ "code" ] skipApprovalScreen: true alwaysShowLoginScreen: false staticClients: - id: sigstore name: 'Sigstore Mock' public: true connectors: - type: mockCallback id: mock name: Mock sigstore-1.8.6/test/e2e/dexidp.Dockerfile000066400000000000000000000012761463713551000203000ustar00rootroot00000000000000# # 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. FROM ghcr.io/dexidp/dex:v2.40.0@sha256:3e35d5d0f7dbd33fbadc36a71ff58cf4097ab98d73d22f6cb9a6471a32e028af sigstore-1.8.6/test/e2e/docker-compose.yml000066400000000000000000000022311463713551000204570ustar00rootroot00000000000000# # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: "3.8" services: vault: build: dockerfile: vault.Dockerfile context: '.' environment: VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_TOKEN} ports: - 8200:8200 privileged: true localstack: build: dockerfile: localstack.Dockerfile context: '.' ports: - 4566:4566 environment: - SERVICES=kms dex: build: dockerfile: dexidp.Dockerfile context: '.' ports: - "5556:5556" volumes: - ./dex-config.yml:/etc/dex/dex-config.yml:z command: ["dex", "serve", "/etc/dex/dex-config.yml"] sigstore-1.8.6/test/e2e/e2e-test.sh000077500000000000000000000033111463713551000170110ustar00rootroot00000000000000#!/bin/bash # # Copyright 2021 The Sigstore Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -ex cleanup() { echo "cleanup" docker-compose down } trap cleanup ERR export VAULT_TOKEN=testtoken export VAULT_ADDR=http://localhost:8200/ echo "starting services" docker-compose config docker-compose up -d --build count=0 echo -n "waiting up to 60 sec for system to start" until [ $(docker-compose ps vault | grep -c -e "Up" -e "running") == 1 -a $(docker-compose logs localstack | grep -c Ready) == 1 ]; do if [ $count -eq 12 ]; then echo "! timeout reached" exit 1 else echo -n "." sleep 5 let 'count+=1' fi done sleep 5 echo echo "running tests" export VAULT_TOKEN=testtoken export VAULT_ADDR=http://localhost:8200/ export AWS_ACCESS_KEY_ID=test export AWS_SECRET_ACCESS_KEY=test export AWS_REGION=us-east-1 export AWS_ENDPOINT=localhost:4566 export AWS_TLS_INSECURE_SKIP_VERIFY=1 export OIDC_ISSUER=http://127.0.0.1:5556/auth export OIDC_ID=sigstore go test -tags e2e -count=1 ../../... cd ../.. for dir in $(find pkg/signature/kms/ -name go.mod | sed -e 's/go\.mod//g') do cd $dir && go test -tags e2e -count=1 ./... cd ../../../../ done cd test/e2e cleanup sigstore-1.8.6/test/e2e/localstack.Dockerfile000066400000000000000000000013111463713551000211310ustar00rootroot00000000000000# # 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. FROM docker.io/localstack/localstack:3.5.0@sha256:c0d346a4b726f167e16451d01a217dfe17f07994ac30f7ab61b57aa321b3e4d6 sigstore-1.8.6/test/e2e/vault.Dockerfile000066400000000000000000000013041463713551000201460ustar00rootroot00000000000000# # 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. FROM docker.io/hashicorp/vault:1.17.0@sha256:51e5f9b108e49aed025a27cbb66848911cb2bccee072057ba965b835a5427bce sigstore-1.8.6/test/fuzz/000077500000000000000000000000001463713551000153475ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/README.md000066400000000000000000000016551463713551000166350ustar00rootroot00000000000000### Fuzzing The fuzzing of sigstore uses [go-fuzz](https://github.com/dvyukov/go-fuzz) for fuzzing. It is integrated into oss-fuzz https://github.com/google/oss-fuzz/pull/6890 for fuzzing continuously. #### Why not use go 1.18 fuzzing? The go-fuzz can be compatible with `libfuzzer`, which is supported by `oss-fuzz`. The go 1.18 doesn't have support for external fuzzer formats yet. #### What is corpus? >A set of inputs for a fuzz target. In most contexts, it refers to a set of minimal test inputs that generate maximal code coverage. https://google.github.io/clusterfuzz/reference/glossary/#corpus #### How do I run the fuzzer? 1. `make fuzz` 2. `go-fuzz -bin=signature-fuzz.zip -func FuzzED25529SignerVerfier` 3. An example to use the `libfuzzer` `go-fuzz-build --libfuzzer -func FuzzRSASignerVerfier ./signature/...` and `clang -fsanitize=fuzzer reflect-fuzz.a -o fmt.libfuzzer` 4. The `libfuzzer` option requires `linux`. sigstore-1.8.6/test/fuzz/corpus/000077500000000000000000000000001463713551000166625ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/corpus/ecdsa/000077500000000000000000000000001463713551000177415ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/corpus/ecdsa/0000066400000000000000000000010011463713551000200130ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTnXFzkBUgER/32YRahg+YyJseS9Gwr G982a+OzogidAlUuzGXGLPuziHcLcbHQDB3MxLWIiRDSGgjGfYmbjIpOAAAAsGyAIeBsgC HgAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOdcXOQFSARH/fZh FqGD5jImx5L0bCsb3zZr47OiCJ0CVS7MZcYs+7OIdwtxsdAMHczEtYiJENIaCMZ9iZuMik 4AAAAhALSGPEUKRuducAVHwVHfqAG3jupDJQnrdcOFeUUW0HmhAAAAFnNhbW15QG5ldy1s YXJnZS1kZXZib3gB -----END OPENSSH PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/ecdsa/1000066400000000000000000000010011463713551000200140ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQn8+kqeep6yWIiuxiZE46+CIgXQaVZ b/drvUj4aimMkqNncvPpYUkEczyJzI8+hpYuIMuXj3TlsK3jwdSHLiUyAAAAsPqPcNH6j3 DRAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCfz6Sp56nrJYiK7 GJkTjr4IiBdBpVlv92u9SPhqKYySo2dy8+lhSQRzPInMjz6Gli4gy5ePdOWwrePB1IcuJT IAAAAgU2zRLbT+EaaRJdXrugpDhi6rxeli730rLFGPUhJXpsAAAAAWc2FtbXlAbmV3LWxh cmdlLWRldmJveAEC -----END OPENSSH PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/ecdsa/2000066400000000000000000000002151463713551000200230ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS -----END OPENSSH PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/ed25519/000077500000000000000000000000001463713551000176605ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/corpus/ed25519/0000066400000000000000000000006431463713551000177450ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACCv5p8foWdwQ6YKC8BP47vgm4hGKs7a0wEvdLMELWCRtgAAAKBCmyBmQpsg ZgAAAAtzc2gtZWQyNTUxOQAAACCv5p8foWdwQ6YKC8BP47vgm4hGKs7a0wEvdLMELWCRtg AAAEAKPu7W+HvvKHBE6CkKSeTyCQ7XX18PvCf1iesnYXiHh6/mnx+hZ3BDpgoLwE/ju+Cb iEYqztrTAS90swQtYJG2AAAAFnNhbW15QG5ldy1sYXJnZS1kZXZib3gBAgMEBQYH -----END OPENSSH PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/ed25519/1000066400000000000000000000006431463713551000177460ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACClVDDJyLbCLxwTQ6okIn1Wpfv2K4Fn33EW7xXNiwF7EgAAAKB0N5GVdDeR lQAAAAtzc2gtZWQyNTUxOQAAACClVDDJyLbCLxwTQ6okIn1Wpfv2K4Fn33EW7xXNiwF7Eg AAAECfDvH57XG4lNcADy8kb1f3oAPJDyaGD8hgdTsLtQ4176VUMMnItsIvHBNDqiQifVal +/YrgWffcRbvFc2LAXsSAAAAFnNhbW15QG5ldy1sYXJnZS1kZXZib3gBAgMEBQYH -----END OPENSSH PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/ed25519/2000066400000000000000000000001101463713551000177340ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- A -----END OPENSSH PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/pem/000077500000000000000000000000001463713551000174435ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/corpus/pem/0000066400000000000000000000000401463713551000175170ustar00rootroot00000000000000-----BEGIN ----- -----END ----- sigstore-1.8.6/test/fuzz/corpus/pem/00aa063b6a11aa6532146400d321a29ac57772df-6000066400000000000000000000000241463713551000246730ustar00rootroot00000000000000-----BEGIN ----- :sigstore-1.8.6/test/fuzz/corpus/pem/039e15380cca84b1e0566d3212c336e5f3d83b07-2000066400000000000000000000000151463713551000247240ustar00rootroot00000000000000-----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/0ad367ffa4f81383a24ef6abe1dc34ea4f77c25f-3000066400000000000000000000000511463713551000254610ustar00rootroot00000000000000-----BEGIN foo----- : -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/0b80059edfb2da2efb180e4d86c3975fb0e1eaba-8000066400000000000000000000000251463713551000255340ustar00rootroot00000000000000-----BEGIN ----- :⿽sigstore-1.8.6/test/fuzz/corpus/pem/1000066400000000000000000000001021463713551000175170ustar00rootroot00000000000000-----BEGIN foo----- : aaa: bbb foo: YmFyYmF6 -----END foo----- sigstore-1.8.6/test/fuzz/corpus/pem/126c5ff159d29cb0be86edd93ac59fea84eeb8f9-2000066400000000000000000000001011463713551000255670ustar00rootroot00000000000000-- --BEGIN foo----- : aaa: bbb fbb f YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/143b2870fa376ee37d700e46bad6b95da7cc6bf8-5000066400000000000000000000000171463713551000253320ustar00rootroot00000000000000-----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/16bef3faa75283175c0f6ee02820f32cfda7b5d0-4000066400000000000000000000001011463713551000253030ustar00rootroot00000000000000-- -aBEGIN1foo----- : -aa: bbb6 ----- : aaa: bb --END foo---sigstore-1.8.6/test/fuzz/corpus/pem/17dc2d28046108693e97a37eadcd107aa04870e3-3000066400000000000000000000000301463713551000250100ustar00rootroot00000000000000-----BEGIN ----- : :sigstore-1.8.6/test/fuzz/corpus/pem/1b83cfdc173ac48684d838336c7c1a55280e0acf-3000066400000000000000000000000141463713551000251600ustar00rootroot00000000000000-----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/1bb1cb35daa2c2c232ace34d07f6067ac86da2ef-1000066400000000000000000000000651463713551000255060ustar00rootroot00000000000000-----BEGIN foo----- fooT YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/1bfab2d6d235f0e89b0a2c9abb0c3afbb61ac831-1000066400000000000000000000000321463713551000255560ustar00rootroot00000000000000-----BEGIN ----- -----END sigstore-1.8.6/test/fuzz/corpus/pem/1c25ea2b045f73b72084eacf83a91a1d4e536194-1000066400000000000000000000000561463713551000250710ustar00rootroot00000000000000-----BEGIN foo----- mFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/1c293c6c956336a2e08d55087f43d331b571623e-6000066400000000000000000000001011463713551000246020ustar00rootroot00000000000000063349815200 -----BEGIN ----- : -aa: bbb6u----- : aaa:aaa: bbsigstore-1.8.6/test/fuzz/corpus/pem/2264b923a08d8b8784e39896da6d85095075eb2a-2000066400000000000000000000001011463713551000247040ustar00rootroot00000000000000-- --BEGIN1foo----- : aaa: bbb6 foo: YmFyYmF6 -----END foo---sigstore-1.8.6/test/fuzz/corpus/pem/242cc35d953670092808e9d961d5511a818e3b6d-1000066400000000000000000000000371463713551000246160ustar00rootroot00000000000000-----BEGIN ----- -----END -----sigstore-1.8.6/test/fuzz/corpus/pem/28023cd89a1827d1e70fe20215bdcf36b71fa499-4000066400000000000000000000001201463713551000250760ustar00rootroot00000000000000-----BEGIN foo----- unK6newline in format does not match input -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/32d7f4d00dbb5c8f962ef8ff8a31629ccc721aa1-4000066400000000000000000000000521463713551000254030ustar00rootroot00000000000000-----BEGIN foo----- :: -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/3fb4188486c64a812260611d749dc9fc7ca15da3-1000066400000000000000000000000461463713551000250300ustar00rootroot00000000000000-----BEGIN foo----- -----END foo------sigstore-1.8.6/test/fuzz/corpus/pem/40bdf4011e9fafe0e9b1b4e7cd4eef84a669cb06-2000066400000000000000000000000671463713551000255500ustar00rootroot00000000000000-----BEGIN foo----- : : : YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/46c44389cde762038f7ed276eeb5eb16287b41b0-2000066400000000000000000000000521463713551000251160ustar00rootroot00000000000000-----BEGIN foo----- :ߧ -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/48feeb9a655d20bfdfd263ba92fdbf6600bba7fa-5000066400000000000000000000001221463713551000257000ustar00rootroot00000000000000-----BEGIN ----- -- -7035266621122884 Gaa: bbbffbb bagW| mFyYmF6 --key has besigstore-1.8.6/test/fuzz/corpus/pem/4a339febca054df203b4627e14d0016fdd518143-7000066400000000000000000000000371463713551000250640ustar00rootroot00000000000000 -----BEGIN ----- aaa:aaa: bbsigstore-1.8.6/test/fuzz/corpus/pem/4bc1c12e85085d1b3e0f0b2551d21422067a8b7b-4000066400000000000000000000000161463713551000247660ustar00rootroot00000000000000-----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/4c1795357af14c6c54d4fa99b6fad04f7a431df9-1000066400000000000000000000000701463713551000252560ustar00rootroot00000000000000-----BEGIN foo----- : : : YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/4d47644faa08a59937b8f013b99ca3b5ac4fffeb-5000066400000000000000000000000241463713551000254150ustar00rootroot00000000000000-----BEGIN ----- :Έsigstore-1.8.6/test/fuzz/corpus/pem/514b139e4ce9d356890d06f4af51df2f1afc3c13-2000066400000000000000000000000541463713551000252410ustar00rootroot00000000000000-----BEGIN foo----- fooT -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/53371d74058793bbeea98a1ed896d235647ee54f-2000066400000000000000000000000721463713551000250570ustar00rootroot00000000000000-----BEGIN foo----- aabbb foo YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/55e49de57989fda88102051841cc1837835663f9-4000066400000000000000000000000261463713551000245670ustar00rootroot00000000000000-----BEGIN ----- :osigstore-1.8.6/test/fuzz/corpus/pem/5727a70cf1fd7c94c5e8b67a644718be30ef4ba1-6000066400000000000000000000000241463713551000252540ustar00rootroot00000000000000-----BEGIN ----- N :sigstore-1.8.6/test/fuzz/corpus/pem/57d856a3a72f72aa0aff7cef1463125e85ebb717-6000066400000000000000000000001221463713551000252470ustar00rootroot00000000000000-----BEGIN ----- - : ---367035266621122884 : Gaa: bbb fbb bagW| mFyYmF6 ---sigstore-1.8.6/test/fuzz/corpus/pem/5e41a95a406ec15af97f98b309ced43f926dcdeb-2000066400000000000000000000000671463713551000254260ustar00rootroot00000000000000-----BEGIN foo----- aabbb fooYmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/6177b5c12494f44da46e86b545f6bf16e6d9a37f-2000066400000000000000000000000141463713551000251260ustar00rootroot00000000000000 -----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/64a855b2b07b06e17e543094b2fea14fc3684e43-2000066400000000000000000000000501463713551000250130ustar00rootroot00000000000000-----BEGIN foo----- 6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/6ba8ad653a36b5f8d8a45c659af0e5b61ec552d8-1000066400000000000000000000001011463713551000253250ustar00rootroot00000000000000-- --BEGIN foo----- : aaa: bbb foo: YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/73f7efa4dc5b350d91f9dec193009afe6089be97-1000066400000000000000000000000141463713551000253440ustar00rootroot00000000000000: YmFyYmF6 sigstore-1.8.6/test/fuzz/corpus/pem/75b35c51db6d069ba0ad6051524168aaf2594bfa-3000066400000000000000000000000261463713551000251440ustar00rootroot00000000000000-----BEGIN ----- : sigstore-1.8.6/test/fuzz/corpus/pem/77ac6f147fab168ade8c977a5c25f2dc27ae5a52-4000066400000000000000000000000171463713551000254150ustar00rootroot00000000000000-----BEGIN -sigstore-1.8.6/test/fuzz/corpus/pem/78d3194b5b93a6448ebbd539a1f12cb5273b00eb-1000066400000000000000000000000371463713551000251530ustar00rootroot00000000000000-----BEGIN ----- -----END o----sigstore-1.8.6/test/fuzz/corpus/pem/7a1a027faf971e46bc3fc08280e58ea47d46696c-9000066400000000000000000000000271463713551000252060ustar00rootroot00000000000000-----BEGIN ----- ܮ:⿽sigstore-1.8.6/test/fuzz/corpus/pem/800630235c61d15f3d21c1e72c1d4fa9c2452a06-3000066400000000000000000000000321463713551000247040ustar00rootroot00000000000000-----BEGIN ----- :foosigstore-1.8.6/test/fuzz/corpus/pem/83a880604a0db06142e5c50c06edcc7568c42f34-7000066400000000000000000000000241463713551000250110ustar00rootroot00000000000000-----BEGIN ----- :sigstore-1.8.6/test/fuzz/corpus/pem/84d7f874ed4f1821d5188f8bfc5a970af2a8f13c-1000066400000000000000000000000261463713551000252700ustar00rootroot00000000000000-----BEGIN ----- foo sigstore-1.8.6/test/fuzz/corpus/pem/86156bb87353421d7a4dbd22ee8c87da90319c85-3000066400000000000000000000000471463713551000250420ustar00rootroot00000000000000-----BEGIN foo----- -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/864196a44d1c943bc3e3426a550c33836e24114c-4000066400000000000000000000000271463713551000245750ustar00rootroot00000000000000-----BEGIN ----- �:osigstore-1.8.6/test/fuzz/corpus/pem/8684efa95476c052138696132158f32eba800ce1-3000066400000000000000000000000541463713551000246140ustar00rootroot00000000000000-----BEGIN foo----- : -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/879034c826380a27c9b61e8549decc9c6d080510-3000066400000000000000000000000231463713551000246760ustar00rootroot00000000000000-----BEGIN ----- :sigstore-1.8.6/test/fuzz/corpus/pem/8cea0a2091af85c9740e519c9b2bcbbef33223db-3000066400000000000000000000000521463713551000253660ustar00rootroot00000000000000-----BEGIN foo----- :ا -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/8deec9a0749c64dc6541da31b465762e2bf11341-6000066400000000000000000000000241463713551000251010ustar00rootroot00000000000000-----BEGIN ----- :sigstore-1.8.6/test/fuzz/corpus/pem/8f51cef2a076c2850e056835015a018e42fd7168-3000066400000000000000000000001011463713551000246540ustar00rootroot00000000000000-- --BEGIN1foo----- : aaa: bbb6 ----- : aaa: bb --END foo---sigstore-1.8.6/test/fuzz/corpus/pem/95c694ba9fc0fc5cb833114b9dc4ed6ae7644c79-3000066400000000000000000000000151463713551000253440ustar00rootroot00000000000000-----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/97d56637605bf32936e7344bc0839dc0d396d002-2000066400000000000000000000000221463713551000246120ustar00rootroot00000000000000-----BEGIN ----- fsigstore-1.8.6/test/fuzz/corpus/pem/9c65264e4b0b01adedc9ca30fbd20d7a3b6e4686-7000066400000000000000000000000251463713551000253720ustar00rootroot00000000000000-----BEGIN ----- :�sigstore-1.8.6/test/fuzz/corpus/pem/9d6ffa203cf753ab82943975ac34ae76b23a9503-4000066400000000000000000000000271463713551000251130ustar00rootroot00000000000000-----BEGIN -----BEGIN sigstore-1.8.6/test/fuzz/corpus/pem/a06a30151c284ca655d30170ab5143c9c6c2df8a-4000066400000000000000000000001351463713551000250500ustar00rootroot00000000000000-----BEGIN ----- -- : ---367035266621122884 : Gaa: bbb fbb f bagW| mFyYmF6 -----END foosigstore-1.8.6/test/fuzz/corpus/pem/a2004bc3882e0e0770e3abcf9768fa5c3d642041-2000066400000000000000000000000521463713551000250630ustar00rootroot00000000000000-----BEGIN foo----- FyF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/a345640366934585f446163074acf57c275b597b-3000066400000000000000000000000501463713551000244610ustar00rootroot00000000000000-----BEGIN foo----- ɝ -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/a5d8e3d21838da80e7830e4d3f608c64e0cc4a32-5000066400000000000000000000001221463713551000251600ustar00rootroot00000000000000-----BEGIN ----- -- : 035266621122884 : Gaa: bbb fbb bagW| mFyYmF6 -----END sigstore-1.8.6/test/fuzz/corpus/pem/a6f71960b5a3fe7787c0792d08963e4272bc76de-2000066400000000000000000000000621463713551000250530ustar00rootroot00000000000000-----BEGIN foo----- fooTYmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/a8a0c9af9edc2f5aa62fdb4355692d843605a6af-2000066400000000000000000000001051463713551000254030ustar00rootroot00000000000000-----BEGIN foo----- uncated base 128 integermFyYmK6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/ac2fde6a33a2f3dc35cce4f7a02fa2c87f2c09e8-2000066400000000000000000000000271463713551000256130ustar00rootroot00000000000000-----BEGIN ----- : :sigstore-1.8.6/test/fuzz/corpus/pem/afb44221440eed241164b63ef1c14e0b5b0ffaad-3000066400000000000000000000000751463713551000253440ustar00rootroot00000000000000-----BEGIN foo----- ted 128 integermFyYmK6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/b9f075ae1a41e19f9e7e6176ab3c0dd1ef967161-5000066400000000000000000000001251463713551000252550ustar00rootroot00000000000000-----BEGIN foo----- unK6newlineinformatdoes not beEfFgGvmatch input -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/bb55dfd080331ac9fed155558a8a5adb134b4e7f-2000066400000000000000000000000561463713551000253770ustar00rootroot00000000000000-----BEGIN foo----- nFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/cd1b2b5fb3598b0c314a6d73a8e0a7073b77e3da-2000066400000000000000000000000471463713551000253100ustar00rootroot00000000000000-----BEGIN foo----- -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/d0663f723b7260b2f16b364dbd67f2dd2c32ff00-2000066400000000000000000000000521463713551000251440ustar00rootroot00000000000000-----BEGIN foo-----  -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/d13f816660c54829c658000f1b61b7b4b50f10b1-3000066400000000000000000000000271463713551000246420ustar00rootroot00000000000000-----BEGIN ----- : :sigstore-1.8.6/test/fuzz/corpus/pem/d51c3d46b0aef042186906efb3e342bbd37676dc-5000066400000000000000000000000251463713551000252360ustar00rootroot00000000000000-----BEGIN ----- :osigstore-1.8.6/test/fuzz/corpus/pem/d680b4047f01df32c39741c6b9fda24bcd8b2ee5-3000066400000000000000000000000521463713551000253170ustar00rootroot00000000000000-----BEGIN foo----- unK6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/d76412e8a07f0804d7f8b728da50966f4663b728-3000066400000000000000000000001051463713551000247070ustar00rootroot00000000000000-----BEGIN foo----- uncated base 028 integermFyYmK6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/d89ae5c348e4931f4b5267efcdb798e42c248f5d-5000066400000000000000000000000251463713551000253030ustar00rootroot00000000000000-----BEGIN ----- :sigstore-1.8.6/test/fuzz/corpus/pem/d95f213104887b0fe67d3de603a2ec49fde13f31-2000066400000000000000000000000261463713551000251640ustar00rootroot00000000000000-----BEGIN ----- :foosigstore-1.8.6/test/fuzz/corpus/pem/dfea2feae7c55cf54c241dafd5f951ee4de74164-5000066400000000000000000000000241463713551000256340ustar00rootroot00000000000000-----BEGIN ----- :sigstore-1.8.6/test/fuzz/corpus/pem/e00036d8be7b3b07286b8ce7624c0aeb4e1c1550-4000066400000000000000000000001011463713551000251340ustar00rootroot00000000000000-BEGIN foo----- END ----- : aaa: bbb fbb f YmFyYmF6 -----END fosigstore-1.8.6/test/fuzz/corpus/pem/e6ec65342f830e1780b16840d6a5767cf225553d-2000066400000000000000000000000331463713551000246710ustar00rootroot00000000000000-----BEGIN ----- -----END sigstore-1.8.6/test/fuzz/corpus/pem/f0811f31ec1c422958fd861786088c9cf71d3fb5-1000066400000000000000000000000521463713551000250430ustar00rootroot00000000000000-----BEGIN foo----- foF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/f142d087e3fa84dd0140414b824f3a5398ef7e21-1000066400000000000000000000000531463713551000250170ustar00rootroot00000000000000-----BEGIN foo----- : b -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/f458c0ff1410a9e9b66df63fb530936d44e6c31a-1000066400000000000000000000000721463713551000251700ustar00rootroot00000000000000-----BEGIN foo----- aabbb foo: YmFyYmF6 -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/fab11055c6a34ab2fd0257b4b073eb6a945be42c-3000066400000000000000000000001041463713551000252650ustar00rootroot00000000000000- --BEGIN foo----- END ----- : aaa: bbb fbb f mFyYmF6 -----END foosigstore-1.8.6/test/fuzz/corpus/pem/fac9f9666c93e22462b864764842be9eb9f17e45-1000066400000000000000000000000471463713551000250730ustar00rootroot00000000000000-----BEGIN foo----- -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/fbdd93e11fdd678a319ec8069279d612d02f8df2-1000066400000000000000000000000571463713551000252670ustar00rootroot00000000000000-----BEGIN foo----- a: b o: -----END foo-----sigstore-1.8.6/test/fuzz/corpus/pem/ffc5d83a112d1776b9a006fcab571901cd61fba3-3000066400000000000000000000000301463713551000252760ustar00rootroot00000000000000-----BEGIN ----- �:osigstore-1.8.6/test/fuzz/corpus/rsa/000077500000000000000000000000001463713551000174475ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/corpus/rsa/0000066400000000000000000000032501463713551000175310ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfCoj9PKxSIpOB jVvP7B0l8Q6KXgwSxEBIobMl11nrH2Fv6ufZRWgma7E3rZcjRMygyfia6SB8KBjq OBMHnxX78tp5IDxbPWniA7GGTWZyBsXgfLFH7GVGBh8fiJJtfL4TP/xmMzY47rx8 qvglkQDktdmSEmvfYmof5SIXD/CBI9YDxpXQB9EBcd16QnjwHUKHElOs4lZI9OeP 8TSV8tWyskq1cO4LxPS8WZVTvbq0jp84OwQTpWtJqG/DUQ1QfMjfixt+uauCDA87 iIwBC+rC7aCfaXHpqNayHzToUi2Jc34O6LMyfHgowEjQgnKehClY4Vuy0aJXQvKB mRDqyjO/AgMBAAECggEBAIHOAs3Gis8+WjRSjXVjh882DG1QsJwXZQYgPT+vpiAl YjKdNpOHRkbd9ARgXY5kEuccxDd7p7E6MM3XFpQf7M51ltpZfWboRgAIgD+WOiHw eSbdytr95C6tj11twTJBH+naGk1sTokxv7aaVdKfIjL49oeBexBFmVe4pW9gkmrE 1z1y1a0RohqbZ0kprYPWjz5UhsNqbCzgkdDqS7IrcOwVg6zvKYFjHnqIHqaJXVif FgIfoNt7tz+12FTHI+6OkKoN3YCJueaxneBhITXm6RLOpQWa9qhdUPbkJ9vQNfph Qqke4faaxKY9UDma+GpEHR016AWufZp92pd9wQkDn0kCgYEA7w/ZizAkefHoZhZ8 Isn/fYu4fdtUaVgrnGUVZobiGxWrHRU9ikbAwR7UwbgRSfppGiJdAMq1lyH2irmb 4OHU64rjuYSlIqUWHLQHWmqUbLUvlDojH/vdmH/Zn0AbrLZaimC5UCjK3Eb7sAMq G0tGeDX2JraQvx7KrbC6peTaaaMCgYEA7tgZBiRCQJ7+mNu+gX9x6OXtjsDCh516 vToRLkxWc7LAbC9LKsuEHl4e3vy1PY/nyuv12Ng2dBq4WDXozAmVgz0ok7rRlIFp w8Yj8o/9KuGZkD/7tw/pLsVc9Q3Wf0ACrnAAh7+3dAvn3yg+WHwXzqWIbrseDPt9 ILCfUoNDpzUCgYAKFCX8y0PObFd67lm/cbq2xUw66iNN6ay1BEH5t5gSwkAbksis ar03pyAbJrJ75vXFZ0t6fBFZ1NG7GYYr3fmHEKz3JlN7+W/MN/7TXgjx6FWgLy9J 6ul1w3YeU6qXBn0ctmU5ru6WiNuVmRyOWAcZjFTbXvkNRbQPzJKh6dsXdwKBgA1D FIihxMf/zBVCxl48bF/JPJqbm3GaTfFp4wBWHsrH1yVqrtrOeCSTh1VMZOfpMK60 0W7b+pIR1cCYJbgGpDWoVLN3QSHk2bGUM/TJB/60jilTVC/DA2ikbtfwj8N7E2sK Lw1amN4ptxNOEcAqC8xepqe3XiDMahNBm2cigMQtAoGBAKwrXvss2BKz+/6poJQU A0c7jhMN8M9Y5S2Ockw07lrQeAgfu4q+/8ztm0NeHJbk01IJvJY5Nt7bSgwgNVlo j7vR2BMAc9U73Ju9aeTl/L6GqmZyA+Ojhl5gA5DPZYqNiqi93ydgRaI6n4+o3dI7 5wnr40AmbuKCDvMOvN7nMybL -----END PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/rsa/1000066400000000000000000000001001463713551000175210ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- A -----END RSA PRIVATE KEY----- sigstore-1.8.6/test/fuzz/corpus/signature/000077500000000000000000000000001463713551000206635ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/corpus/signature/0000066400000000000000000000000321463713551000207400ustar00rootroot000000000000004695082086889915666293004 sigstore-1.8.6/test/fuzz/corpus/signature/1000066400000000000000000000000231463713551000207410ustar00rootroot00000000000000564007835656437916 sigstore-1.8.6/test/fuzz/corpus/signature/2000066400000000000000000000000241463713551000207430ustar00rootroot000000000000009735816121518442091 sigstore-1.8.6/test/fuzz/dsse/000077500000000000000000000000001463713551000163055ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/dsse/fuzz_test.go000066400000000000000000000041451463713551000206750ustar00rootroot00000000000000// // 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 dsse import ( "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "encoding/base64" "encoding/json" "strings" "testing" "unicode/utf8" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/sigstore/pkg/signature" ds "github.com/sigstore/sigstore/pkg/signature/dsse" ) func FuzzDSSE(f *testing.F) { f.Fuzz(func(t *testing.T, data, payload string) { if !utf8.Valid([]byte(data)) { t.Skip("invalid utf8") } if !utf8.Valid([]byte(payload)) { t.Skip("invalid utf8") } p, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Errorf("failed to generate key: %v", err) } sv, err := signature.LoadECDSASignerVerifier(p, crypto.SHA256) if err != nil { t.Errorf("failed to load signer verifier: %v", err) } wsv := ds.WrapSignerVerifier(sv, payload) sig, err := wsv.SignMessage(strings.NewReader(data)) if err != nil { t.Errorf("failed to sign message: %v", err) } if err := wsv.VerifySignature(bytes.NewReader(sig), nil); err != nil { t.Errorf("failed to verify signature: %v", err) } env := dsse.Envelope{} if err := json.Unmarshal(sig, &env); err != nil { panic(err) } if env.PayloadType != payload { t.Errorf("Expected payloadType %s, got %s", payload, env.PayloadType) } got, err := base64.StdEncoding.DecodeString(env.Payload) if err != nil { t.Errorf("failed to decode payload: %v", err) } if string(got) != data { t.Errorf("Expected payload %s, got %s", data, env.Payload) } }) } sigstore-1.8.6/test/fuzz/fuzz_password_test.go000066400000000000000000000023761463713551000216650ustar00rootroot00000000000000// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fuzz import ( "bytes" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func FuzzGetPassword(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { original := cryptoutils.Read cryptoutils.Read = func() func() ([]byte, error) { return func() ([]byte, error) { return data, nil } } defer func() { cryptoutils.Read = original }() p, err := cryptoutils.GetPasswordFromStdIn(true) if err != nil { t.Errorf("error in getting the password %v", err) } // the password we got back is not what was entered if bytes.Compare(p, data) != 0 { t.Errorf("password %v does not match %v", p, data) } t.Skip("invalid data") }) } sigstore-1.8.6/test/fuzz/go.mod000066400000000000000000000021401463713551000164520ustar00rootroot00000000000000module github.com/sigstore/sigstore/test/fuzz go 1.21 require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20211102141018-f7be0cbad29c github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1 github.com/secure-systems-lab/go-securesystemslib v0.8.0 github.com/sigstore/sigstore v1.8.4 ) require ( github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect github.com/google/go-containerregistry v0.19.1 // indirect github.com/kr/pretty v0.2.1 // indirect github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/stephens2424/writerset v1.0.2 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/term v0.20.0 // indirect golang.org/x/tools v0.9.1 // indirect google.golang.org/grpc v1.56.3 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) sigstore-1.8.6/test/fuzz/go.sum000066400000000000000000000204461463713551000165100ustar00rootroot00000000000000github.com/AdaLogics/go-fuzz-headers v0.0.0-20211102141018-f7be0cbad29c h1:9K6I0yCgGSneuHCoIlJl0O09UjqqWduCwd+ZL1nHFWc= github.com/AdaLogics/go-fuzz-headers v0.0.0-20211102141018-f7be0cbad29c/go.mod h1:WpB7kf89yJUETZxQnP1kgYPNwlT2jjdDYUCoxVggM3g= github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= 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/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1 h1:YQOLTC8zvFaNSEuMexG0i7pY26bOksnQFsSJfGclo54= github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= 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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e h1:RLTpX495BXToqxpM90Ws4hXEo4Wfh81jr9DX1n/4WOo= github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e/go.mod h1:EAuqr9VFWxBi9nD5jc/EA2MT1RFty9288TF6zdtYoCU= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= 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.4 h1:g4ICNpiENFnWxjmBzBDWUn62rNFeny/P77HUC8da32w= github.com/sigstore/sigstore v1.8.4/go.mod h1:1jIKtkTFEeISen7en+ZPWdDHazqhxco/+v9CNjc7oNg= github.com/stephens2424/writerset v1.0.2 h1:znRLgU6g8RS5euYRcy004XeE4W+Tu44kALzy7ghPif8= github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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/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= go.opentelemetry.io/otel v1.15.0 h1:NIl24d4eiLJPM0vKn4HjLYM+UZf6gSfi9Z+NmCxkWbk= go.opentelemetry.io/otel v1.15.0/go.mod h1:qfwLEbWhLPk5gyWrne4XnF0lC8wtywbuJbgfAE3zbek= go.opentelemetry.io/otel/trace v1.15.0 h1:5Fwje4O2ooOxkfyqI/kJwxWotggDLix4BSAvpE1wlpo= go.opentelemetry.io/otel/trace v1.15.0/go.mod h1:CUsmE2Ht1CRkvE8OsMESvraoZrrcgD1J2W8GV1ev0Y4= 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/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sigstore-1.8.6/test/fuzz/pem/000077500000000000000000000000001463713551000161305ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/pem/fuzzcert_test.go000066400000000000000000000041701463713551000213740ustar00rootroot00000000000000// // 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 pem import ( "bytes" "encoding/pem" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func FuzzLoadCertificates(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { b, _ := pem.Decode(data) if b == nil { t.Skip("invalid pem") } result, err := cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(data)) if err != nil { if result != nil { t.Errorf("result %v should be nil when there is an error %v", result, err) } t.Skip("invalid pem") } for _, cert := range result { if len(cert.Raw) == 0 { t.Errorf("x509 cert raw is empty") } } }) } func FuzzUnmarshalCertificatesFromPEM(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { b, _ := pem.Decode(data) if b == nil { t.Skip("invalid pem") } result, err := cryptoutils.UnmarshalCertificatesFromPEM(data) if err != nil { if result != nil { t.Errorf("result %v should be nil when there is an error %v", result, err) } t.Skip("invalid pem") } for _, cert := range result { if len(cert.Raw) == 0 { t.Errorf("x509 cert raw is empty") } } }) } func FuzzUnmarshalPEMToPublicKey(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { b, _ := pem.Decode(data) if b == nil { t.Skip("invalid pem") } result, err := cryptoutils.UnmarshalPEMToPublicKey(data) if err != nil { if result != nil { t.Errorf("result %v should be nil when there is an error %v", result, err) } t.Skip("invalid pem") } if result == nil { t.Errorf("result %v should not be nil", result) } }) } sigstore-1.8.6/test/fuzz/signature/000077500000000000000000000000001463713551000173505ustar00rootroot00000000000000sigstore-1.8.6/test/fuzz/signature/fuzz_signature_test.go000066400000000000000000000110421463713551000240130ustar00rootroot00000000000000// // 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 signature import ( "bytes" "crypto" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "math/big" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" fuzz "github.com/AdaLogics/go-fuzz-headers" "github.com/sigstore/sigstore/pkg/signature" ) func FuzzECDSASigner(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { x := ecdsa.PrivateKey{} z := new(big.Int) z.SetBytes(data) x.X = z x.Y = z x.D = z x.Curve = elliptic.P384() signer, err := signature.LoadECDSASignerVerifier(&x, crypto.SHA512) if err != nil { if signer != nil { t.Errorf("key %v is not nil when there is an error %v ", signer, err) } t.Skip("not valid key") } sig, err := signer.SignMessage(bytes.NewReader(data)) if err != nil { if sig != nil { t.Errorf("key %v is not nil when there is an error %v ", sig, err) } t.Skip("not valid key") } if err = signer.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)); err != nil { t.Skip("not valid key") } }) } func FuzzComputeDigest(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { hashFuncs := []crypto.Hash{ crypto.SHA256, crypto.SHA512, crypto.SHA384, crypto.SHA224, crypto.SHA1, } data, _, err := signature.ComputeDigestForSigning(bytes.NewReader(data), crypto.SHA512, hashFuncs) if err != nil { if data != nil { t.Errorf("key %v is not nil when there is an error %v ", data, err) } t.Skip("not valid key") } }) } func FuzzComputeVerifying(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { hashFuncs := []crypto.Hash{ crypto.SHA256, crypto.SHA512, crypto.SHA384, crypto.SHA224, crypto.SHA1, } data, _, err := signature.ComputeDigestForVerifying(bytes.NewReader(data), crypto.SHA512, hashFuncs) if err != nil { if data != nil { t.Errorf("key %v is not nil when there is an error %v ", data, err) } t.Skip("not valid key") } }) } func FuzzED25529SignerVerfier(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { x := ed25519.PrivateKey(data) signer, err := signature.LoadED25519SignerVerifier(x) if err != nil { if signer != nil { t.Errorf("key %v is not nil when there is an error %v ", signer, err) } t.Skip("not valid key") } sig, err := signer.SignMessage(bytes.NewReader(data)) if err != nil { if sig != nil { t.Errorf("key %v is not nil when there is an error %v ", sig, err) } t.Skip("not valid key") } signer.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data)) }) } func FuzzRSAPKCS1v15SignerVerfier(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { f := fuzz.NewConsumer(data) x := rsa.PrivateKey{} f.GenerateStruct(&x) signer, err := signature.LoadRSAPKCS1v15Signer(&x, crypto.SHA512) if err != nil { if signer != nil { t.Errorf("key %v is not nil when there is an error %v ", signer, err) } t.Skip("not valid key") } sig, err := signer.SignMessage(bytes.NewReader(data)) if err != nil { if sig != nil { t.Errorf("key %v is not nil when there is an error %v ", sig, err) } t.Skip("not valid key") } if _, err := signer.Sign(bytes.NewReader(data), data, nil); err != nil { t.Skip("not valid key") } }) } func FuzzRSAPSSSignerVerfier(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { privateKey, err := cryptoutils.UnmarshalPEMToPrivateKey(data, cryptoutils.SkipPassword) if err != nil { t.Skip() } signer, err := signature.LoadRSAPSSSignerVerifier(privateKey.(*rsa.PrivateKey), crypto.SHA512, nil) if err != nil { if signer != nil { t.Errorf("key %v is not nil when there is an error %v ", signer, err) } t.Skip("not valid key") } sig, err := signer.SignMessage(bytes.NewReader(data)) if err != nil { if sig != nil { t.Errorf("key %v is not nil when there is an error %v ", sig, err) } t.Skip("not valid key") } if _, err := signer.Sign(bytes.NewReader(data), data, nil); err != nil { t.Skip("not valid key") } }) } sigstore-1.8.6/test/fuzz/tools.go000066400000000000000000000015751463713551000170460ustar00rootroot00000000000000//go:build tools // +build tools // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This package imports things required by build scripts, to force `go mod` to see them as dependencies package fuzz import ( _ "github.com/AdaLogics/go-fuzz-headers" _ "github.com/dvyukov/go-fuzz/go-fuzz" _ "github.com/dvyukov/go-fuzz/go-fuzz-build" )