diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7470ed3b..9b831a90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,8 +20,8 @@ jobs: ci: uses: smallstep/workflows/.github/workflows/goCI.yml@main with: - os-dependencies: "libpcsclite-dev" - run-gitleaks: true + only-latest-golang: false + os-dependencies: 'libpcsclite-dev' run-codeql: true - make-test: true # run `make test` instead of the default test workflow + test-command: 'V=1 make test' secrets: inherit diff --git a/.github/workflows/code-scan-cron.yml b/.github/workflows/code-scan-cron.yml index 56969c11..9a35b7fe 100644 --- a/.github/workflows/code-scan-cron.yml +++ b/.github/workflows/code-scan-cron.yml @@ -5,5 +5,3 @@ on: jobs: code-scan: uses: smallstep/workflows/.github/workflows/code-scan.yml@main - secrets: - GITLEAKS_LICENSE_KEY: ${{ secrets.GITLEAKS_LICENSE_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 621f6a91..37fe2c2e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,38 +55,12 @@ jobs: prerelease: ${{ steps.is_prerelease.outputs.IS_PRERELEASE }} goreleaser: - name: Upload Assets To Github w/ goreleaser - runs-on: ubuntu-latest needs: create_release permissions: id-token: write contents: write - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.19 - check-latest: true - - name: Install cosign - uses: sigstore/cosign-installer@v2 - with: - cosign-release: 'v1.13.1' - - name: Get Release Date - id: release_date - run: | - RELEASE_DATE=$(date +"%y-%m-%d") - echo "RELEASE_DATE=${RELEASE_DATE}" >> ${GITHUB_ENV} - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v3 - with: - version: 'latest' - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.GORELEASER_PAT }} - RELEASE_DATE: ${{ env.RELEASE_DATE }} - COSIGN_EXPERIMENTAL: 1 + uses: smallstep/workflows/.github/workflows/goreleaser.yml@main + secrets: inherit build_upload_docker: name: Build & Upload Docker Images diff --git a/.gitleaksignore b/.gitleaksignore deleted file mode 100644 index 71318c8a..00000000 --- a/.gitleaksignore +++ /dev/null @@ -1,18 +0,0 @@ -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:85 -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:107 -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:108 -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:129 -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:131 -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:136 -deac15327f5605a1a963e50818760a95cee9d882:docs/kms.md:generic-api-key:138 -7c9ab9814fb676cb3c125c3dac4893271f1b7ae5:README.md:generic-api-key:282 -fb7140444ac8f1fa1245a80e49d17e206f7435f3:docs/provisioners.md:generic-api-key:110 -e4de7f07e82118b3f926716666b620db058fa9f7:docs/revocation.md:generic-api-key:73 -e4de7f07e82118b3f926716666b620db058fa9f7:docs/revocation.md:generic-api-key:113 -e4de7f07e82118b3f926716666b620db058fa9f7:docs/revocation.md:generic-api-key:151 -8b2de42e9cf6ce99f53a5049881e1d6077d5d66e:docs/docker.md:generic-api-key:152 -3939e855264117e81531df777a642ea953d325a7:autocert/init/ca/intermediate_ca_key:private-key:1 -e72f08703753facfa05f2d8c68f9f6a3745824b8:README.md:generic-api-key:244 -e70a5dae7de0b6ca40a0393c09c28872d4cfa071:autocert/README.md:generic-api-key:365 -e70a5dae7de0b6ca40a0393c09c28872d4cfa071:autocert/README.md:generic-api-key:366 -c284a2c0ab1c571a46443104be38c873ef0c7c6d:config.json:generic-api-key:10 diff --git a/.goreleaser.yml b/.goreleaser.yml index c296092d..255659db 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -31,12 +31,11 @@ builds: - -w -X main.Version={{.Version}} -X main.BuildTime={{.Date}} archives: - - + - &ARCHIVE # Can be used to change the archive formats for specific GOOSs. # Most common use case is to archive as zip on Windows. # Default is empty. name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Version }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" - rlcp: true format_overrides: - goos: windows format: zip @@ -45,6 +44,11 @@ archives: - README.md - LICENSE allow_different_binary_count: true + - + << : *ARCHIVE + id: unversioned + name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" + nfpms: # Configure nFPM for .deb and .rpm releases @@ -56,7 +60,7 @@ nfpms: # List file contents: dpkg -c dist/step_...deb # Package metadata: dpkg --info dist/step_....deb # - - + - &NFPM builds: - step-ca package_name: step-ca @@ -76,10 +80,13 @@ nfpms: contents: - src: debian/copyright dst: /usr/share/doc/step-ca/copyright + - + << : *NFPM + id: unversioned + file_name_template: "{{ .PackageName }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" source: enabled: true - rlcp: true name_template: '{{ .ProjectName }}_{{ .Version }}' checksum: @@ -132,17 +139,17 @@ release: #### Linux - - 📦 [step-ca_linux_{{ .Version }}_amd64.tar.gz](https://dl.step.sm/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_linux_{{ .Version }}_amd64.tar.gz) - - 📦 [step-ca_{{ .Version }}_amd64.deb](https://dl.step.sm/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_{{ .Version }}_amd64.deb) + - 📦 [step-ca_linux_{{ .Version }}_amd64.tar.gz](https://dl.smallstep.com/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_linux_{{ .Version }}_amd64.tar.gz) + - 📦 [step-ca_{{ .Version }}_amd64.deb](https://dl.smallstep.com/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_{{ .Version }}_amd64.deb) #### OSX Darwin - - 📦 [step-ca_darwin_{{ .Version }}_amd64.tar.gz](https://dl.step.sm/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_darwin_{{ .Version }}_amd64.tar.gz) - - 📦 [step-ca_darwin_{{ .Version }}_arm64.tar.gz](https://dl.step.sm/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_darwin_{{ .Version }}_arm64.tar.gz) + - 📦 [step-ca_darwin_{{ .Version }}_amd64.tar.gz](https://dl.smallstep.com/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_darwin_{{ .Version }}_amd64.tar.gz) + - 📦 [step-ca_darwin_{{ .Version }}_arm64.tar.gz](https://dl.smallstep.com/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_darwin_{{ .Version }}_arm64.tar.gz) #### Windows - - 📦 [step-ca_windows_{{ .Version }}_amd64.zip](https://dl.step.sm/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_windows_{{ .Version }}_amd64.zip) + - 📦 [step-ca_windows_{{ .Version }}_amd64.zip](https://dl.smallstep.com/gh-release/certificates/gh-release-header/{{ .Tag }}/step-ca_windows_{{ .Version }}_amd64.zip) For more builds across platforms and architectures, see the `Assets` section below. And for packaged versions (Docker, k8s, Homebrew), see our [installation docs](https://smallstep.com/docs/step-ca/installation). @@ -157,11 +164,11 @@ release: ``` cosign verify-blob \ - --certificate ~/Downloads/step-ca_darwin_{{ .Version }}_amd64.tar.gz.sig.pem \ - --signature ~/Downloads/step-ca_darwin_{{ .Version }}_amd64.tar.gz.sig \ - --certificate-identity-regexp "https://github\.com/smallstep/certificates/.*" \ + --certificate step-ca_darwin_{{ .Version }}_amd64.tar.gz.sig.pem \ + --signature step-ca_darwin_{{ .Version }}_amd64.tar.gz.sig \ + --certificate-identity-regexp "https://github\.com/smallstep/workflows/.*" \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - ~/Downloads/step-ca_darwin_{{ .Version }}_amd64.tar.gz + step-ca_darwin_{{ .Version }}_amd64.tar.gz ``` The `checksums.txt` file (in the `Assets` section below) contains a checksum for every artifact in the release. @@ -190,39 +197,159 @@ release: # - glob: ./glob/**/to/**/file/**/* # - glob: ./glob/foo/to/bar/file/foobar/override_from_previous -scoop: - # Template for the url which is determined by the given Token (github or gitlab) - # Default for github is "https://github.com///releases/download/{{ .Tag }}/{{ .ArtifactName }}" - # Default for gitlab is "https://gitlab.com///uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}" - # Default for gitea is "https://gitea.com///releases/download/{{ .Tag }}/{{ .ArtifactName }}" - url_template: "http://github.com/smallstep/certificates/releases/download/{{ .Tag }}/{{ .ArtifactName }}" - - # Repository to push the app manifest to. - bucket: - owner: smallstep - name: scoop-bucket - - # Git author used to commit to the repository. - # Defaults are shown. - commit_author: - name: goreleaserbot - email: goreleaser@smallstep.com - - # The project name and current git tag are used in the format string. - commit_msg_template: "Scoop update for {{ .ProjectName }} version {{ .Tag }}" - - # Your app's homepage. - # Default is empty. - homepage: "https://smallstep.com/docs/step-ca" +winget: + - + # IDs of the archives to use. + # Empty means all IDs. + ids: [ default ] + + # + # Default: ProjectName + # Templates: allowed + name: step-ca + + # Publisher name. + # + # Templates: allowed + # Required. + publisher: Smallstep + + # Your app's description. + # + # Templates: allowed + # Required. + short_description: "A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management." + + # License name. + # + # Templates: allowed + # Required. + license: "Apache-2.0" + + # Publisher URL. + # + # Templates: allowed + publisher_url: "https://smallstep.com" + + # Publisher support URL. + # + # Templates: allowed + publisher_support_url: "https://github.com/smallstep/certificates/discussions" + + # URL which is determined by the given Token (github, gitlab or gitea). + # + # Default depends on the client. + # Templates: allowed + url_template: "https://github.com/smallstep/certificates/releases/download/{{ .Tag }}/{{ .ArtifactName }}" + + # Git author used to commit to the repository. + commit_author: + name: goreleaserbot + email: goreleaser@smallstep.com + + # The project name and current git tag are used in the format string. + # + # Templates: allowed + commit_msg_template: "{{ .PackageIdentifier }}: {{ .Tag }}" + + # Your app's homepage. + homepage: "https://github.com/smallstep/certificates" + + # Your app's long description. + # + # Templates: allowed + description: "" + + # License URL. + # + # Templates: allowed + license_url: "https://github.com/smallstep/certificates/blob/master/LICENSE" + + # Release notes URL. + # + # Templates: allowed + release_notes_url: "https://github.com/smallstep/certificates/releases/tag/{{.Version}}" + + # Create the PR - for testing + skip_upload: auto + + # Tags. + tags: + - certificates + - smallstep + - tls + + # Repository to push the generated files to. + repository: + owner: smallstep + name: winget-pkgs + branch: step + + # Optionally a token can be provided, if it differs from the token + # provided to GoReleaser + # Templates: allowed + #token: "{{ .Env.GITHUB_PERSONAL_AUTH_TOKEN }}" + + # Sets up pull request creation instead of just pushing to the given branch. + # Make sure the 'branch' property is different from base before enabling + # it. + # + # Since: v1.17 + pull_request: + # Whether to enable it or not. + enabled: true + check_boxes: true + # Whether to open the PR as a draft or not. + # + # Default: false + # Since: v1.19 + # draft: true + + # Base can also be another repository, in which case the owner and name + # above will be used as HEAD, allowing cross-repository pull requests. + # + # Since: v1.19 + base: + owner: microsoft + name: winget-pkgs + branch: master + + +scoops: + - + ids: [ default ] + # Template for the url which is determined by the given Token (github or gitlab) + # Default for github is "https://github.com///releases/download/{{ .Tag }}/{{ .ArtifactName }}" + # Default for gitlab is "https://gitlab.com///uploads/{{ .ArtifactUploadHash }}/{{ .ArtifactName }}" + # Default for gitea is "https://gitea.com///releases/download/{{ .Tag }}/{{ .ArtifactName }}" + url_template: "http://github.com/smallstep/certificates/releases/download/{{ .Tag }}/{{ .ArtifactName }}" + # Repository to push the app manifest to. + repository: + owner: smallstep + name: scoop-bucket + branch: main + + # Git author used to commit to the repository. + # Defaults are shown. + commit_author: + name: goreleaserbot + email: goreleaser@smallstep.com + + # The project name and current git tag are used in the format string. + commit_msg_template: "Scoop update for {{ .ProjectName }} version {{ .Tag }}" + + # Your app's homepage. + # Default is empty. + homepage: "https://smallstep.com/docs/step-ca" - # Skip uploads for prerelease. - skip_upload: auto + # Skip uploads for prerelease. + skip_upload: auto - # Your app's description. - # Default is empty. - description: "A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH." + # Your app's description. + # Default is empty. + description: "A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH." - # Your app's license - # Default is empty. - license: "Apache-2.0" + # Your app's license + # Default is empty. + license: "Apache-2.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index a7c85936..4e0a92a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,89 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. --- +## [0.25.0] - 2023-09-26 + +### Added + +- Added support for configuring SCEP decrypters in the provisioner (smallstep/certificates#1414) +- Added support for TPM KMS (smallstep/crypto#253) +- Added support for disableSmallstepExtensions provisioner claim + (smallstep/certificates#1484) +- Added script to migrate a badger DB to MySQL or PostgreSQL + (smallstep/certificates#1477) +- Added AWS public certificates for me-central-1 and ap-southeast-3 + (smallstep/certificates#1404) +- Added namespace field to VaultCAS JSON config (smallstep/certificates#1424) +- Added AWS public certificates for me-central-1 and ap-southeast-3 + (smallstep/certificates#1404) +- Added unversioned filenames to Github release assets + (smallstep/certificates#1435) +- Send X5C leaf certificate to webhooks (smallstep/certificates#1485) +- Added support for disableSmallstepExtensions claim (smallstep/certificates#1484) +- Added all AWS Identity Document Certificates (smallstep/certificates#1404, smallstep/certificates#1510) +- Added Winget release automation (smallstep/certificates#1519) +- Added CSR to SCEPCHALLENGE webhook request body (smallstep/certificates#1523) +- Added SCEP issuance notification webhook (smallstep/certificates#1544) +- Added ability to disable color in the log text formatter + (smallstep/certificates(#1559) + +### Changed + +- Changed the Makefile to produce cgo-enabled builds running + `make build GO_ENVS="CGO_ENABLED=1"` (smallstep/certificates#1446) +- Return more detailed errors to ACME clients using device-attest-01 + (smallstep/certificates#1495) +- Change SCEP password type to string (smallstep/certificates#1555) + +### Removed + +- Removed OIDC user regexp check (smallstep/certificates#1481) +- Removed automatic initialization of $STEPPATH (smallstep/certificates#1493) +- Removed db datasource from error msg to prevent leaking of secrets to logs + (smallstep/certificates#1528) + +### Fixed + +- Improved authentication for ACME requests using kid and provisioner name + (smallstep/certificates#1386). +- Fixed indentation of KMS configuration in helm charts + (smallstep/certificates#1405) +- Fixed simultaneous sign or decrypt operation on a YubiKey + (smallstep/certificates#1476, smallstep/crypto#288) +- Fixed adding certificate templates with ASN.1 functions + (smallstep/certificates#1500, smallstep/crypto#302) +- Fixed a problem when the ca.json is truncated if the encoding of the + configuration fails (e.g., new provisioner with bad template data) + (smallstep/cli#994, smallstep/certificates#1501) +- Fixed provisionerOptionsToLinkedCA missing template and templateData + (smallstep/certificates#1520) +- Fix calculation of webhook signature (smallstep/certificates#1546) + +## [v0.24.2] - 2023-05-11 + +### Added + +- Log SSH certificates (smallstep/certificates#1374) +- CRL endpoints on the HTTP server (smallstep/certificates#1372) +- Dynamic SCEP challenge validation using webhooks (smallstep/certificates#1366) +- For Docker deployments, added DOCKER_STEPCA_INIT_PASSWORD_FILE. Useful for pointing to a Docker Secret in the container (smallstep/certificates#1384) + +### Changed + +- Depend on [smallstep/go-attestation](https://github.com/smallstep/go-attestation) instead of [google/go-attestation](https://github.com/google/go-attestation) +- Render CRLs into http.ResponseWriter instead of memory (smallstep/certificates#1373) +- Redaction of SCEP static challenge when listing provisioners (smallstep/certificates#1204) + +### Fixed + +- VaultCAS certificate lifetime (smallstep/certificates#1376) + +## [v0.24.1] - 2023-04-14 + +### Fixed + +- Docker image name for HSM support (smallstep/certificates#1348) + ## [v0.24.0] - 2023-04-12 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 35f75159..2c13828e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,7 @@ sudo yum install pcsc-lite-devel To build `step-ca`, clone this repository and run the following: ```shell -make bootstrap && make build GOFLAGS="" +make bootstrap && make build GO_ENVS="CGO_ENABLED=1" ``` When the build is complete, you will find binaries in `bin/`. diff --git a/Makefile b/Makefile index 5d7995f4..630b54b9 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,23 @@ endif DATE := $(shell date -u '+%Y-%m-%d %H:%M UTC') LDFLAGS := -ldflags='-w -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"' -GOFLAGS := CGO_ENABLED=0 + +# Always explicitly enable or disable cgo, +# so that go doesn't silently fall back on +# non-cgo when gcc is not found. +ifeq (,$(findstring CGO_ENABLED,$(GO_ENVS))) + ifneq ($(origin GOFLAGS),undefined) + # This section is for backward compatibility with + # + # $ make build GOFLAGS="" + # + # which is how we recommended building step-ca with cgo support + # until June 2023. + GO_ENVS := $(GO_ENVS) CGO_ENABLED=1 + else + GO_ENVS := $(GO_ENVS) CGO_ENABLED=0 + endif +endif download: $Q go mod download @@ -71,7 +87,7 @@ build: $(PREFIX)bin/$(BINNAME) $(PREFIX)bin/$(BINNAME): download $(call rwildcard,*.go) $Q mkdir -p $(@D) - $Q $(GOOS_OVERRIDE) $(GOFLAGS) go build -v -o $(PREFIX)bin/$(BINNAME) $(LDFLAGS) $(PKG) + $Q $(GOOS_OVERRIDE) GOFLAGS="$(GOFLAGS)" $(GO_ENVS) go build -v -o $(PREFIX)bin/$(BINNAME) $(LDFLAGS) $(PKG) # Target to force a build of step-ca without running tests simple: build @@ -93,10 +109,10 @@ generate: test: testdefault testtpmsimulator combinecoverage testdefault: - $Q $(GOFLAGS) gotestsum -- -coverprofile=defaultcoverage.out -short -covermode=atomic ./... + $Q $(GO_ENVS) gotestsum -- -coverprofile=defaultcoverage.out -short -covermode=atomic ./... testtpmsimulator: - $Q CGO_ENALBED=1 gotestsum -- -coverprofile=tpmsimulatorcoverage.out -short -covermode=atomic -tags tpmsimulator ./acme + $Q CGO_ENABLED=1 gotestsum -- -coverprofile=tpmsimulatorcoverage.out -short -covermode=atomic -tags tpmsimulator ./acme testcgo: $Q gotestsum -- -coverprofile=coverage.out -short -covermode=atomic ./... @@ -109,7 +125,7 @@ combinecoverage: integrate: integration integration: bin/$(BINNAME) - $Q $(GOFLAGS) gotestsum -- -tags=integration ./integration/... + $Q $(GO_ENVS) gotestsum -- -tags=integration ./integration/... .PHONY: integrate integration diff --git a/README.md b/README.md index 9544e7cd..9b454f51 100644 --- a/README.md +++ b/README.md @@ -119,18 +119,12 @@ See our installation docs [here](https://smallstep.com/docs/step-ca/installation ## Documentation -Documentation can be found in a handful of different places: - -1. On the web at https://smallstep.com/docs/step-ca. - -2. On the command line with `step help ca xxx` where `xxx` is the subcommand -you are interested in. Ex: `step help ca provisioner list`. - -3. In your browser, by running `step help --http=:8080 ca` from the command line +* [Official documentation](https://smallstep.com/docs/step-ca) is on smallstep.com +* The `step` command reference is available via `step help`, +[on smallstep.com](https://smallstep.com/docs/step-cli/reference/), +or by running `step help --http=:8080` from the command line and visiting http://localhost:8080. -4. The [docs](./docs/README.md) folder is being deprecated, but it still has some documentation and tutorials. - ## Feedback? * Tell us what you like and don't like about managing your PKI - we're eager to help solve problems in this space. diff --git a/acme/account.go b/acme/account.go index fa4b1167..38cca218 100644 --- a/acme/account.go +++ b/acme/account.go @@ -20,6 +20,16 @@ type Account struct { Status Status `json:"status"` OrdersURL string `json:"orders"` ExternalAccountBinding interface{} `json:"externalAccountBinding,omitempty"` + LocationPrefix string `json:"-"` + ProvisionerName string `json:"-"` +} + +// GetLocation returns the URL location of the given account. +func (a *Account) GetLocation() string { + if a.LocationPrefix == "" { + return "" + } + return a.LocationPrefix + a.ID } // ToLog enables response logging. @@ -72,6 +82,7 @@ func (p *Policy) GetAllowedNameOptions() *policy.X509NameOptions { IPRanges: p.X509.Allowed.IPRanges, } } + func (p *Policy) GetDeniedNameOptions() *policy.X509NameOptions { if p == nil { return nil diff --git a/acme/account_test.go b/acme/account_test.go index b8ce7276..d4122500 100644 --- a/acme/account_test.go +++ b/acme/account_test.go @@ -66,6 +66,23 @@ func TestKeyToID(t *testing.T) { } } +func TestAccount_GetLocation(t *testing.T) { + locationPrefix := "https://test.ca.smallstep.com/acme/foo/account/" + type test struct { + acc *Account + exp string + } + tests := map[string]test{ + "empty": {acc: &Account{LocationPrefix: ""}, exp: ""}, + "not-empty": {acc: &Account{ID: "bar", LocationPrefix: locationPrefix}, exp: locationPrefix + "bar"}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + assert.Equals(t, tc.acc.GetLocation(), tc.exp) + }) + } +} + func TestAccount_IsValid(t *testing.T) { type test struct { acc *Account diff --git a/acme/api/account.go b/acme/api/account.go index 954cb9de..25d923c7 100644 --- a/acme/api/account.go +++ b/acme/api/account.go @@ -1,11 +1,12 @@ package api import ( + "context" "encoding/json" "errors" "net/http" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/smallstep/certificates/acme" "github.com/smallstep/certificates/api/render" @@ -67,6 +68,12 @@ func (u *UpdateAccountRequest) Validate() error { } } +// getAccountLocationPath returns the current account URL location. +// Returned location will be of the form: https:///acme//account/ +func getAccountLocationPath(ctx context.Context, linker acme.Linker, accID string) string { + return linker.GetLink(ctx, acme.AccountLinkType, accID) +} + // NewAccount is the handler resource for creating new ACME accounts. func NewAccount(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -125,9 +132,11 @@ func NewAccount(w http.ResponseWriter, r *http.Request) { } acc = &acme.Account{ - Key: jwk, - Contact: nar.Contact, - Status: acme.StatusValid, + Key: jwk, + Contact: nar.Contact, + Status: acme.StatusValid, + LocationPrefix: getAccountLocationPath(ctx, linker, ""), + ProvisionerName: prov.GetName(), } if err := db.CreateAccount(ctx, acc); err != nil { render.Error(w, acme.WrapErrorISE(err, "error creating account")) @@ -152,7 +161,7 @@ func NewAccount(w http.ResponseWriter, r *http.Request) { linker.LinkAccount(ctx, acc) - w.Header().Set("Location", linker.GetLink(r.Context(), acme.AccountLinkType, acc.ID)) + w.Header().Set("Location", getAccountLocationPath(ctx, linker, acc.ID)) render.JSONStatus(w, acc, httpStatus) } diff --git a/acme/api/account_test.go b/acme/api/account_test.go index d46c9eed..7d799c88 100644 --- a/acme/api/account_test.go +++ b/acme/api/account_test.go @@ -7,12 +7,13 @@ import ( "encoding/json" "fmt" "io" + "net/http" "net/http/httptest" "net/url" "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" "go.step.sm/crypto/jose" @@ -34,31 +35,24 @@ var ( type fakeProvisioner struct{} -func (*fakeProvisioner) AuthorizeOrderIdentifier(ctx context.Context, identifier provisioner.ACMEIdentifier) error { +func (*fakeProvisioner) AuthorizeOrderIdentifier(context.Context, provisioner.ACMEIdentifier) error { return nil } - -func (*fakeProvisioner) AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error) { +func (*fakeProvisioner) AuthorizeSign(context.Context, string) ([]provisioner.SignOption, error) { return nil, nil } - -func (*fakeProvisioner) IsChallengeEnabled(ctx context.Context, challenge provisioner.ACMEChallenge) bool { +func (*fakeProvisioner) IsChallengeEnabled(context.Context, provisioner.ACMEChallenge) bool { return true } - -func (*fakeProvisioner) IsAttestationFormatEnabled(ctx context.Context, format provisioner.ACMEAttestationFormat) bool { +func (*fakeProvisioner) IsAttestationFormatEnabled(context.Context, provisioner.ACMEAttestationFormat) bool { return true } - -func (*fakeProvisioner) GetAttestationRoots() (*x509.CertPool, bool) { - return nil, false -} - -func (*fakeProvisioner) AuthorizeRevoke(ctx context.Context, token string) error { return nil } -func (*fakeProvisioner) GetID() string { return "" } -func (*fakeProvisioner) GetName() string { return "" } -func (*fakeProvisioner) DefaultTLSCertDuration() time.Duration { return 0 } -func (*fakeProvisioner) GetOptions() *provisioner.Options { return nil } +func (*fakeProvisioner) GetAttestationRoots() (*x509.CertPool, bool) { return nil, false } +func (*fakeProvisioner) AuthorizeRevoke(context.Context, string) error { return nil } +func (*fakeProvisioner) GetID() string { return "" } +func (*fakeProvisioner) GetName() string { return "" } +func (*fakeProvisioner) DefaultTLSCertDuration() time.Duration { return 0 } +func (*fakeProvisioner) GetOptions() *provisioner.Options { return nil } func newProv() acme.Provisioner { // Initialize provisioners @@ -320,7 +314,7 @@ func TestHandler_GetOrdersByAccountID(t *testing.T) { "fail/nil-account": func(t *testing.T) test { return test{ db: &acme.MockDB{}, - ctx: context.WithValue(context.Background(), accContextKey, nil), + ctx: context.WithValue(context.Background(), accContextKey, http.NoBody), statusCode: 400, err: acme.NewError(acme.ErrorAccountDoesNotExistType, "account does not exist"), } @@ -370,7 +364,7 @@ func TestHandler_GetOrdersByAccountID(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewContext(tc.ctx, tc.db, nil, acme.NewLinker("test.ca.smallstep.com", "acme"), nil) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetOrdersByAccountID(w, req) @@ -809,7 +803,7 @@ func TestHandler_NewAccount(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewContext(tc.ctx, tc.db, nil, acme.NewLinker("test.ca.smallstep.com", "acme"), nil) - req := httptest.NewRequest("GET", "/foo/bar", nil) + req := httptest.NewRequest("GET", "/foo/bar", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() NewAccount(w, req) @@ -1012,7 +1006,7 @@ func TestHandler_GetOrUpdateAccount(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewContext(tc.ctx, tc.db, nil, acme.NewLinker("test.ca.smallstep.com", "acme"), nil) - req := httptest.NewRequest("GET", "/foo/bar", nil) + req := httptest.NewRequest("GET", "/foo/bar", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetOrUpdateAccount(w, req) diff --git a/acme/api/handler.go b/acme/api/handler.go index e6aad131..d2940f49 100644 --- a/acme/api/handler.go +++ b/acme/api/handler.go @@ -9,7 +9,7 @@ import ( "net/http" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/smallstep/certificates/acme" "github.com/smallstep/certificates/api" @@ -273,7 +273,7 @@ func shouldAddMetaObject(p *provisioner.ACME) bool { // NotImplemented returns a 501 and is generally a placeholder for functionality which // MAY be added at some point in the future but is not in any way a guarantee of such. -func NotImplemented(w http.ResponseWriter, r *http.Request) { +func NotImplemented(w http.ResponseWriter, _ *http.Request) { render.Error(w, acme.NewError(acme.ErrorNotImplementedType, "this API is not implemented")) } diff --git a/acme/api/handler_test.go b/acme/api/handler_test.go index 7ef7cd68..bd7bb50e 100644 --- a/acme/api/handler_test.go +++ b/acme/api/handler_test.go @@ -15,7 +15,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" @@ -60,7 +60,7 @@ func TestHandler_GetNonce(t *testing.T) { } // Request with chi context - req := httptest.NewRequest("GET", "http://ca.smallstep.com/nonce", nil) + req := httptest.NewRequest("GET", "http://ca.smallstep.com/nonce", http.NoBody) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -175,7 +175,7 @@ func TestHandler_GetDirectory(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewLinkerContext(tc.ctx, acme.NewLinker("test.ca.smallstep.com", "acme")) - req := httptest.NewRequest("GET", "/foo/bar", nil) + req := httptest.NewRequest("GET", "/foo/bar", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetDirectory(w, req) @@ -347,7 +347,7 @@ func TestHandler_GetAuthorization(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewContext(tc.ctx, tc.db, nil, acme.NewLinker("test.ca.smallstep.com", "acme"), nil) - req := httptest.NewRequest("GET", "/foo/bar", nil) + req := httptest.NewRequest("GET", "/foo/bar", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetAuthorization(w, req) @@ -489,7 +489,7 @@ func TestHandler_GetCertificate(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewDatabaseContext(tc.ctx, tc.db) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetCertificate(w, req) @@ -747,7 +747,7 @@ func TestHandler_GetChallenge(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewContext(tc.ctx, tc.db, nil, acme.NewLinker("test.ca.smallstep.com", "acme"), nil) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetChallenge(w, req) diff --git a/acme/api/middleware.go b/acme/api/middleware.go index 5dcb93e3..ab2ab908 100644 --- a/acme/api/middleware.go +++ b/acme/api/middleware.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "net/url" + "path" "strings" "go.step.sm/crypto/jose" @@ -16,7 +17,6 @@ import ( "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/logging" - "github.com/smallstep/nosql" ) type nextHTTP = func(http.ResponseWriter, *http.Request) @@ -293,7 +293,6 @@ func lookupJWK(next nextHTTP) nextHTTP { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() db := acme.MustDatabaseFromContext(ctx) - linker := acme.MustLinkerFromContext(ctx) jws, err := jwsFromContext(ctx) if err != nil { @@ -301,19 +300,16 @@ func lookupJWK(next nextHTTP) nextHTTP { return } - kidPrefix := linker.GetLink(ctx, acme.AccountLinkType, "") kid := jws.Signatures[0].Protected.KeyID - if !strings.HasPrefix(kid, kidPrefix) { - render.Error(w, acme.NewError(acme.ErrorMalformedType, - "kid does not have required prefix; expected %s, but got %s", - kidPrefix, kid)) + if kid == "" { + render.Error(w, acme.NewError(acme.ErrorMalformedType, "signature missing 'kid'")) return } - accID := strings.TrimPrefix(kid, kidPrefix) + accID := path.Base(kid) acc, err := db.GetAccount(ctx, accID) switch { - case nosql.IsErrNotFound(err): + case acme.IsErrNotFound(err): render.Error(w, acme.NewError(acme.ErrorAccountDoesNotExistType, "account with ID '%s' not found", accID)) return case err != nil: @@ -324,6 +320,45 @@ func lookupJWK(next nextHTTP) nextHTTP { render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account is not active")) return } + + if storedLocation := acc.GetLocation(); storedLocation != "" { + if kid != storedLocation { + // ACME accounts should have a stored location equivalent to the + // kid in the ACME request. + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, + "kid does not match stored account location; expected %s, but got %s", + storedLocation, kid)) + return + } + + // Verify that the provisioner with which the account was created + // matches the provisioner in the request URL. + reqProv := acme.MustProvisionerFromContext(ctx) + reqProvName := reqProv.GetName() + accProvName := acc.ProvisionerName + if reqProvName != accProvName { + // Provisioner in the URL must match the provisioner with + // which the account was created. + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, + "account provisioner does not match requested provisioner; account provisioner = %s, requested provisioner = %s", + accProvName, reqProvName)) + return + } + } else { + // This code will only execute for old ACME accounts that do + // not have a cached location. The following validation was + // the original implementation of the `kid` check which has + // since been deprecated. However, the code will remain to + // ensure consistent behavior for old ACME accounts. + linker := acme.MustLinkerFromContext(ctx) + kidPrefix := linker.GetLink(ctx, acme.AccountLinkType, "") + if !strings.HasPrefix(kid, kidPrefix) { + render.Error(w, acme.NewError(acme.ErrorMalformedType, + "kid does not have required prefix; expected %s, but got %s", + kidPrefix, kid)) + return + } + } ctx = context.WithValue(ctx, accContextKey, acc) ctx = context.WithValue(ctx, jwkContextKey, acc.Key) next(w, r.WithContext(ctx)) diff --git a/acme/api/middleware_test.go b/acme/api/middleware_test.go index 3db3773c..90190bc7 100644 --- a/acme/api/middleware_test.go +++ b/acme/api/middleware_test.go @@ -17,14 +17,13 @@ import ( "github.com/pkg/errors" "github.com/smallstep/assert" "github.com/smallstep/certificates/acme" - "github.com/smallstep/nosql/database" "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" ) var testBody = []byte("foo") -func testNext(w http.ResponseWriter, r *http.Request) { +func testNext(w http.ResponseWriter, _ *http.Request) { w.Write(testBody) } @@ -76,7 +75,7 @@ func TestHandler_addNonce(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(context.Background(), tc.db) - req := httptest.NewRequest("GET", u, nil).WithContext(ctx) + req := httptest.NewRequest("GET", u, http.NoBody).WithContext(ctx) w := httptest.NewRecorder() addNonce(testNext)(w, req) res := w.Result() @@ -128,7 +127,7 @@ func TestHandler_addDirLink(t *testing.T) { for name, run := range tests { tc := run(t) t.Run(name, func(t *testing.T) { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req = req.WithContext(tc.ctx) w := httptest.NewRecorder() addDirLink(testNext)(w, req) @@ -231,7 +230,7 @@ func TestHandler_verifyContentType(t *testing.T) { if tc.url != "" { _u = tc.url } - req := httptest.NewRequest("GET", _u, nil) + req := httptest.NewRequest("GET", _u, http.NoBody) req = req.WithContext(tc.ctx) req.Header.Add("Content-Type", tc.contentType) w := httptest.NewRecorder() @@ -299,7 +298,7 @@ func TestHandler_isPostAsGet(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { // h := &Handler{} - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(tc.ctx) w := httptest.NewRecorder() isPostAsGet(testNext)(w, req) @@ -328,7 +327,7 @@ func TestHandler_isPostAsGet(t *testing.T) { type errReader int -func (errReader) Read(p []byte) (n int, err error) { +func (errReader) Read([]byte) (int, error) { return 0, errors.New("force") } func (errReader) Close() error { @@ -583,7 +582,7 @@ func TestHandler_verifyAndExtractJWSPayload(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { // h := &Handler{} - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(tc.ctx) w := httptest.NewRecorder() verifyAndExtractJWSPayload(tc.next)(w, req) @@ -678,31 +677,7 @@ func TestHandler_lookupJWK(t *testing.T) { linker: acme.NewLinker("test.ca.smallstep.com", "acme"), ctx: ctx, statusCode: 400, - err: acme.NewError(acme.ErrorMalformedType, "kid does not have required prefix; expected %s, but got ", prefix), - } - }, - "fail/bad-kid-prefix": func(t *testing.T) test { - _so := new(jose.SignerOptions) - _so.WithHeader("kid", "foo") - _signer, err := jose.NewSigner(jose.SigningKey{ - Algorithm: jose.SignatureAlgorithm(jwk.Algorithm), - Key: jwk.Key, - }, _so) - assert.FatalError(t, err) - _jws, err := _signer.Sign([]byte("baz")) - assert.FatalError(t, err) - _raw, err := _jws.CompactSerialize() - assert.FatalError(t, err) - _parsed, err := jose.ParseJWS(_raw) - assert.FatalError(t, err) - ctx := acme.NewProvisionerContext(context.Background(), prov) - ctx = context.WithValue(ctx, jwsContextKey, _parsed) - return test{ - db: &acme.MockDB{}, - linker: acme.NewLinker("test.ca.smallstep.com", "acme"), - ctx: ctx, - statusCode: 400, - err: acme.NewError(acme.ErrorMalformedType, "kid does not have required prefix; expected %s, but got foo", prefix), + err: acme.NewError(acme.ErrorMalformedType, "signature missing 'kid'"), } }, "fail/account-not-found": func(t *testing.T) test { @@ -713,7 +688,7 @@ func TestHandler_lookupJWK(t *testing.T) { db: &acme.MockDB{ MockGetAccount: func(ctx context.Context, accID string) (*acme.Account, error) { assert.Equals(t, accID, accID) - return nil, database.ErrNotFound + return nil, acme.ErrNotFound }, }, ctx: ctx, @@ -754,7 +729,77 @@ func TestHandler_lookupJWK(t *testing.T) { err: acme.NewError(acme.ErrorUnauthorizedType, "account is not active"), } }, - "ok": func(t *testing.T) test { + "fail/account-with-location-prefix/bad-kid": func(t *testing.T) test { + acc := &acme.Account{LocationPrefix: "foobar", Status: "valid"} + ctx := acme.NewProvisionerContext(context.Background(), prov) + ctx = context.WithValue(ctx, jwsContextKey, parsedJWS) + return test{ + linker: acme.NewLinker("test.ca.smallstep.com", "acme"), + db: &acme.MockDB{ + MockGetAccount: func(ctx context.Context, id string) (*acme.Account, error) { + assert.Equals(t, id, accID) + return acc, nil + }, + }, + ctx: ctx, + statusCode: http.StatusUnauthorized, + err: acme.NewError(acme.ErrorUnauthorizedType, "kid does not match stored account location; expected foobar, but %q", prefix+accID), + } + }, + "fail/account-with-location-prefix/bad-provisioner": func(t *testing.T) test { + acc := &acme.Account{LocationPrefix: prefix + accID, Status: "valid", Key: jwk, ProvisionerName: "other"} + ctx := acme.NewProvisionerContext(context.Background(), prov) + ctx = context.WithValue(ctx, jwsContextKey, parsedJWS) + return test{ + linker: acme.NewLinker("test.ca.smallstep.com", "acme"), + db: &acme.MockDB{ + MockGetAccount: func(ctx context.Context, id string) (*acme.Account, error) { + assert.Equals(t, id, accID) + return acc, nil + }, + }, + ctx: ctx, + next: func(w http.ResponseWriter, r *http.Request) { + _acc, err := accountFromContext(r.Context()) + assert.FatalError(t, err) + assert.Equals(t, _acc, acc) + _jwk, err := jwkFromContext(r.Context()) + assert.FatalError(t, err) + assert.Equals(t, _jwk, jwk) + w.Write(testBody) + }, + statusCode: http.StatusUnauthorized, + err: acme.NewError(acme.ErrorUnauthorizedType, + "account provisioner does not match requested provisioner; account provisioner = %s, reqested provisioner = %s", + prov.GetName(), "other"), + } + }, + "ok/account-with-location-prefix": func(t *testing.T) test { + acc := &acme.Account{LocationPrefix: prefix + accID, Status: "valid", Key: jwk, ProvisionerName: prov.GetName()} + ctx := acme.NewProvisionerContext(context.Background(), prov) + ctx = context.WithValue(ctx, jwsContextKey, parsedJWS) + return test{ + linker: acme.NewLinker("test.ca.smallstep.com", "acme"), + db: &acme.MockDB{ + MockGetAccount: func(ctx context.Context, id string) (*acme.Account, error) { + assert.Equals(t, id, accID) + return acc, nil + }, + }, + ctx: ctx, + next: func(w http.ResponseWriter, r *http.Request) { + _acc, err := accountFromContext(r.Context()) + assert.FatalError(t, err) + assert.Equals(t, _acc, acc) + _jwk, err := jwkFromContext(r.Context()) + assert.FatalError(t, err) + assert.Equals(t, _jwk, jwk) + w.Write(testBody) + }, + statusCode: http.StatusOK, + } + }, + "ok/account-without-location-prefix": func(t *testing.T) test { acc := &acme.Account{Status: "valid", Key: jwk} ctx := acme.NewProvisionerContext(context.Background(), prov) ctx = context.WithValue(ctx, jwsContextKey, parsedJWS) @@ -784,7 +829,7 @@ func TestHandler_lookupJWK(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db, tc.linker) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() lookupJWK(tc.next)(w, req) @@ -983,7 +1028,7 @@ func TestHandler_extractJWK(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() extractJWK(tc.next)(w, req) @@ -1358,7 +1403,7 @@ func TestHandler_validateJWS(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() validateJWS(tc.next)(w, req) @@ -1540,7 +1585,7 @@ func TestHandler_extractOrLookupJWK(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db, tc.linker) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() extractOrLookupJWK(tc.next)(w, req) @@ -1625,7 +1670,7 @@ func TestHandler_checkPrerequisites(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := acme.NewPrerequisitesCheckerContext(tc.ctx, tc.prerequisitesChecker) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() checkPrerequisites(tc.next)(w, req) diff --git a/acme/api/order.go b/acme/api/order.go index 0c81df76..b207f87c 100644 --- a/acme/api/order.go +++ b/acme/api/order.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "go.step.sm/crypto/randutil" "go.step.sm/crypto/x509util" diff --git a/acme/api/order_test.go b/acme/api/order_test.go index 9f03c547..36de975a 100644 --- a/acme/api/order_test.go +++ b/acme/api/order_test.go @@ -8,13 +8,14 @@ import ( "encoding/json" "fmt" "io" + "net/http" "net/http/httptest" "net/url" "reflect" "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" "go.step.sm/crypto/pemutil" @@ -468,7 +469,7 @@ func TestHandler_GetOrder(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db, acme.NewLinker("test.ca.smallstep.com", "acme")) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() GetOrder(w, req) @@ -1827,7 +1828,7 @@ func TestHandler_NewOrder(t *testing.T) { t.Run(name, func(t *testing.T) { mockMustAuthority(t, tc.ca) ctx := newBaseContext(tc.ctx, tc.db, acme.NewLinker("test.ca.smallstep.com", "acme")) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() NewOrder(w, req) @@ -2124,7 +2125,7 @@ func TestHandler_FinalizeOrder(t *testing.T) { tc := run(t) t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db, acme.NewLinker("test.ca.smallstep.com", "acme")) - req := httptest.NewRequest("GET", u, nil) + req := httptest.NewRequest("GET", u, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() FinalizeOrder(w, req) diff --git a/acme/api/revoke.go b/acme/api/revoke.go index a8b98f3f..270a9fbb 100644 --- a/acme/api/revoke.go +++ b/acme/api/revoke.go @@ -151,7 +151,7 @@ func RevokeCert(w http.ResponseWriter, r *http.Request) { // the identifiers in the certificate are extracted and compared against the (valid) Authorizations // that are stored for the ACME Account. If these sets match, the Account is considered authorized // to revoke the certificate. If this check fails, the client will receive an unauthorized error. -func isAccountAuthorized(ctx context.Context, dbCert *acme.Certificate, certToBeRevoked *x509.Certificate, account *acme.Account) *acme.Error { +func isAccountAuthorized(_ context.Context, dbCert *acme.Certificate, certToBeRevoked *x509.Certificate, account *acme.Account) *acme.Error { if !account.IsValid() { return wrapUnauthorizedError(certToBeRevoked, nil, fmt.Sprintf("account '%s' has status '%s'", account.ID, account.Status), nil) } diff --git a/acme/api/revoke_test.go b/acme/api/revoke_test.go index c4182400..1c472e6e 100644 --- a/acme/api/revoke_test.go +++ b/acme/api/revoke_test.go @@ -21,7 +21,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" "golang.org/x/crypto/ocsp" @@ -258,7 +258,7 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { // jwsFinal constructs the final JWS object. // Implementation taken from github.com/mholt/acmez, which seems to be based on // https://github.com/golang/crypto/blob/master/acme/jws.go. -func jwsFinal(sha crypto.Hash, sig []byte, phead, payload string) ([]byte, error) { +func jwsFinal(_ crypto.Hash, sig []byte, phead, payload string) ([]byte, error) { enc := struct { Protected string `json:"protected"` Payload string `json:"payload"` @@ -281,7 +281,7 @@ type mockCA struct { MockAreSANsallowed func(ctx context.Context, sans []string) error } -func (m *mockCA) Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { +func (m *mockCA) Sign(*x509.CertificateRequest, provisioner.SignOptions, ...provisioner.SignOption) ([]*x509.Certificate, error) { return nil, nil } @@ -1072,7 +1072,7 @@ func TestHandler_RevokeCert(t *testing.T) { t.Run(name, func(t *testing.T) { ctx := newBaseContext(tc.ctx, tc.db, acme.NewLinker("test.ca.smallstep.com", "acme")) mockMustAuthority(t, tc.ca) - req := httptest.NewRequest("POST", revokeURL, nil) + req := httptest.NewRequest("POST", revokeURL, http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() RevokeCert(w, req) @@ -1094,7 +1094,7 @@ func TestHandler_RevokeCert(t *testing.T) { assert.Equals(t, res.Header["Content-Type"], []string{"application/problem+json"}) } else { assert.True(t, bytes.Equal(bytes.TrimSpace(body), []byte{})) - assert.Equals(t, int64(0), req.ContentLength) + assert.Equals(t, int64(-1), req.ContentLength) assert.Equals(t, []string{fmt.Sprintf("<%s/acme/%s/directory>;rel=\"index\"", baseURL.String(), escProvName)}, res.Header["Link"]) } }) diff --git a/acme/challenge.go b/acme/challenge.go index a1d4067f..b8294ef0 100644 --- a/acme/challenge.go +++ b/acme/challenge.go @@ -26,10 +26,11 @@ import ( "time" "github.com/fxamacker/cbor/v2" - "github.com/google/go-attestation/attest" - "github.com/google/go-tpm/tpm2" + "github.com/google/go-tpm/legacy/tpm2" "golang.org/x/exp/slices" + "github.com/smallstep/go-attestation/attest" + "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" "go.step.sm/crypto/pemutil" @@ -379,13 +380,18 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose return WrapErrorISE(err, "error unmarshalling CBOR") } + format := att.Format prov := MustProvisionerFromContext(ctx) - if !prov.IsAttestationFormatEnabled(ctx, provisioner.ACMEAttestationFormat(att.Format)) { + if !prov.IsAttestationFormatEnabled(ctx, provisioner.ACMEAttestationFormat(format)) { + if format != "apple" && format != "step" && format != "tpm" { + return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "unsupported attestation object format %q", format)) + } + return storeError(ctx, db, ch, true, - NewError(ErrorBadAttestationStatementType, "attestation format %q is not enabled", att.Format)) + NewError(ErrorBadAttestationStatementType, "attestation format %q is not enabled", format)) } - switch att.Format { + switch format { case "apple": data, err := doAppleAttestationFormat(ctx, prov, ch, &att) if err != nil { @@ -398,11 +404,12 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose } return WrapErrorISE(err, "error validating attestation") } + // Validate nonce with SHA-256 of the token. if len(data.Nonce) != 0 { sum := sha256.Sum256([]byte(ch.Token)) if subtle.ConstantTimeCompare(data.Nonce, sum[:]) != 1 { - return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "challenge token does not match")) + return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "challenge token does not match")) } } @@ -411,7 +418,12 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose // // Note: We might want to use an external service for this. if data.UDID != ch.Value && data.SerialNumber != ch.Value { - return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "permanent identifier does not match")) + subproblem := NewSubproblemWithIdentifier( + ErrorRejectedIdentifierType, + Identifier{Type: "permanent-identifier", Value: ch.Value}, + "challenge identifier %q doesn't match any of the attested hardware identifiers %q", ch.Value, []string{data.UDID, data.SerialNumber}, + ) + return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem)) } // Update attestation key fingerprint to compare against the CSR @@ -435,11 +447,11 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose // Note: We might want to use an external service for this. if data.SerialNumber != ch.Value { subproblem := NewSubproblemWithIdentifier( - ErrorMalformedType, + ErrorRejectedIdentifierType, Identifier{Type: "permanent-identifier", Value: ch.Value}, "challenge identifier %q doesn't match the attested hardware identifier %q", ch.Value, data.SerialNumber, ) - return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem)) + return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem)) } // Update attestation key fingerprint to compare against the CSR @@ -448,8 +460,6 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose case "tpm": data, err := doTPMAttestationFormat(ctx, prov, ch, jwk, &att) if err != nil { - // TODO(hs): we should provide more details in the error reported to the client; - // "Attestation statement cannot be verified" is VERY generic. Also holds true for the other formats. var acmeError *Error if errors.As(err, &acmeError) { if acmeError.Status == 500 { @@ -467,17 +477,17 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose // still fail if the challenge value isn't equal to the CSR subject. if len(data.PermanentIdentifiers) > 0 && !slices.Contains(data.PermanentIdentifiers, ch.Value) { // TODO(hs): add support for HardwareModuleName subproblem := NewSubproblemWithIdentifier( - ErrorMalformedType, + ErrorRejectedIdentifierType, Identifier{Type: "permanent-identifier", Value: ch.Value}, "challenge identifier %q doesn't match any of the attested hardware identifiers %q", ch.Value, data.PermanentIdentifiers, ) - return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, "permanent identifier does not match").AddSubproblems(subproblem)) + return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem)) } // Update attestation key fingerprint to compare against the CSR az.Fingerprint = data.Fingerprint default: - return storeError(ctx, db, ch, true, NewError(ErrorBadAttestationStatementType, "unexpected attestation object format")) + return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "unsupported attestation object format %q", format)) } // Update and store the challenge. @@ -520,41 +530,41 @@ const ( coseAlgRS256 coseAlgorithmIdentifier = -257 ) -func doTPMAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *attestationObject) (*tpmAttestationData, error) { +func doTPMAttestationFormat(_ context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *attestationObject) (*tpmAttestationData, error) { ver, ok := att.AttStatement["ver"].(string) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "ver not present") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "ver not present") } if ver != "2.0" { - return nil, NewError(ErrorBadAttestationStatementType, "version %q is not supported", ver) + return nil, NewDetailedError(ErrorBadAttestationStatementType, "version %q is not supported", ver) } x5c, ok := att.AttStatement["x5c"].([]interface{}) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c not present") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c not present") } if len(x5c) == 0 { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is empty") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is empty") } akCertBytes, ok := x5c[0].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is malformed") } akCert, err := x509.ParseCertificate(akCertBytes) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is malformed") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is malformed") } intermediates := x509.NewCertPool() for _, v := range x5c[1:] { intCertBytes, vok := v.([]byte) if !vok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is malformed") } intCert, err := x509.ParseCertificate(intCertBytes) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is malformed") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is malformed") } intermediates.AddCert(intCert) } @@ -592,19 +602,19 @@ func doTPMAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, }) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is not valid") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is not valid") } // validate additional AK certificate requirements if err := validateAKCertificate(akCert); err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "AK certificate is not valid") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "AK certificate is not valid") } // TODO(hs): implement revocation check; Verify() doesn't perform CRL check nor OCSP lookup. sans, err := x509util.ParseSubjectAlternativeNames(akCert) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "failed parsing AK certificate Subject Alternative Names") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "failed parsing AK certificate Subject Alternative Names") } permanentIdentifiers := make([]string, len(sans.PermanentIdentifiers)) @@ -615,37 +625,37 @@ func doTPMAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge // extract and validate pubArea, sig, certInfo and alg properties from the request body pubArea, ok := att.AttStatement["pubArea"].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "invalid pubArea in attestation statement") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid pubArea in attestation statement") } if len(pubArea) == 0 { - return nil, NewError(ErrorBadAttestationStatementType, "pubArea is empty") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "pubArea is empty") } sig, ok := att.AttStatement["sig"].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "invalid sig in attestation statement") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid sig in attestation statement") } if len(sig) == 0 { - return nil, NewError(ErrorBadAttestationStatementType, "sig is empty") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "sig is empty") } certInfo, ok := att.AttStatement["certInfo"].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "invalid certInfo in attestation statement") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid certInfo in attestation statement") } if len(certInfo) == 0 { - return nil, NewError(ErrorBadAttestationStatementType, "certInfo is empty") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "certInfo is empty") } alg, ok := att.AttStatement["alg"].(int64) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "invalid alg in attestation statement") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid alg in attestation statement") } // only RS256 and ES256 are allowed coseAlg := coseAlgorithmIdentifier(alg) if coseAlg != coseAlgRS256 && coseAlg != coseAlgES256 { - return nil, NewError(ErrorBadAttestationStatementType, "invalid alg %d in attestation statement", alg) + return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid alg %d in attestation statement", alg) } // set the hash algorithm to use to SHA256 @@ -663,36 +673,36 @@ func doTPMAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge Hash: hash, } if err = certificationParameters.Verify(verifyOpts); err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "invalid certification parameters") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "invalid certification parameters") } // decode the "certInfo" data. This won't fail, as it's also done as part of Verify(). tpmCertInfo, err := tpm2.DecodeAttestationData(certInfo) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "failed decoding attestation data") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "failed decoding attestation data") } keyAuth, err := KeyAuthorization(ch.Token, jwk) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "failed creating key auth digest") + return nil, WrapErrorISE(err, "failed creating key auth digest") } hashedKeyAuth := sha256.Sum256([]byte(keyAuth)) // verify the WebAuthn object contains the expect key authorization digest, which is carried // within the encoded `certInfo` property of the attestation statement. if subtle.ConstantTimeCompare(hashedKeyAuth[:], []byte(tpmCertInfo.ExtraData)) == 0 { - return nil, NewError(ErrorBadAttestationStatementType, "key authorization does not match") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "key authorization invalid") } // decode the (attested) public key and determine its fingerprint. This won't fail, as it's also done as part of Verify(). pub, err := tpm2.DecodePublic(pubArea) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "failed decoding pubArea") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "failed decoding pubArea") } publicKey, err := pub.Key() if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "failed getting public key") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "failed getting public key") } data := &tpmAttestationData{ @@ -742,11 +752,7 @@ func validateAKCertificate(c *x509.Certificate) error { if err := validateAKCertificateExtendedKeyUsage(c); err != nil { return err } - if err := validateAKCertificateSubjectAlternativeNames(c); err != nil { - return err - } - - return nil + return validateAKCertificateSubjectAlternativeNames(c) } // validateAKCertificateSubjectAlternativeNames checks if the AK certificate @@ -828,7 +834,7 @@ type appleAttestationData struct { Fingerprint string } -func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, att *attestationObject) (*appleAttestationData, error) { +func doAppleAttestationFormat(_ context.Context, prov Provisioner, _ *Challenge, att *attestationObject) (*appleAttestationData, error) { // Use configured or default attestation roots if none is configured. roots, ok := prov.GetAttestationRoots() if !ok { @@ -842,30 +848,30 @@ func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challen x5c, ok := att.AttStatement["x5c"].([]interface{}) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c not present") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c not present") } if len(x5c) == 0 { - return nil, NewError(ErrorRejectedIdentifierType, "x5c is empty") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is empty") } der, ok := x5c[0].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is malformed") } leaf, err := x509.ParseCertificate(der) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is malformed") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is malformed") } intermediates := x509.NewCertPool() for _, v := range x5c[1:] { der, ok = v.([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is malformed") } cert, err := x509.ParseCertificate(der) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is malformed") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is malformed") } intermediates.AddCert(cert) } @@ -876,7 +882,7 @@ func doAppleAttestationFormat(ctx context.Context, prov Provisioner, ch *Challen CurrentTime: time.Now().Truncate(time.Second), KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, }); err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is not valid") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is not valid") } data := &appleAttestationData{ @@ -933,7 +939,7 @@ type stepAttestationData struct { Fingerprint string } -func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *attestationObject) (*stepAttestationData, error) { +func doStepAttestationFormat(_ context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *attestationObject) (*stepAttestationData, error) { // Use configured or default attestation roots if none is configured. roots, ok := prov.GetAttestationRoots() if !ok { @@ -948,28 +954,28 @@ func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challeng // Extract x5c and verify certificate x5c, ok := att.AttStatement["x5c"].([]interface{}) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c not present") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c not present") } if len(x5c) == 0 { - return nil, NewError(ErrorRejectedIdentifierType, "x5c is empty") + return nil, NewDetailedError(ErrorRejectedIdentifierType, "x5c is empty") } der, ok := x5c[0].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is malformed") } leaf, err := x509.ParseCertificate(der) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is malformed") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is malformed") } intermediates := x509.NewCertPool() for _, v := range x5c[1:] { der, ok = v.([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "x5c is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "x5c is malformed") } cert, err := x509.ParseCertificate(der) if err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is malformed") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is malformed") } intermediates.AddCert(cert) } @@ -979,7 +985,7 @@ func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challeng CurrentTime: time.Now().Truncate(time.Second), KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, }); err != nil { - return nil, WrapError(ErrorBadAttestationStatementType, err, "x5c is not valid") + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "x5c is not valid") } // Verify proof of possession of private key validating the key @@ -989,10 +995,10 @@ func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challeng var sig []byte csig, ok := att.AttStatement["sig"].([]byte) if !ok { - return nil, NewError(ErrorBadAttestationStatementType, "sig not present") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "sig not present") } if err := cbor.Unmarshal(csig, &sig); err != nil { - return nil, NewError(ErrorBadAttestationStatementType, "sig is malformed") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "sig is malformed") } keyAuth, err := KeyAuthorization(ch.Token, jwk) if err != nil { @@ -1002,23 +1008,23 @@ func doStepAttestationFormat(ctx context.Context, prov Provisioner, ch *Challeng switch pub := leaf.PublicKey.(type) { case *ecdsa.PublicKey: if pub.Curve != elliptic.P256() { - return nil, WrapError(ErrorBadAttestationStatementType, err, "unsupported elliptic curve %s", pub.Curve) + return nil, WrapDetailedError(ErrorBadAttestationStatementType, err, "unsupported elliptic curve %s", pub.Curve) } sum := sha256.Sum256([]byte(keyAuth)) if !ecdsa.VerifyASN1(pub, sum[:], sig) { - return nil, NewError(ErrorBadAttestationStatementType, "failed to validate signature") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "failed to validate signature") } case *rsa.PublicKey: sum := sha256.Sum256([]byte(keyAuth)) if err := rsa.VerifyPKCS1v15(pub, crypto.SHA256, sum[:], sig); err != nil { - return nil, NewError(ErrorBadAttestationStatementType, "failed to validate signature") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "failed to validate signature") } case ed25519.PublicKey: if !ed25519.Verify(pub, []byte(keyAuth), sig) { - return nil, NewError(ErrorBadAttestationStatementType, "failed to validate signature") + return nil, NewDetailedError(ErrorBadAttestationStatementType, "failed to validate signature") } default: - return nil, NewError(ErrorBadAttestationStatementType, "unsupported public key type %T", pub) + return nil, NewDetailedError(ErrorBadAttestationStatementType, "unsupported public key type %T", pub) } // Parse attestation data: diff --git a/acme/challenge_test.go b/acme/challenge_test.go index ff93bea3..c20cf6aa 100644 --- a/acme/challenge_test.go +++ b/acme/challenge_test.go @@ -148,7 +148,7 @@ func mustAttestApple(t *testing.T, nonce string) ([]byte, *x509.Certificate, *x5 return payload, leaf, ca.Root } -func mustAttestYubikey(t *testing.T, nonce, keyAuthorization string, serial int) ([]byte, *x509.Certificate, *x509.Certificate) { +func mustAttestYubikey(t *testing.T, _, keyAuthorization string, serial int) ([]byte, *x509.Certificate, *x509.Certificate) { ca, err := minica.New() fatalError(t, err) @@ -888,7 +888,7 @@ func TestChallenge_Validate(t *testing.T) { type errReader int -func (errReader) Read(p []byte) (n int, err error) { +func (errReader) Read([]byte) (int, error) { return 0, errors.New("force") } func (errReader) Close() error { @@ -1631,14 +1631,14 @@ func newTestTLSALPNServer(validationCert *tls.Certificate, opts ...func(*httptes // noopConn is a mock net.Conn that does nothing. type noopConn struct{} -func (c *noopConn) Read(_ []byte) (n int, err error) { return 0, io.EOF } -func (c *noopConn) Write(_ []byte) (n int, err error) { return 0, io.EOF } -func (c *noopConn) Close() error { return nil } -func (c *noopConn) LocalAddr() net.Addr { return &net.IPAddr{IP: net.IPv4zero, Zone: ""} } -func (c *noopConn) RemoteAddr() net.Addr { return &net.IPAddr{IP: net.IPv4zero, Zone: ""} } -func (c *noopConn) SetDeadline(t time.Time) error { return nil } -func (c *noopConn) SetReadDeadline(t time.Time) error { return nil } -func (c *noopConn) SetWriteDeadline(t time.Time) error { return nil } +func (c *noopConn) Read(_ []byte) (n int, err error) { return 0, io.EOF } +func (c *noopConn) Write(_ []byte) (n int, err error) { return 0, io.EOF } +func (c *noopConn) Close() error { return nil } +func (c *noopConn) LocalAddr() net.Addr { return &net.IPAddr{IP: net.IPv4zero, Zone: ""} } +func (c *noopConn) RemoteAddr() net.Addr { return &net.IPAddr{IP: net.IPv4zero, Zone: ""} } +func (c *noopConn) SetDeadline(time.Time) error { return nil } +func (c *noopConn) SetReadDeadline(time.Time) error { return nil } +func (c *noopConn) SetWriteDeadline(time.Time) error { return nil } func newTLSALPNValidationCert(keyAuthHash []byte, obsoleteOID, critical bool, names ...string) (*tls.Certificate, error) { privateKey, err := rsa.GenerateKey(rand.Reader, 2048) @@ -3444,7 +3444,7 @@ func Test_deviceAttest01Validate(t *testing.T) { }, payload: errorCBORPayload, }, - wantErr: NewErrorISE("error unmarshalling CBOR: cbor: cannot unmarshal positive integer into Go value of type acme.attestationObject"), + wantErr: NewErrorISE("error unmarshalling CBOR: cbor:"), } }, "ok/prov.IsAttestationFormatEnabled": func(t *testing.T) test { @@ -3532,7 +3532,7 @@ func Test_deviceAttest01Validate(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "12345678", updch.Value) - err := NewError(ErrorBadAttestationStatementType, "x5c not present") + err := NewDetailedError(ErrorBadAttestationStatementType, "x5c not present") assert.EqualError(t, updch.Error.Err, err.Err.Error()) assert.Equal(t, err.Type, updch.Error.Type) @@ -3579,7 +3579,7 @@ func Test_deviceAttest01Validate(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "serial-number", updch.Value) - err := NewError(ErrorBadAttestationStatementType, "challenge token does not match") + err := NewDetailedError(ErrorBadAttestationStatementType, "challenge token does not match") assert.EqualError(t, updch.Error.Err, err.Err.Error()) assert.Equal(t, err.Type, updch.Error.Type) @@ -3625,7 +3625,12 @@ func Test_deviceAttest01Validate(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "non-matching-value", updch.Value) - err := NewError(ErrorBadAttestationStatementType, "permanent identifier does not match") + subproblem := NewSubproblemWithIdentifier( + ErrorRejectedIdentifierType, + Identifier{Type: "permanent-identifier", Value: "non-matching-value"}, + `challenge identifier "non-matching-value" doesn't match any of the attested hardware identifiers ["udid" "serial-number"]`, + ) + err := NewDetailedError(ErrorBadAttestationStatementType, "permanent identifier does not match").AddSubproblems(subproblem) assert.EqualError(t, updch.Error.Err, err.Err.Error()) assert.Equal(t, err.Type, updch.Error.Type) @@ -3698,7 +3703,7 @@ func Test_deviceAttest01Validate(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "12345678", updch.Value) - err := NewError(ErrorBadAttestationStatementType, "x5c not present") + err := NewDetailedError(ErrorBadAttestationStatementType, "x5c not present") assert.EqualError(t, updch.Error.Err, err.Err.Error()) assert.Equal(t, err.Type, updch.Error.Type) @@ -3752,9 +3757,9 @@ func Test_deviceAttest01Validate(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "12345678", updch.Value) - err := NewError(ErrorBadAttestationStatementType, "permanent identifier does not match"). + err := NewDetailedError(ErrorBadAttestationStatementType, "permanent identifier does not match"). AddSubproblems(NewSubproblemWithIdentifier( - ErrorMalformedType, + ErrorRejectedIdentifierType, Identifier{Type: "permanent-identifier", Value: "12345678"}, "challenge identifier \"12345678\" doesn't match the attested hardware identifier \"87654321\"", )) @@ -3847,7 +3852,7 @@ func Test_deviceAttest01Validate(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "12345678", updch.Value) - err := NewError(ErrorBadAttestationStatementType, "unexpected attestation object format") + err := NewDetailedError(ErrorBadAttestationStatementType, `unsupported attestation object format "bogus-format"`) assert.EqualError(t, updch.Error.Err, err.Err.Error()) assert.Equal(t, err.Type, updch.Error.Type) @@ -3998,8 +4003,9 @@ func Test_deviceAttest01Validate(t *testing.T) { tc := run(t) if err := deviceAttest01Validate(tc.args.ctx, tc.args.ch, tc.args.db, tc.args.jwk, tc.args.payload); err != nil { - assert.Error(t, tc.wantErr) - assert.EqualError(t, err, tc.wantErr.Error()) + if assert.Error(t, tc.wantErr) { + assert.ErrorContains(t, err, tc.wantErr.Error()) + } return } diff --git a/acme/challenge_tpmsimulator_test.go b/acme/challenge_tpmsimulator_test.go index dbd63226..87db8631 100644 --- a/acme/challenge_tpmsimulator_test.go +++ b/acme/challenge_tpmsimulator_test.go @@ -18,10 +18,10 @@ import ( "testing" "github.com/fxamacker/cbor/v2" - "github.com/google/go-attestation/attest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smallstep/go-attestation/attest" "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" "go.step.sm/crypto/minica" @@ -49,8 +49,9 @@ func withSimulator(t *testing.T) tpm.NewTPMOption { err := sim.Close() require.NoError(t, err) }) - sim = simulator.New() - err := sim.Open() + sim, err := simulator.New() + require.NoError(t, err) + err = sim.Open() require.NoError(t, err) return tpm.WithSimulator(sim) } @@ -236,7 +237,7 @@ func Test_deviceAttest01ValidateWithTPMSimulator(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "device.id.12345678", updch.Value) - err := NewError(ErrorBadAttestationStatementType, `version "bogus" is not supported`) + err := NewDetailedError(ErrorBadAttestationStatementType, `version "bogus" is not supported`) assert.EqualError(t, updch.Error.Err, err.Err.Error()) assert.Equal(t, err.Type, updch.Error.Type) @@ -281,9 +282,9 @@ func Test_deviceAttest01ValidateWithTPMSimulator(t *testing.T) { assert.Equal(t, ChallengeType("device-attest-01"), updch.Type) assert.Equal(t, "device.id.99999999", updch.Value) - err := NewError(ErrorRejectedIdentifierType, `permanent identifier does not match`). + err := NewDetailedError(ErrorBadAttestationStatementType, `permanent identifier does not match`). AddSubproblems(NewSubproblemWithIdentifier( - ErrorMalformedType, + ErrorRejectedIdentifierType, Identifier{Type: "permanent-identifier", Value: "device.id.99999999"}, `challenge identifier "device.id.99999999" doesn't match any of the attested hardware identifiers ["device.id.12345678"]`, )) @@ -827,7 +828,7 @@ func Test_doTPMAttestationFormat(t *testing.T) { "certInfo": params.CreateAttestation, "pubArea": params.Public, }, - }}, nil, newBadAttestationStatementError("key authorization does not match")}, + }}, nil, newBadAttestationStatementError("key authorization invalid")}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/acme/common.go b/acme/common.go index 91cf772b..7d58305f 100644 --- a/acme/common.go +++ b/acme/common.go @@ -46,7 +46,7 @@ type PrerequisitesChecker func(ctx context.Context) (bool, error) // DefaultPrerequisitesChecker is the default PrerequisiteChecker and returns // always true. -func DefaultPrerequisitesChecker(ctx context.Context) (bool, error) { +func DefaultPrerequisitesChecker(context.Context) (bool, error) { return true, nil } diff --git a/acme/db.go b/acme/db.go index d7c9d5f4..fa9aa0de 100644 --- a/acme/db.go +++ b/acme/db.go @@ -12,6 +12,12 @@ import ( // account. var ErrNotFound = errors.New("not found") +// IsErrNotFound returns true if the error is a "not found" error. Returns false +// otherwise. +func IsErrNotFound(err error) bool { + return errors.Is(err, ErrNotFound) +} + // DB is the DB interface expected by the step-ca ACME API. type DB interface { CreateAccount(ctx context.Context, acc *Account) error diff --git a/acme/db/nosql/account.go b/acme/db/nosql/account.go index 1c3bec5d..d590ccb3 100644 --- a/acme/db/nosql/account.go +++ b/acme/db/nosql/account.go @@ -13,12 +13,14 @@ import ( // dbAccount represents an ACME account. type dbAccount struct { - ID string `json:"id"` - Key *jose.JSONWebKey `json:"key"` - Contact []string `json:"contact,omitempty"` - Status acme.Status `json:"status"` - CreatedAt time.Time `json:"createdAt"` - DeactivatedAt time.Time `json:"deactivatedAt"` + ID string `json:"id"` + Key *jose.JSONWebKey `json:"key"` + Contact []string `json:"contact,omitempty"` + Status acme.Status `json:"status"` + LocationPrefix string `json:"locationPrefix"` + ProvisionerName string `json:"provisionerName"` + CreatedAt time.Time `json:"createdAt"` + DeactivatedAt time.Time `json:"deactivatedAt"` } func (dba *dbAccount) clone() *dbAccount { @@ -26,7 +28,7 @@ func (dba *dbAccount) clone() *dbAccount { return &nu } -func (db *DB) getAccountIDByKeyID(ctx context.Context, kid string) (string, error) { +func (db *DB) getAccountIDByKeyID(_ context.Context, kid string) (string, error) { id, err := db.db.Get(accountByKeyIDTable, []byte(kid)) if err != nil { if nosqlDB.IsErrNotFound(err) { @@ -38,7 +40,7 @@ func (db *DB) getAccountIDByKeyID(ctx context.Context, kid string) (string, erro } // getDBAccount retrieves and unmarshals dbAccount. -func (db *DB) getDBAccount(ctx context.Context, id string) (*dbAccount, error) { +func (db *DB) getDBAccount(_ context.Context, id string) (*dbAccount, error) { data, err := db.db.Get(accountTable, []byte(id)) if err != nil { if nosqlDB.IsErrNotFound(err) { @@ -62,10 +64,12 @@ func (db *DB) GetAccount(ctx context.Context, id string) (*acme.Account, error) } return &acme.Account{ - Status: dbacc.Status, - Contact: dbacc.Contact, - Key: dbacc.Key, - ID: dbacc.ID, + Status: dbacc.Status, + Contact: dbacc.Contact, + Key: dbacc.Key, + ID: dbacc.ID, + LocationPrefix: dbacc.LocationPrefix, + ProvisionerName: dbacc.ProvisionerName, }, nil } @@ -87,11 +91,13 @@ func (db *DB) CreateAccount(ctx context.Context, acc *acme.Account) error { } dba := &dbAccount{ - ID: acc.ID, - Key: acc.Key, - Contact: acc.Contact, - Status: acc.Status, - CreatedAt: clock.Now(), + ID: acc.ID, + Key: acc.Key, + Contact: acc.Contact, + Status: acc.Status, + CreatedAt: clock.Now(), + LocationPrefix: acc.LocationPrefix, + ProvisionerName: acc.ProvisionerName, } kid, err := acme.KeyToID(dba.Key) diff --git a/acme/db/nosql/account_test.go b/acme/db/nosql/account_test.go index 6097cc5a..085ce2eb 100644 --- a/acme/db/nosql/account_test.go +++ b/acme/db/nosql/account_test.go @@ -197,6 +197,8 @@ func TestDB_getAccountIDByKeyID(t *testing.T) { func TestDB_GetAccount(t *testing.T) { accID := "accID" + locationPrefix := "https://test.ca.smallstep.com/acme/foo/account/" + provisionerName := "foo" type test struct { db nosql.DB err error @@ -222,12 +224,14 @@ func TestDB_GetAccount(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) dbacc := &dbAccount{ - ID: accID, - Status: acme.StatusDeactivated, - CreatedAt: now, - DeactivatedAt: now, - Contact: []string{"foo", "bar"}, - Key: jwk, + ID: accID, + Status: acme.StatusDeactivated, + CreatedAt: now, + DeactivatedAt: now, + Contact: []string{"foo", "bar"}, + Key: jwk, + LocationPrefix: locationPrefix, + ProvisionerName: provisionerName, } b, err := json.Marshal(dbacc) assert.FatalError(t, err) @@ -266,6 +270,8 @@ func TestDB_GetAccount(t *testing.T) { assert.Equals(t, acc.ID, tc.dbacc.ID) assert.Equals(t, acc.Status, tc.dbacc.Status) assert.Equals(t, acc.Contact, tc.dbacc.Contact) + assert.Equals(t, acc.LocationPrefix, tc.dbacc.LocationPrefix) + assert.Equals(t, acc.ProvisionerName, tc.dbacc.ProvisionerName) assert.Equals(t, acc.Key.KeyID, tc.dbacc.Key.KeyID) } }) @@ -379,6 +385,7 @@ func TestDB_GetAccountByKeyID(t *testing.T) { } func TestDB_CreateAccount(t *testing.T) { + locationPrefix := "https://test.ca.smallstep.com/acme/foo/account/" type test struct { db nosql.DB acc *acme.Account @@ -390,9 +397,10 @@ func TestDB_CreateAccount(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) acc := &acme.Account{ - Status: acme.StatusValid, - Contact: []string{"foo", "bar"}, - Key: jwk, + Status: acme.StatusValid, + Contact: []string{"foo", "bar"}, + Key: jwk, + LocationPrefix: locationPrefix, } return test{ db: &db.MockNoSQLDB{ @@ -413,9 +421,10 @@ func TestDB_CreateAccount(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) acc := &acme.Account{ - Status: acme.StatusValid, - Contact: []string{"foo", "bar"}, - Key: jwk, + Status: acme.StatusValid, + Contact: []string{"foo", "bar"}, + Key: jwk, + LocationPrefix: locationPrefix, } return test{ db: &db.MockNoSQLDB{ @@ -436,9 +445,10 @@ func TestDB_CreateAccount(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) acc := &acme.Account{ - Status: acme.StatusValid, - Contact: []string{"foo", "bar"}, - Key: jwk, + Status: acme.StatusValid, + Contact: []string{"foo", "bar"}, + Key: jwk, + LocationPrefix: locationPrefix, } return test{ db: &db.MockNoSQLDB{ @@ -456,6 +466,8 @@ func TestDB_CreateAccount(t *testing.T) { assert.FatalError(t, json.Unmarshal(nu, dbacc)) assert.Equals(t, dbacc.ID, string(key)) assert.Equals(t, dbacc.Contact, acc.Contact) + assert.Equals(t, dbacc.LocationPrefix, acc.LocationPrefix) + assert.Equals(t, dbacc.ProvisionerName, acc.ProvisionerName) assert.Equals(t, dbacc.Key.KeyID, acc.Key.KeyID) assert.True(t, clock.Now().Add(-time.Minute).Before(dbacc.CreatedAt)) assert.True(t, clock.Now().Add(time.Minute).After(dbacc.CreatedAt)) @@ -479,9 +491,10 @@ func TestDB_CreateAccount(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) acc := &acme.Account{ - Status: acme.StatusValid, - Contact: []string{"foo", "bar"}, - Key: jwk, + Status: acme.StatusValid, + Contact: []string{"foo", "bar"}, + Key: jwk, + LocationPrefix: locationPrefix, } return test{ db: &db.MockNoSQLDB{ @@ -500,6 +513,8 @@ func TestDB_CreateAccount(t *testing.T) { assert.FatalError(t, json.Unmarshal(nu, dbacc)) assert.Equals(t, dbacc.ID, string(key)) assert.Equals(t, dbacc.Contact, acc.Contact) + assert.Equals(t, dbacc.LocationPrefix, acc.LocationPrefix) + assert.Equals(t, dbacc.ProvisionerName, acc.ProvisionerName) assert.Equals(t, dbacc.Key.KeyID, acc.Key.KeyID) assert.True(t, clock.Now().Add(-time.Minute).Before(dbacc.CreatedAt)) assert.True(t, clock.Now().Add(time.Minute).After(dbacc.CreatedAt)) @@ -539,12 +554,14 @@ func TestDB_UpdateAccount(t *testing.T) { jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) dbacc := &dbAccount{ - ID: accID, - Status: acme.StatusDeactivated, - CreatedAt: now, - DeactivatedAt: now, - Contact: []string{"foo", "bar"}, - Key: jwk, + ID: accID, + Status: acme.StatusDeactivated, + CreatedAt: now, + DeactivatedAt: now, + Contact: []string{"foo", "bar"}, + LocationPrefix: "foo", + ProvisionerName: "alpha", + Key: jwk, } b, err := json.Marshal(dbacc) assert.FatalError(t, err) @@ -644,10 +661,12 @@ func TestDB_UpdateAccount(t *testing.T) { }, "ok": func(t *testing.T) test { acc := &acme.Account{ - ID: accID, - Status: acme.StatusDeactivated, - Contact: []string{"foo", "bar"}, - Key: jwk, + ID: accID, + Status: acme.StatusDeactivated, + Contact: []string{"baz", "zap"}, + LocationPrefix: "bar", + ProvisionerName: "beta", + Key: jwk, } return test{ acc: acc, @@ -666,7 +685,10 @@ func TestDB_UpdateAccount(t *testing.T) { assert.FatalError(t, json.Unmarshal(nu, dbNew)) assert.Equals(t, dbNew.ID, dbacc.ID) assert.Equals(t, dbNew.Status, acc.Status) - assert.Equals(t, dbNew.Contact, dbacc.Contact) + assert.Equals(t, dbNew.Contact, acc.Contact) + // LocationPrefix should not change. + assert.Equals(t, dbNew.LocationPrefix, dbacc.LocationPrefix) + assert.Equals(t, dbNew.ProvisionerName, dbacc.ProvisionerName) assert.Equals(t, dbNew.Key.KeyID, dbacc.Key.KeyID) assert.Equals(t, dbNew.CreatedAt, dbacc.CreatedAt) assert.True(t, dbNew.DeactivatedAt.Add(-time.Minute).Before(now)) @@ -686,12 +708,7 @@ func TestDB_UpdateAccount(t *testing.T) { assert.HasPrefix(t, err.Error(), tc.err.Error()) } } else { - if assert.Nil(t, tc.err) { - assert.Equals(t, tc.acc.ID, dbacc.ID) - assert.Equals(t, tc.acc.Status, dbacc.Status) - assert.Equals(t, tc.acc.Contact, dbacc.Contact) - assert.Equals(t, tc.acc.Key.KeyID, dbacc.Key.KeyID) - } + assert.Nil(t, tc.err) } }) } diff --git a/acme/db/nosql/authz.go b/acme/db/nosql/authz.go index d63aa89e..be3b0fbb 100644 --- a/acme/db/nosql/authz.go +++ b/acme/db/nosql/authz.go @@ -32,7 +32,7 @@ func (ba *dbAuthz) clone() *dbAuthz { // getDBAuthz retrieves and unmarshals a database representation of the // ACME Authorization type. -func (db *DB) getDBAuthz(ctx context.Context, id string) (*dbAuthz, error) { +func (db *DB) getDBAuthz(_ context.Context, id string) (*dbAuthz, error) { data, err := db.db.Get(authzTable, []byte(id)) if nosql.IsErrNotFound(err) { return nil, acme.NewError(acme.ErrorMalformedType, "authz %s not found", id) @@ -121,7 +121,7 @@ func (db *DB) UpdateAuthorization(ctx context.Context, az *acme.Authorization) e } // GetAuthorizationsByAccountID retrieves and unmarshals ACME authz types from the database. -func (db *DB) GetAuthorizationsByAccountID(ctx context.Context, accountID string) ([]*acme.Authorization, error) { +func (db *DB) GetAuthorizationsByAccountID(_ context.Context, accountID string) ([]*acme.Authorization, error) { entries, err := db.db.List(authzTable) if err != nil { return nil, errors.Wrapf(err, "error listing authz") diff --git a/acme/db/nosql/certificate.go b/acme/db/nosql/certificate.go index 8f271ba5..35c55246 100644 --- a/acme/db/nosql/certificate.go +++ b/acme/db/nosql/certificate.go @@ -69,7 +69,7 @@ func (db *DB) CreateCertificate(ctx context.Context, cert *acme.Certificate) err // GetCertificate retrieves and unmarshals an ACME certificate type from the // datastore. -func (db *DB) GetCertificate(ctx context.Context, id string) (*acme.Certificate, error) { +func (db *DB) GetCertificate(_ context.Context, id string) (*acme.Certificate, error) { b, err := db.db.Get(certTable, []byte(id)) if nosql.IsErrNotFound(err) { return nil, acme.NewError(acme.ErrorMalformedType, "certificate %s not found", id) diff --git a/acme/db/nosql/challenge.go b/acme/db/nosql/challenge.go index c9224574..9af1ae0d 100644 --- a/acme/db/nosql/challenge.go +++ b/acme/db/nosql/challenge.go @@ -29,7 +29,7 @@ func (dbc *dbChallenge) clone() *dbChallenge { return &u } -func (db *DB) getDBChallenge(ctx context.Context, id string) (*dbChallenge, error) { +func (db *DB) getDBChallenge(_ context.Context, id string) (*dbChallenge, error) { data, err := db.db.Get(challengeTable, []byte(id)) if nosql.IsErrNotFound(err) { return nil, acme.NewError(acme.ErrorMalformedType, "challenge %s not found", id) @@ -69,6 +69,7 @@ func (db *DB) CreateChallenge(ctx context.Context, ch *acme.Challenge) error { // GetChallenge retrieves and unmarshals an ACME challenge type from the database. // Implements the acme.DB GetChallenge interface. func (db *DB) GetChallenge(ctx context.Context, id, authzID string) (*acme.Challenge, error) { + _ = authzID // unused input dbch, err := db.getDBChallenge(ctx, id) if err != nil { return nil, err diff --git a/acme/db/nosql/eab.go b/acme/db/nosql/eab.go index e3651151..e2a437dd 100644 --- a/acme/db/nosql/eab.go +++ b/acme/db/nosql/eab.go @@ -35,7 +35,7 @@ type dbExternalAccountKeyReference struct { } // getDBExternalAccountKey retrieves and unmarshals dbExternalAccountKey. -func (db *DB) getDBExternalAccountKey(ctx context.Context, id string) (*dbExternalAccountKey, error) { +func (db *DB) getDBExternalAccountKey(_ context.Context, id string) (*dbExternalAccountKey, error) { data, err := db.db.Get(externalAccountKeyTable, []byte(id)) if err != nil { if nosqlDB.IsErrNotFound(err) { @@ -160,6 +160,8 @@ func (db *DB) DeleteExternalAccountKey(ctx context.Context, provisionerID, keyID // GetExternalAccountKeys retrieves all External Account Binding keys for a provisioner func (db *DB) GetExternalAccountKeys(ctx context.Context, provisionerID, cursor string, limit int) ([]*acme.ExternalAccountKey, string, error) { + _, _ = cursor, limit // unused input + externalAccountKeyMutex.RLock() defer externalAccountKeyMutex.RUnlock() @@ -227,7 +229,7 @@ func (db *DB) GetExternalAccountKeyByReference(ctx context.Context, provisionerI return db.GetExternalAccountKey(ctx, provisionerID, dbExternalAccountKeyReference.ExternalAccountKeyID) } -func (db *DB) GetExternalAccountKeyByAccountID(ctx context.Context, provisionerID, accountID string) (*acme.ExternalAccountKey, error) { +func (db *DB) GetExternalAccountKeyByAccountID(context.Context, string, string) (*acme.ExternalAccountKey, error) { //nolint:nilnil // legacy return nil, nil } diff --git a/acme/db/nosql/nonce.go b/acme/db/nosql/nonce.go index e438c9ed..af85b183 100644 --- a/acme/db/nosql/nonce.go +++ b/acme/db/nosql/nonce.go @@ -39,7 +39,7 @@ func (db *DB) CreateNonce(ctx context.Context) (acme.Nonce, error) { // DeleteNonce verifies that the nonce is valid (by checking if it exists), // and if so, consumes the nonce resource by deleting it from the database. -func (db *DB) DeleteNonce(ctx context.Context, nonce acme.Nonce) error { +func (db *DB) DeleteNonce(_ context.Context, nonce acme.Nonce) error { err := db.db.Update(&database.Tx{ Operations: []*database.TxEntry{ { diff --git a/acme/db/nosql/nosql.go b/acme/db/nosql/nosql.go index 98f6a04d..d19e2987 100644 --- a/acme/db/nosql/nosql.go +++ b/acme/db/nosql/nosql.go @@ -48,7 +48,7 @@ func New(db nosqlDB.DB) (*DB, error) { // save writes the new data to the database, overwriting the old data if it // existed. -func (db *DB) save(ctx context.Context, id string, nu, old interface{}, typ string, table []byte) error { +func (db *DB) save(_ context.Context, id string, nu, old interface{}, typ string, table []byte) error { var ( err error newB []byte diff --git a/acme/db/nosql/order.go b/acme/db/nosql/order.go index 0c6bf795..fc8f2114 100644 --- a/acme/db/nosql/order.go +++ b/acme/db/nosql/order.go @@ -35,7 +35,7 @@ func (a *dbOrder) clone() *dbOrder { } // getDBOrder retrieves and unmarshals an ACME Order type from the database. -func (db *DB) getDBOrder(ctx context.Context, id string) (*dbOrder, error) { +func (db *DB) getDBOrder(_ context.Context, id string) (*dbOrder, error) { b, err := db.db.Get(orderTable, []byte(id)) if nosql.IsErrNotFound(err) { return nil, acme.NewError(acme.ErrorMalformedType, "order %s not found", id) diff --git a/acme/errors.go b/acme/errors.go index 44f367a0..658ec6e0 100644 --- a/acme/errors.go +++ b/acme/errors.go @@ -293,6 +293,27 @@ type Subproblem struct { Identifier *Identifier `json:"identifier,omitempty"` } +// NewError creates a new Error. +func NewError(pt ProblemType, msg string, args ...interface{}) *Error { + return newError(pt, errors.Errorf(msg, args...)) +} + +// NewDetailedError creates a new Error that includes the error +// message in the details, providing more information to the +// ACME client. +func NewDetailedError(pt ProblemType, msg string, args ...interface{}) *Error { + return NewError(pt, msg, args...).withDetail() +} + +func (e *Error) withDetail() *Error { + if e == nil || e.Status >= 500 || e.Err == nil { + return e + } + + e.Detail = fmt.Sprintf("%s: %s", e.Detail, e.Err) + return e +} + // AddSubproblems adds the Subproblems to Error. It // returns the Error, allowing for fluent addition. func (e *Error) AddSubproblems(subproblems ...Subproblem) *Error { @@ -300,11 +321,6 @@ func (e *Error) AddSubproblems(subproblems ...Subproblem) *Error { return e } -// NewError creates a new Error type. -func NewError(pt ProblemType, msg string, args ...interface{}) *Error { - return newError(pt, errors.Errorf(msg, args...)) -} - // NewSubproblem creates a new Subproblem. The msg and args // are used to create a new error, which is set as the Detail, allowing // for more detailed error messages to be returned to the ACME client. @@ -368,6 +384,10 @@ func WrapError(typ ProblemType, err error, msg string, args ...interface{}) *Err } } +func WrapDetailedError(typ ProblemType, err error, msg string, args ...interface{}) *Error { + return WrapError(typ, err, msg, args...).withDetail() +} + // WrapErrorISE shortcut to wrap an internal server error type. func WrapErrorISE(err error, msg string, args ...interface{}) *Error { return WrapError(ErrorServerInternalType, err, msg, args...) diff --git a/acme/errors_test.go b/acme/errors_test.go new file mode 100644 index 00000000..8e586a12 --- /dev/null +++ b/acme/errors_test.go @@ -0,0 +1,54 @@ +package acme + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func mustJSON(t *testing.T, m map[string]interface{}) string { + t.Helper() + + b, err := json.Marshal(m) + require.NoError(t, err) + + return string(b) +} + +func TestError_WithAdditionalErrorDetail(t *testing.T) { + internalJSON := mustJSON(t, map[string]interface{}{ + "detail": "The server experienced an internal error", + "type": "urn:ietf:params:acme:error:serverInternal", + }) + malformedErr := NewError(ErrorMalformedType, "malformed error") // will result in Err == nil behavior + malformedJSON := mustJSON(t, map[string]interface{}{ + "detail": "The request message was malformed", + "type": "urn:ietf:params:acme:error:malformed", + }) + withDetailJSON := mustJSON(t, map[string]interface{}{ + "detail": "Attestation statement cannot be verified: invalid property", + "type": "urn:ietf:params:acme:error:badAttestationStatement", + }) + tests := []struct { + name string + err *Error + want string + }{ + {"internal", NewDetailedError(ErrorServerInternalType, ""), internalJSON}, + {"nil err", malformedErr, malformedJSON}, + {"detailed", NewDetailedError(ErrorBadAttestationStatementType, "invalid property"), withDetailJSON}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b, err := json.Marshal(tt.err) + require.NoError(t, err) + + // tests if the additional error detail is included in the JSON representation + // of the ACME error. This is what is returned to ACME clients and being logged + // by the CA. + assert.JSONEq(t, tt.want, string(b)) + }) + } +} diff --git a/acme/linker.go b/acme/linker.go index bddc21f1..e59db4ee 100644 --- a/acme/linker.go +++ b/acme/linker.go @@ -8,7 +8,7 @@ import ( "net/url" "strings" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/provisioner" diff --git a/acme/order_test.go b/acme/order_test.go index b8018c7b..2851bb19 100644 --- a/acme/order_test.go +++ b/acme/order_test.go @@ -301,7 +301,7 @@ func (m *mockSignAuth) LoadProvisionerByName(name string) (provisioner.Interface return m.ret1.(provisioner.Interface), m.err } -func (m *mockSignAuth) IsRevoked(sn string) (bool, error) { +func (m *mockSignAuth) IsRevoked(string) (bool, error) { return false, nil } diff --git a/api/api.go b/api/api.go index 9c2f1f31..7cf44a11 100644 --- a/api/api.go +++ b/api/api.go @@ -1,6 +1,7 @@ package api import ( + "bytes" "context" "crypto" "crypto/dsa" //nolint:staticcheck // support legacy algorithms @@ -18,10 +19,13 @@ import ( "strings" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" + "go.step.sm/crypto/sshutil" + "golang.org/x/crypto/ssh" "github.com/smallstep/certificates/api/log" + "github.com/smallstep/certificates/api/models" "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/config" @@ -224,8 +228,60 @@ type RootResponse struct { // ProvisionersResponse is the response object that returns the list of // provisioners. type ProvisionersResponse struct { - Provisioners provisioner.List `json:"provisioners"` - NextCursor string `json:"nextCursor"` + Provisioners provisioner.List + NextCursor string +} + +const redacted = "*** REDACTED ***" + +func scepFromProvisioner(p *provisioner.SCEP) *models.SCEP { + return &models.SCEP{ + ID: p.ID, + Type: p.Type, + Name: p.Name, + ForceCN: p.ForceCN, + ChallengePassword: redacted, + Capabilities: p.Capabilities, + IncludeRoot: p.IncludeRoot, + ExcludeIntermediate: p.ExcludeIntermediate, + MinimumPublicKeyLength: p.MinimumPublicKeyLength, + DecrypterCertificate: []byte(redacted), + DecrypterKeyPEM: []byte(redacted), + DecrypterKeyURI: redacted, + DecrypterKeyPassword: redacted, + EncryptionAlgorithmIdentifier: p.EncryptionAlgorithmIdentifier, + Options: p.Options, + Claims: p.Claims, + } +} + +// MarshalJSON implements json.Marshaler. It marshals the ProvisionersResponse +// into a byte slice. +// +// Special treatment is given to the SCEP provisioner, as it contains a +// challenge secret that MUST NOT be leaked in (public) HTTP responses. The +// challenge value is thus redacted in HTTP responses. +func (p ProvisionersResponse) MarshalJSON() ([]byte, error) { + var responseProvisioners provisioner.List + for _, item := range p.Provisioners { + scepProv, ok := item.(*provisioner.SCEP) + if !ok { + responseProvisioners = append(responseProvisioners, item) + continue + } + + responseProvisioners = append(responseProvisioners, scepFromProvisioner(scepProv)) + } + + var list = struct { + Provisioners []provisioner.Interface `json:"provisioners"` + NextCursor string `json:"nextCursor"` + }{ + Provisioners: []provisioner.Interface(responseProvisioners), + NextCursor: p.NextCursor, + } + + return json.Marshal(list) } // ProvisionerKeyResponse is the response object that returns the encrypted key @@ -257,7 +313,7 @@ func (h *caHandler) Route(r Router) { // New creates a new RouterHandler with the CA endpoints. // // Deprecated: Use api.Route(r Router) -func New(auth Authority) RouterHandler { +func New(Authority) RouterHandler { return &caHandler{} } @@ -304,7 +360,7 @@ func Version(w http.ResponseWriter, r *http.Request) { } // Health is an HTTP handler that returns the status of the server. -func Health(w http.ResponseWriter, r *http.Request) { +func Health(w http.ResponseWriter, _ *http.Request) { render.JSON(w, HealthResponse{Status: "ok"}) } @@ -438,7 +494,7 @@ func logOtt(w http.ResponseWriter, token string) { } } -// LogCertificate add certificate fields to the log message. +// LogCertificate adds certificate fields to the log message. func LogCertificate(w http.ResponseWriter, cert *x509.Certificate) { if rl, ok := w.(logging.ResponseLogger); ok { m := map[string]interface{}{ @@ -470,6 +526,41 @@ func LogCertificate(w http.ResponseWriter, cert *x509.Certificate) { } } +// LogSSHCertificate adds SSH certificate fields to the log message. +func LogSSHCertificate(w http.ResponseWriter, cert *ssh.Certificate) { + if rl, ok := w.(logging.ResponseLogger); ok { + mak := bytes.TrimSpace(ssh.MarshalAuthorizedKey(cert)) + var certificate string + parts := strings.Split(string(mak), " ") + if len(parts) > 1 { + certificate = parts[1] + } + var userOrHost string + if cert.CertType == ssh.HostCert { + userOrHost = "host" + } else { + userOrHost = "user" + } + certificateType := fmt.Sprintf("%s %s certificate", parts[0], userOrHost) // e.g. ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate + m := map[string]interface{}{ + "serial": cert.Serial, + "principals": cert.ValidPrincipals, + "valid-from": time.Unix(int64(cert.ValidAfter), 0).Format(time.RFC3339), + "valid-to": time.Unix(int64(cert.ValidBefore), 0).Format(time.RFC3339), + "certificate": certificate, + "certificate-type": certificateType, + } + fingerprint, err := sshutil.FormatFingerprint(mak, sshutil.DefaultFingerprint) + if err == nil { + fpParts := strings.Split(fingerprint, " ") + if len(fpParts) > 3 { + m["public-key"] = fmt.Sprintf("%s %s", fpParts[1], fpParts[len(fpParts)-1]) + } + } + rl.WithFields(m) + } +} + // ParseCursor parses the cursor and limit from the request query params. func ParseCursor(r *http.Request) (cursor string, limit int, err error) { q := r.URL.Query() diff --git a/api/api_test.go b/api/api_test.go index e24751b3..c57eef31 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "crypto" - "crypto/dsa" //nolint + "crypto/dsa" //nolint:staticcheck // support legacy algorithms "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" @@ -26,14 +26,17 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" - "golang.org/x/crypto/ssh" - + sassert "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.step.sm/crypto/jose" "go.step.sm/crypto/x509util" + "golang.org/x/crypto/ssh" + squarejose "gopkg.in/square/go-jose.v2" "github.com/smallstep/assert" + "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/errs" @@ -800,7 +803,7 @@ func Test_CRLGeneration(t *testing.T) { } chiCtx := chi.NewRouteContext() - req := httptest.NewRequest("GET", "http://example.com/crl", nil) + req := httptest.NewRequest("GET", "http://example.com/crl", http.NoBody) req = req.WithContext(context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)) for _, tt := range tests { @@ -853,7 +856,7 @@ func Test_caHandler_Route(t *testing.T) { } func Test_Health(t *testing.T) { - req := httptest.NewRequest("GET", "http://example.com/health", nil) + req := httptest.NewRequest("GET", "http://example.com/health", http.NoBody) w := httptest.NewRecorder() Health(w, req) @@ -887,7 +890,7 @@ func Test_Root(t *testing.T) { // Request with chi context chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("sha", "efc7d6b475a56fe587650bcdb999a4a308f815ba44db4bf0371ea68a786ccd36") - req := httptest.NewRequest("GET", "http://example.com/root/efc7d6b475a56fe587650bcdb999a4a308f815ba44db4bf0371ea68a786ccd36", nil) + req := httptest.NewRequest("GET", "http://example.com/root/efc7d6b475a56fe587650bcdb999a4a308f815ba44db4bf0371ea68a786ccd36", http.NoBody) req = req.WithContext(context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)) expected := []byte(`{"ca":"` + strings.ReplaceAll(rootPEM, "\n", `\n`) + `\n"}`) @@ -1102,7 +1105,7 @@ func Test_Renew(t *testing.T) { return nil }, }) - req := httptest.NewRequest("POST", "http://example.com/renew", nil) + req := httptest.NewRequest("POST", "http://example.com/renew", http.NoBody) req.TLS = tt.tls req.Header = tt.header w := httptest.NewRecorder() @@ -1310,7 +1313,7 @@ func Test_ProvisionerKey(t *testing.T) { // Request with chi context chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("kid", "oV1p0MJeGQ7qBlK6B-oyfVdBRjh_e7VSK_YSEEqgW00") - req := httptest.NewRequest("GET", "http://example.com/provisioners/oV1p0MJeGQ7qBlK6B-oyfVdBRjh_e7VSK_YSEEqgW00/encrypted-key", nil) + req := httptest.NewRequest("GET", "http://example.com/provisioners/oV1p0MJeGQ7qBlK6B-oyfVdBRjh_e7VSK_YSEEqgW00/encrypted-key", http.NoBody) req = req.WithContext(context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)) tests := []struct { @@ -1378,7 +1381,7 @@ func Test_Roots(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockMustAuthority(t, &mockAuthority{ret1: []*x509.Certificate{tt.root}, err: tt.err}) - req := httptest.NewRequest("GET", "http://example.com/roots", nil) + req := httptest.NewRequest("GET", "http://example.com/roots", http.NoBody) req.TLS = tt.tls w := httptest.NewRecorder() Roots(w, req) @@ -1419,7 +1422,7 @@ func Test_caHandler_RootsPEM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockMustAuthority(t, &mockAuthority{ret1: tt.roots, err: tt.err}) - req := httptest.NewRequest("GET", "https://example.com/roots", nil) + req := httptest.NewRequest("GET", "https://example.com/roots", http.NoBody) w := httptest.NewRecorder() RootsPEM(w, req) res := w.Result() @@ -1464,7 +1467,7 @@ func Test_Federation(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockMustAuthority(t, &mockAuthority{ret1: []*x509.Certificate{tt.root}, err: tt.err}) - req := httptest.NewRequest("GET", "http://example.com/federation", nil) + req := httptest.NewRequest("GET", "http://example.com/federation", http.NoBody) req.TLS = tt.tls w := httptest.NewRecorder() Federation(w, req) @@ -1564,3 +1567,140 @@ func mustCertificate(t *testing.T, pub, priv interface{}) *x509.Certificate { } return cert } + +func TestProvisionersResponse_MarshalJSON(t *testing.T) { + k := map[string]any{ + "use": "sig", + "kty": "EC", + "kid": "4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc", + "crv": "P-256", + "alg": "ES256", + "x": "7ZdAAMZCFU4XwgblI5RfZouBi8lYmF6DlZusNNnsbm8", + "y": "sQr2JdzwD2fgyrymBEXWsxDxFNjjqN64qLLSbLdLZ9Y", + } + key := squarejose.JSONWebKey{} + b, err := json.Marshal(k) + require.NoError(t, err) + err = json.Unmarshal(b, &key) + require.NoError(t, err) + + r := ProvisionersResponse{ + Provisioners: provisioner.List{ + &provisioner.SCEP{ + Name: "scep", + Type: "scep", + ChallengePassword: "not-so-secret", + MinimumPublicKeyLength: 2048, + EncryptionAlgorithmIdentifier: 2, + IncludeRoot: true, + ExcludeIntermediate: true, + DecrypterCertificate: []byte{1, 2, 3, 4}, + DecrypterKeyPEM: []byte{5, 6, 7, 8}, + DecrypterKeyURI: "softkms:path=/path/to/private.key", + DecrypterKeyPassword: "super-secret-password", + }, + &provisioner.JWK{ + EncryptedKey: "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlhOdmYxQjgxSUlLMFA2NUkwcmtGTGcifQ.XaN9zcPQeWt49zchUDm34FECUTHfQTn_.tmNHPQDqR3ebsWfd.9WZr3YVdeOyJh36vvx0VlRtluhvYp4K7jJ1KGDr1qypwZ3ziBVSNbYYQ71du7fTtrnfG1wgGTVR39tWSzBU-zwQ5hdV3rpMAaEbod5zeW6SHd95H3Bvcb43YiiqJFNL5sGZzFb7FqzVmpsZ1efiv6sZaGDHtnCAL6r12UG5EZuqGfM0jGCZitUz2m9TUKXJL5DJ7MOYbFfkCEsUBPDm_TInliSVn2kMJhFa0VOe5wZk5YOuYM3lNYW64HGtbf-llN2Xk-4O9TfeSPizBx9ZqGpeu8pz13efUDT2WL9tWo6-0UE-CrG0bScm8lFTncTkHcu49_a5NaUBkYlBjEiw.thPcx3t1AUcWuEygXIY3Fg", + Key: &key, + Name: "step-cli", + Type: "JWK", + }, + }, + NextCursor: "next", + } + + expected := map[string]any{ + "provisioners": []map[string]any{ + { + "type": "scep", + "name": "scep", + "forceCN": false, + "includeRoot": true, + "excludeIntermediate": true, + "challenge": "*** REDACTED ***", + "decrypterCertificate": []byte("*** REDACTED ***"), + "decrypterKey": "*** REDACTED ***", + "decrypterKeyPEM": []byte("*** REDACTED ***"), + "decrypterKeyPassword": "*** REDACTED ***", + "minimumPublicKeyLength": 2048, + "encryptionAlgorithmIdentifier": 2, + }, + { + "type": "JWK", + "name": "step-cli", + "key": map[string]any{ + "use": "sig", + "kty": "EC", + "kid": "4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc", + "crv": "P-256", + "alg": "ES256", + "x": "7ZdAAMZCFU4XwgblI5RfZouBi8lYmF6DlZusNNnsbm8", + "y": "sQr2JdzwD2fgyrymBEXWsxDxFNjjqN64qLLSbLdLZ9Y", + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlhOdmYxQjgxSUlLMFA2NUkwcmtGTGcifQ.XaN9zcPQeWt49zchUDm34FECUTHfQTn_.tmNHPQDqR3ebsWfd.9WZr3YVdeOyJh36vvx0VlRtluhvYp4K7jJ1KGDr1qypwZ3ziBVSNbYYQ71du7fTtrnfG1wgGTVR39tWSzBU-zwQ5hdV3rpMAaEbod5zeW6SHd95H3Bvcb43YiiqJFNL5sGZzFb7FqzVmpsZ1efiv6sZaGDHtnCAL6r12UG5EZuqGfM0jGCZitUz2m9TUKXJL5DJ7MOYbFfkCEsUBPDm_TInliSVn2kMJhFa0VOe5wZk5YOuYM3lNYW64HGtbf-llN2Xk-4O9TfeSPizBx9ZqGpeu8pz13efUDT2WL9tWo6-0UE-CrG0bScm8lFTncTkHcu49_a5NaUBkYlBjEiw.thPcx3t1AUcWuEygXIY3Fg", + }, + }, + "nextCursor": "next", + } + + expBytes, err := json.Marshal(expected) + sassert.NoError(t, err) + + br, err := r.MarshalJSON() + sassert.NoError(t, err) + sassert.JSONEq(t, string(expBytes), string(br)) + + keyCopy := key + expList := provisioner.List{ + &provisioner.SCEP{ + Name: "scep", + Type: "scep", + ChallengePassword: "not-so-secret", + MinimumPublicKeyLength: 2048, + EncryptionAlgorithmIdentifier: 2, + IncludeRoot: true, + ExcludeIntermediate: true, + DecrypterCertificate: []byte{1, 2, 3, 4}, + DecrypterKeyPEM: []byte{5, 6, 7, 8}, + DecrypterKeyURI: "softkms:path=/path/to/private.key", + DecrypterKeyPassword: "super-secret-password", + }, + &provisioner.JWK{ + EncryptedKey: "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlhOdmYxQjgxSUlLMFA2NUkwcmtGTGcifQ.XaN9zcPQeWt49zchUDm34FECUTHfQTn_.tmNHPQDqR3ebsWfd.9WZr3YVdeOyJh36vvx0VlRtluhvYp4K7jJ1KGDr1qypwZ3ziBVSNbYYQ71du7fTtrnfG1wgGTVR39tWSzBU-zwQ5hdV3rpMAaEbod5zeW6SHd95H3Bvcb43YiiqJFNL5sGZzFb7FqzVmpsZ1efiv6sZaGDHtnCAL6r12UG5EZuqGfM0jGCZitUz2m9TUKXJL5DJ7MOYbFfkCEsUBPDm_TInliSVn2kMJhFa0VOe5wZk5YOuYM3lNYW64HGtbf-llN2Xk-4O9TfeSPizBx9ZqGpeu8pz13efUDT2WL9tWo6-0UE-CrG0bScm8lFTncTkHcu49_a5NaUBkYlBjEiw.thPcx3t1AUcWuEygXIY3Fg", + Key: &keyCopy, + Name: "step-cli", + Type: "JWK", + }, + } + + // MarshalJSON must not affect the struct properties itself + sassert.Equal(t, expList, r.Provisioners) +} + +const ( + fixtureECDSACertificate = `ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgLnkvSk4odlo3b1R+RDw+LmorL3RkN354IilCIVFVen4AAAAIbmlzdHAyNTYAAABBBHjKHss8WM2ffMYlavisoLXR0I6UEIU+cidV1ogEH1U6+/SYaFPrlzQo0tGLM5CNkMbhInbyasQsrHzn8F1Rt7nHg5/tcSf9qwAAAAEAAAAGaGVybWFuAAAACgAAAAZoZXJtYW4AAAAAY8kvJwAAAABjyhBjAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAEEE/ayqpPrZZF5uA1UlDt4FreTf15agztQIzpxnWq/XoxAHzagRSkFGkdgFpjgsfiRpP8URHH3BZScqc0ZDCTxhoQAAAGQAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAEkAAAAhAJuP1wCVwoyrKrEtHGfFXrVbRHySDjvXtS1tVTdHyqymAAAAIBa/CSSzfZb4D2NLP+eEmOOMJwSjYOiNM8fiOoAaqglI herman` +) + +func TestLogSSHCertificate(t *testing.T) { + + out, _, _, _, err := ssh.ParseAuthorizedKey([]byte(fixtureECDSACertificate)) + require.NoError(t, err) + + cert, ok := out.(*ssh.Certificate) + require.True(t, ok) + + w := httptest.NewRecorder() + rl := logging.NewResponseLogger(w) + LogSSHCertificate(rl, cert) + + sassert.Equal(t, 200, w.Result().StatusCode) + + fields := rl.Fields() + sassert.Equal(t, uint64(14376510277651266987), fields["serial"]) + sassert.Equal(t, []string{"herman"}, fields["principals"]) + sassert.Equal(t, "ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate", fields["certificate-type"]) + sassert.Equal(t, time.Unix(1674129191, 0).Format(time.RFC3339), fields["valid-from"]) + sassert.Equal(t, time.Unix(1674186851, 0).Format(time.RFC3339), fields["valid-to"]) + sassert.Equal(t, "AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgLnkvSk4odlo3b1R+RDw+LmorL3RkN354IilCIVFVen4AAAAIbmlzdHAyNTYAAABBBHjKHss8WM2ffMYlavisoLXR0I6UEIU+cidV1ogEH1U6+/SYaFPrlzQo0tGLM5CNkMbhInbyasQsrHzn8F1Rt7nHg5/tcSf9qwAAAAEAAAAGaGVybWFuAAAACgAAAAZoZXJtYW4AAAAAY8kvJwAAAABjyhBjAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAEEE/ayqpPrZZF5uA1UlDt4FreTf15agztQIzpxnWq/XoxAHzagRSkFGkdgFpjgsfiRpP8URHH3BZScqc0ZDCTxhoQAAAGQAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAEkAAAAhAJuP1wCVwoyrKrEtHGfFXrVbRHySDjvXtS1tVTdHyqymAAAAIBa/CSSzfZb4D2NLP+eEmOOMJwSjYOiNM8fiOoAaqglI", fields["certificate"]) + sassert.Equal(t, "SHA256:RvkDPGwl/G9d7LUFm1kmWhvOD9I/moPq4yxcb0STwr0 (ECDSA-CERT)", fields["public-key"]) +} diff --git a/api/crl.go b/api/crl.go index 1a4d309a..6386f34a 100644 --- a/api/crl.go +++ b/api/crl.go @@ -17,13 +17,13 @@ func CRL(w http.ResponseWriter, r *http.Request) { _, formatAsPEM := r.URL.Query()["pem"] if formatAsPEM { - pemBytes := pem.EncodeToMemory(&pem.Block{ + w.Header().Add("Content-Type", "application/x-pem-file") + w.Header().Add("Content-Disposition", "attachment; filename=\"crl.pem\"") + + _ = pem.Encode(w, &pem.Block{ Type: "X509 CRL", Bytes: crlBytes, }) - w.Header().Add("Content-Type", "application/x-pem-file") - w.Header().Add("Content-Disposition", "attachment; filename=\"crl.pem\"") - w.Write(pemBytes) } else { w.Header().Add("Content-Type", "application/pkix-crl") w.Header().Add("Content-Disposition", "attachment; filename=\"crl.der\"") diff --git a/api/models/scep.go b/api/models/scep.go new file mode 100644 index 00000000..f4aa1502 --- /dev/null +++ b/api/models/scep.go @@ -0,0 +1,118 @@ +package models + +import ( + "context" + "crypto/x509" + "errors" + + "github.com/smallstep/certificates/authority/provisioner" + "golang.org/x/crypto/ssh" +) + +var errDummyImplementation = errors.New("dummy implementation") + +// SCEP is the SCEP provisioner model used solely in CA API +// responses. All methods for the [provisioner.Interface] interface +// are implemented, but return a dummy error. +// TODO(hs): remove reliance on the interface for the API responses +type SCEP struct { + ID string `json:"-"` + Type string `json:"type"` + Name string `json:"name"` + ForceCN bool `json:"forceCN"` + ChallengePassword string `json:"challenge"` + Capabilities []string `json:"capabilities,omitempty"` + IncludeRoot bool `json:"includeRoot"` + ExcludeIntermediate bool `json:"excludeIntermediate"` + MinimumPublicKeyLength int `json:"minimumPublicKeyLength"` + DecrypterCertificate []byte `json:"decrypterCertificate"` + DecrypterKeyPEM []byte `json:"decrypterKeyPEM"` + DecrypterKeyURI string `json:"decrypterKey"` + DecrypterKeyPassword string `json:"decrypterKeyPassword"` + EncryptionAlgorithmIdentifier int `json:"encryptionAlgorithmIdentifier"` + Options *provisioner.Options `json:"options,omitempty"` + Claims *provisioner.Claims `json:"claims,omitempty"` +} + +// GetID returns the provisioner unique identifier. +func (s *SCEP) GetID() string { + if s.ID != "" { + return s.ID + } + return s.GetIDForToken() +} + +// GetIDForToken returns an identifier that will be used to load the provisioner +// from a token. +func (s *SCEP) GetIDForToken() string { + return "scep/" + s.Name +} + +// GetName returns the name of the provisioner. +func (s *SCEP) GetName() string { + return s.Name +} + +// GetType returns the type of provisioner. +func (s *SCEP) GetType() provisioner.Type { + return provisioner.TypeSCEP +} + +// GetEncryptedKey returns the base provisioner encrypted key if it's defined. +func (s *SCEP) GetEncryptedKey() (string, string, bool) { + return "", "", false +} + +// GetTokenID returns the identifier of the token. +func (s *SCEP) GetTokenID(string) (string, error) { + return "", errDummyImplementation +} + +// Init initializes and validates the fields of a SCEP type. +func (s *SCEP) Init(_ provisioner.Config) (err error) { + return errDummyImplementation +} + +// AuthorizeSign returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for signing x509 Certificates. +func (s *SCEP) AuthorizeSign(context.Context, string) ([]provisioner.SignOption, error) { + return nil, errDummyImplementation +} + +// AuthorizeRevoke returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for revoking x509 Certificates. +func (s *SCEP) AuthorizeRevoke(context.Context, string) error { + return errDummyImplementation +} + +// AuthorizeRenew returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for renewing x509 Certificates. +func (s *SCEP) AuthorizeRenew(context.Context, *x509.Certificate) error { + return errDummyImplementation +} + +// AuthorizeSSHSign returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for signing SSH Certificates. +func (s *SCEP) AuthorizeSSHSign(context.Context, string) ([]provisioner.SignOption, error) { + return nil, errDummyImplementation +} + +// AuthorizeRevoke returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for revoking SSH Certificates. +func (s *SCEP) AuthorizeSSHRevoke(context.Context, string) error { + return errDummyImplementation +} + +// AuthorizeSSHRenew returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for renewing SSH Certificates. +func (s *SCEP) AuthorizeSSHRenew(context.Context, string) (*ssh.Certificate, error) { + return nil, errDummyImplementation +} + +// AuthorizeSSHRekey returns an unimplemented error. Provisioners should overwrite +// this method if they will support authorizing tokens for rekeying SSH Certificates. +func (s *SCEP) AuthorizeSSHRekey(context.Context, string) (*ssh.Certificate, []provisioner.SignOption, error) { + return nil, nil, errDummyImplementation +} + +var _ provisioner.Interface = (*SCEP)(nil) diff --git a/api/render/render.go b/api/render/render.go index 81a7a02e..7829ba25 100644 --- a/api/render/render.go +++ b/api/render/render.go @@ -2,7 +2,6 @@ package render import ( - "bytes" "encoding/json" "errors" "net/http" @@ -24,14 +23,25 @@ func JSON(w http.ResponseWriter, v interface{}) { // JSONStatus sets the Content-Type of w to application/json unless one is // specified. func JSONStatus(w http.ResponseWriter, v interface{}, status int) { - var b bytes.Buffer - if err := json.NewEncoder(&b).Encode(v); err != nil { - panic(err) - } - setContentTypeUnlessPresent(w, "application/json") w.WriteHeader(status) - _, _ = b.WriteTo(w) + + if err := json.NewEncoder(w).Encode(v); err != nil { + var errUnsupportedType *json.UnsupportedTypeError + if errors.As(err, &errUnsupportedType) { + panic(err) + } + + var errUnsupportedValue *json.UnsupportedValueError + if errors.As(err, &errUnsupportedValue) { + panic(err) + } + + var errMarshalError *json.MarshalerError + if errors.As(err, &errMarshalError) { + panic(err) + } + } log.EnabledResponse(w, v) } diff --git a/api/render/render_test.go b/api/render/render_test.go index 06d092d3..e88544c7 100644 --- a/api/render/render_test.go +++ b/api/render/render_test.go @@ -1,8 +1,10 @@ package render import ( + "encoding/json" "fmt" "io" + "math" "net/http" "net/http/httptest" "strconv" @@ -26,10 +28,43 @@ func TestJSON(t *testing.T) { assert.Empty(t, rw.Fields()) } -func TestJSONPanics(t *testing.T) { - assert.Panics(t, func() { - JSON(httptest.NewRecorder(), make(chan struct{})) - }) +func TestJSONPanicsOnUnsupportedType(t *testing.T) { + jsonPanicTest[json.UnsupportedTypeError](t, make(chan struct{})) +} + +func TestJSONPanicsOnUnsupportedValue(t *testing.T) { + jsonPanicTest[json.UnsupportedValueError](t, math.NaN()) +} + +func TestJSONPanicsOnMarshalerError(t *testing.T) { + var v erroneousJSONMarshaler + jsonPanicTest[json.MarshalerError](t, v) +} + +type erroneousJSONMarshaler struct{} + +func (erroneousJSONMarshaler) MarshalJSON() ([]byte, error) { + return nil, assert.AnError +} + +func jsonPanicTest[T json.UnsupportedTypeError | json.UnsupportedValueError | json.MarshalerError](t *testing.T, v any) { + t.Helper() + + defer func() { + var err error + if r := recover(); r == nil { + t.Fatal("expected panic") + } else if e, ok := r.(error); !ok { + t.Fatalf("did not panic with an error (%T)", r) + } else { + err = e + } + + var e *T + assert.ErrorAs(t, err, &e) + }() + + JSON(httptest.NewRecorder(), v) } type renderableError struct { diff --git a/api/sign.go b/api/sign.go index f7c3cc5a..c0c83ce2 100644 --- a/api/sign.go +++ b/api/sign.go @@ -88,6 +88,7 @@ func Sign(w http.ResponseWriter, r *http.Request) { if len(certChainPEM) > 1 { caPEM = certChainPEM[1] } + LogCertificate(w, certChain[0]) render.JSONStatus(w, &SignResponse{ ServerPEM: certChainPEM[0], diff --git a/api/ssh.go b/api/ssh.go index 4bd20495..fbaa8c5a 100644 --- a/api/ssh.go +++ b/api/ssh.go @@ -338,6 +338,7 @@ func SSHSign(w http.ResponseWriter, r *http.Request) { identityCertificate = certChainToPEM(certChain) } + LogSSHCertificate(w, cert) render.JSONStatus(w, &SSHSignResponse{ Certificate: SSHCertificate{cert}, AddUserCertificate: addUserCertificate, diff --git a/api/sshRekey.go b/api/sshRekey.go index 6c0a5064..80fc6d87 100644 --- a/api/sshRekey.go +++ b/api/sshRekey.go @@ -89,6 +89,7 @@ func SSHRekey(w http.ResponseWriter, r *http.Request) { return } + LogSSHCertificate(w, newCert) render.JSONStatus(w, &SSHRekeyResponse{ Certificate: SSHCertificate{newCert}, IdentityCertificate: identity, diff --git a/api/sshRenew.go b/api/sshRenew.go index 4e4d0b04..cd6d9bde 100644 --- a/api/sshRenew.go +++ b/api/sshRenew.go @@ -81,6 +81,7 @@ func SSHRenew(w http.ResponseWriter, r *http.Request) { return } + LogSSHCertificate(w, newCert) render.JSONStatus(w, &SSHSignResponse{ Certificate: SSHCertificate{newCert}, IdentityCertificate: identity, diff --git a/authority/admin/api/acme.go b/authority/admin/api/acme.go index 0ce8d4d7..32f2bdcc 100644 --- a/authority/admin/api/acme.go +++ b/authority/admin/api/acme.go @@ -69,17 +69,17 @@ func NewACMEAdminResponder() ACMEAdminResponder { } // GetExternalAccountKeys writes the response for the EAB keys GET endpoint -func (h *acmeAdminResponder) GetExternalAccountKeys(w http.ResponseWriter, r *http.Request) { +func (h *acmeAdminResponder) GetExternalAccountKeys(w http.ResponseWriter, _ *http.Request) { render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm")) } // CreateExternalAccountKey writes the response for the EAB key POST endpoint -func (h *acmeAdminResponder) CreateExternalAccountKey(w http.ResponseWriter, r *http.Request) { +func (h *acmeAdminResponder) CreateExternalAccountKey(w http.ResponseWriter, _ *http.Request) { render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm")) } // DeleteExternalAccountKey writes the response for the EAB key DELETE endpoint -func (h *acmeAdminResponder) DeleteExternalAccountKey(w http.ResponseWriter, r *http.Request) { +func (h *acmeAdminResponder) DeleteExternalAccountKey(w http.ResponseWriter, _ *http.Request) { render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm")) } diff --git a/authority/admin/api/acme_test.go b/authority/admin/api/acme_test.go index 6d478145..4c0af799 100644 --- a/authority/admin/api/acme_test.go +++ b/authority/admin/api/acme_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" @@ -128,7 +128,7 @@ func TestHandler_requireEABEnabled(t *testing.T) { for name, prep := range tests { tc := prep(t) t.Run(name, func(t *testing.T) { - req := httptest.NewRequest("GET", "/foo", nil).WithContext(tc.ctx) + req := httptest.NewRequest("GET", "/foo", http.NoBody).WithContext(tc.ctx) w := httptest.NewRecorder() requireEABEnabled(tc.next)(w, req) res := w.Result() @@ -223,7 +223,7 @@ func TestHandler_CreateExternalAccountKey(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { - req := httptest.NewRequest("POST", "/foo", nil) // chi routing is prepared in test setup + req := httptest.NewRequest("POST", "/foo", http.NoBody) // chi routing is prepared in test setup req = req.WithContext(tc.ctx) w := httptest.NewRecorder() acmeResponder := NewACMEAdminResponder() @@ -276,7 +276,7 @@ func TestHandler_DeleteExternalAccountKey(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { - req := httptest.NewRequest("DELETE", "/foo", nil) // chi routing is prepared in test setup + req := httptest.NewRequest("DELETE", "/foo", http.NoBody) // chi routing is prepared in test setup req = req.WithContext(tc.ctx) w := httptest.NewRecorder() acmeResponder := NewACMEAdminResponder() @@ -311,7 +311,7 @@ func TestHandler_GetExternalAccountKeys(t *testing.T) { "ok": func(t *testing.T) test { chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("provisionerName", "provName") - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) return test{ ctx: ctx, diff --git a/authority/admin/api/admin.go b/authority/admin/api/admin.go index c7adced3..e4d9d9fe 100644 --- a/authority/admin/api/admin.go +++ b/authority/admin/api/admin.go @@ -4,7 +4,7 @@ import ( "context" "net/http" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "go.step.sm/linkedca" diff --git a/authority/admin/api/admin_test.go b/authority/admin/api/admin_test.go index 3d4cdd9c..aae22056 100644 --- a/authority/admin/api/admin_test.go +++ b/authority/admin/api/admin_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "google.golang.org/protobuf/types/known/timestamppb" @@ -357,7 +357,7 @@ func TestHandler_GetAdmin(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { mockMustAuthority(t, tc.auth) - req := httptest.NewRequest("GET", "/foo", nil) // chi routing is prepared in test setup + req := httptest.NewRequest("GET", "/foo", http.NoBody) // chi routing is prepared in test setup req = req.WithContext(tc.ctx) w := httptest.NewRecorder() GetAdmin(w, req) @@ -406,7 +406,7 @@ func TestHandler_GetAdmins(t *testing.T) { } var tests = map[string]func(t *testing.T) test{ "fail/parse-cursor": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo?limit=A", nil) + req := httptest.NewRequest("GET", "/foo?limit=A", http.NoBody) return test{ ctx: context.Background(), req: req, @@ -420,7 +420,7 @@ func TestHandler_GetAdmins(t *testing.T) { } }, "fail/auth.GetAdmins": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) auth := &mockAdminAuthority{ MockGetAdmins: func(cursor string, limit int) ([]*linkedca.Admin, string, error) { assert.Equals(t, "", cursor) @@ -442,7 +442,7 @@ func TestHandler_GetAdmins(t *testing.T) { } }, "ok": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) createdAt := time.Now() var deletedAt time.Time adm1 := &linkedca.Admin{ @@ -764,7 +764,7 @@ func TestHandler_DeleteAdmin(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { mockMustAuthority(t, tc.auth) - req := httptest.NewRequest("DELETE", "/foo", nil) // chi routing is prepared in test setup + req := httptest.NewRequest("DELETE", "/foo", http.NoBody) // chi routing is prepared in test setup req = req.WithContext(tc.ctx) w := httptest.NewRecorder() DeleteAdmin(w, req) diff --git a/authority/admin/api/middleware.go b/authority/admin/api/middleware.go index 3c1b040a..fb29219f 100644 --- a/authority/admin/api/middleware.go +++ b/authority/admin/api/middleware.go @@ -4,7 +4,7 @@ import ( "errors" "net/http" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "go.step.sm/linkedca" diff --git a/authority/admin/api/middleware_test.go b/authority/admin/api/middleware_test.go index 4684b047..d166865f 100644 --- a/authority/admin/api/middleware_test.go +++ b/authority/admin/api/middleware_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "google.golang.org/protobuf/types/known/timestamppb" @@ -72,7 +72,7 @@ func TestHandler_requireAPIEnabled(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { mockMustAuthority(t, tc.auth) - req := httptest.NewRequest("GET", "/foo", nil) // chi routing is prepared in test setup + req := httptest.NewRequest("GET", "/foo", http.NoBody) // chi routing is prepared in test setup req = req.WithContext(tc.ctx) w := httptest.NewRecorder() requireAPIEnabled(tc.next)(w, req) @@ -113,7 +113,7 @@ func TestHandler_extractAuthorizeTokenAdmin(t *testing.T) { } var tests = map[string]func(t *testing.T) test{ "fail/missing-authorization-token": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req.Header["Authorization"] = []string{""} return test{ ctx: context.Background(), @@ -128,7 +128,7 @@ func TestHandler_extractAuthorizeTokenAdmin(t *testing.T) { } }, "fail/auth.AuthorizeAdminToken": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req.Header["Authorization"] = []string{"token"} auth := &mockAdminAuthority{ MockAuthorizeAdminToken: func(r *http.Request, token string) (*linkedca.Admin, error) { @@ -153,7 +153,7 @@ func TestHandler_extractAuthorizeTokenAdmin(t *testing.T) { } }, "ok": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req.Header["Authorization"] = []string{"token"} createdAt := time.Now() var deletedAt time.Time @@ -324,7 +324,7 @@ func TestHandler_loadProvisionerByName(t *testing.T) { t.Run(name, func(t *testing.T) { mockMustAuthority(t, tc.auth) ctx := admin.NewContext(tc.ctx, tc.adminDB) - req := httptest.NewRequest("GET", "/foo", nil) // chi routing is prepared in test setup + req := httptest.NewRequest("GET", "/foo", http.NoBody) // chi routing is prepared in test setup req = req.WithContext(ctx) w := httptest.NewRecorder() @@ -399,7 +399,7 @@ func TestHandler_checkAction(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { ctx := admin.NewContext(context.Background(), tc.adminDB) - req := httptest.NewRequest("GET", "/foo", nil).WithContext(ctx) + req := httptest.NewRequest("GET", "/foo", http.NoBody).WithContext(ctx) w := httptest.NewRecorder() checkAction(tc.next, tc.supportedInStandalone)(w, req) res := w.Result() @@ -643,7 +643,7 @@ func TestHandler_loadExternalAccountKey(t *testing.T) { tc := prep(t) t.Run(name, func(t *testing.T) { ctx := acme.NewDatabaseContext(tc.ctx, tc.acmeDB) - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() loadExternalAccountKey(tc.next)(w, req) diff --git a/authority/admin/api/policy_test.go b/authority/admin/api/policy_test.go index 1ec88fb6..159fc0e1 100644 --- a/authority/admin/api/policy_test.go +++ b/authority/admin/api/policy_test.go @@ -241,7 +241,7 @@ func TestPolicyAdminResponder_GetAuthorityPolicy(t *testing.T) { ctx := admin.NewContext(tc.ctx, tc.adminDB) par := NewPolicyAdminResponder() - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() @@ -1164,7 +1164,7 @@ func TestPolicyAdminResponder_GetProvisionerPolicy(t *testing.T) { ctx = acme.NewDatabaseContext(ctx, tc.acmeDB) par := NewPolicyAdminResponder() - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() @@ -1986,7 +1986,7 @@ func TestPolicyAdminResponder_GetACMEAccountPolicy(t *testing.T) { ctx = acme.NewDatabaseContext(ctx, tc.acmeDB) par := NewPolicyAdminResponder() - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) req = req.WithContext(ctx) w := httptest.NewRecorder() diff --git a/authority/admin/api/provisioner.go b/authority/admin/api/provisioner.go index c584361b..d44e9e03 100644 --- a/authority/admin/api/provisioner.go +++ b/authority/admin/api/provisioner.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "go.step.sm/crypto/sshutil" "go.step.sm/crypto/x509util" diff --git a/authority/admin/api/provisioner_test.go b/authority/admin/api/provisioner_test.go index 86f8a31b..9860d824 100644 --- a/authority/admin/api/provisioner_test.go +++ b/authority/admin/api/provisioner_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "google.golang.org/protobuf/encoding/protojson" @@ -37,7 +37,7 @@ func TestHandler_GetProvisioner(t *testing.T) { } var tests = map[string]func(t *testing.T) test{ "fail/auth.LoadProvisionerByID": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo?id=provID", nil) + req := httptest.NewRequest("GET", "/foo?id=provID", http.NoBody) chiCtx := chi.NewRouteContext() ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) auth := &mockAdminAuthority{ @@ -61,7 +61,7 @@ func TestHandler_GetProvisioner(t *testing.T) { } }, "fail/auth.LoadProvisionerByName": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("name", "provName") ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) @@ -86,7 +86,7 @@ func TestHandler_GetProvisioner(t *testing.T) { } }, "fail/db.GetProvisioner": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("name", "provName") ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) @@ -120,7 +120,7 @@ func TestHandler_GetProvisioner(t *testing.T) { } }, "ok": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("name", "provName") ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) @@ -208,7 +208,7 @@ func TestHandler_GetProvisioners(t *testing.T) { } var tests = map[string]func(t *testing.T) test{ "fail/parse-cursor": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo?limit=X", nil) + req := httptest.NewRequest("GET", "/foo?limit=X", http.NoBody) return test{ ctx: context.Background(), statusCode: 400, @@ -222,7 +222,7 @@ func TestHandler_GetProvisioners(t *testing.T) { } }, "fail/auth.GetProvisioners": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) auth := &mockAdminAuthority{ MockGetProvisioners: func(cursor string, limit int) (provisioner.List, string, error) { assert.Equals(t, "", cursor) @@ -244,7 +244,7 @@ func TestHandler_GetProvisioners(t *testing.T) { } }, "ok": func(t *testing.T) test { - req := httptest.NewRequest("GET", "/foo", nil) + req := httptest.NewRequest("GET", "/foo", http.NoBody) provisioners := provisioner.List{ &provisioner.OIDC{ Type: "OIDC", @@ -481,7 +481,7 @@ func TestHandler_DeleteProvisioner(t *testing.T) { } var tests = map[string]func(t *testing.T) test{ "fail/auth.LoadProvisionerByID": func(t *testing.T) test { - req := httptest.NewRequest("DELETE", "/foo?id=provID", nil) + req := httptest.NewRequest("DELETE", "/foo?id=provID", http.NoBody) chiCtx := chi.NewRouteContext() ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) auth := &mockAdminAuthority{ @@ -504,7 +504,7 @@ func TestHandler_DeleteProvisioner(t *testing.T) { } }, "fail/auth.LoadProvisionerByName": func(t *testing.T) test { - req := httptest.NewRequest("DELETE", "/foo", nil) + req := httptest.NewRequest("DELETE", "/foo", http.NoBody) chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("name", "provName") ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) @@ -528,7 +528,7 @@ func TestHandler_DeleteProvisioner(t *testing.T) { } }, "fail/auth.RemoveProvisioner": func(t *testing.T) test { - req := httptest.NewRequest("DELETE", "/foo", nil) + req := httptest.NewRequest("DELETE", "/foo", http.NoBody) chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("name", "provName") ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) @@ -560,7 +560,7 @@ func TestHandler_DeleteProvisioner(t *testing.T) { } }, "ok": func(t *testing.T) test { - req := httptest.NewRequest("DELETE", "/foo", nil) + req := httptest.NewRequest("DELETE", "/foo", http.NoBody) chiCtx := chi.NewRouteContext() chiCtx.URLParams.Add("name", "provName") ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) diff --git a/authority/admin/api/webhook.go b/authority/admin/api/webhook.go index f73f6806..f01ddb65 100644 --- a/authority/admin/api/webhook.go +++ b/authority/admin/api/webhook.go @@ -6,7 +6,7 @@ import ( "net/http" "net/url" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/smallstep/certificates/api/read" "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority/admin" @@ -56,10 +56,8 @@ func validateWebhook(webhook *linkedca.Webhook) error { } // kind - switch webhook.Kind { - case linkedca.Webhook_ENRICHING, linkedca.Webhook_AUTHORIZING: - default: - return admin.NewError(admin.ErrorBadRequestType, "webhook kind is invalid") + if _, ok := linkedca.Webhook_Kind_name[int32(webhook.Kind)]; !ok || webhook.Kind == linkedca.Webhook_NO_KIND { + return admin.NewError(admin.ErrorBadRequestType, "webhook kind %q is invalid", webhook.Kind) } return nil diff --git a/authority/admin/api/webhook_test.go b/authority/admin/api/webhook_test.go index baac2c11..8f4ee1a2 100644 --- a/authority/admin/api/webhook_test.go +++ b/authority/admin/api/webhook_test.go @@ -6,11 +6,12 @@ import ( "encoding/json" "errors" "io" + "net/http" "net/http/httptest" "strings" "testing" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/admin" "github.com/stretchr/testify/assert" @@ -180,6 +181,26 @@ func TestWebhookAdminResponder_CreateProvisionerWebhook(t *testing.T) { statusCode: 400, } }, + "fail/unsupported-webhook-kind": func(t *testing.T) test { + prov := &linkedca.Provisioner{ + Name: "provName", + } + ctx := linkedca.NewContextWithProvisioner(context.Background(), prov) + adminErr := admin.NewError(admin.ErrorBadRequestType, `(line 5:13): invalid value for enum type: "UNSUPPORTED"`) + adminErr.Message = `(line 5:13): invalid value for enum type: "UNSUPPORTED"` + body := []byte(` + { + "name": "metadata", + "url": "https://example.com", + "kind": "UNSUPPORTED", + }`) + return test{ + ctx: ctx, + body: body, + err: adminErr, + statusCode: 400, + } + }, "fail/auth.UpdateProvisioner-error": func(t *testing.T) test { adm := &linkedca.Admin{ Subject: "step", @@ -355,7 +376,7 @@ func TestWebhookAdminResponder_DeleteProvisionerWebhook(t *testing.T) { } ctx = linkedca.NewContextWithProvisioner(ctx, prov) ctx = admin.NewContext(ctx, &admin.MockDB{}) - req := httptest.NewRequest("DELETE", "/foo", nil).WithContext(ctx) + req := httptest.NewRequest("DELETE", "/foo", http.NoBody).WithContext(ctx) war := NewWebhookAdminResponder() diff --git a/authority/admin/db/nosql/admin.go b/authority/admin/db/nosql/admin.go index c0f90c2f..e30cea3a 100644 --- a/authority/admin/db/nosql/admin.go +++ b/authority/admin/db/nosql/admin.go @@ -40,7 +40,7 @@ func (dba *dbAdmin) clone() *dbAdmin { return &u } -func (db *DB) getDBAdminBytes(ctx context.Context, id string) ([]byte, error) { +func (db *DB) getDBAdminBytes(_ context.Context, id string) ([]byte, error) { data, err := db.db.Get(adminsTable, []byte(id)) if nosql.IsErrNotFound(err) { return nil, admin.NewError(admin.ErrorNotFoundType, "admin %s not found", id) @@ -102,7 +102,7 @@ func (db *DB) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) // GetAdmins retrieves and unmarshals all active (not deleted) admins // from the database. // TODO should we be paginating? -func (db *DB) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) { +func (db *DB) GetAdmins(context.Context) ([]*linkedca.Admin, error) { dbEntries, err := db.db.List(adminsTable) if err != nil { return nil, errors.Wrap(err, "error loading admins") @@ -115,12 +115,10 @@ func (db *DB) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) { if errors.As(err, &ae) { if ae.IsType(admin.ErrorDeletedType) || ae.IsType(admin.ErrorAuthorityMismatchType) { continue - } else { - return nil, err } - } else { return nil, err } + return nil, err } if adm.AuthorityId != db.authorityID { continue diff --git a/authority/admin/db/nosql/nosql.go b/authority/admin/db/nosql/nosql.go index 32e05d92..02acf72a 100644 --- a/authority/admin/db/nosql/nosql.go +++ b/authority/admin/db/nosql/nosql.go @@ -36,7 +36,7 @@ func New(db nosqlDB.DB, authorityID string) (*DB, error) { // save writes the new data to the database, overwriting the old data if it // existed. -func (db *DB) save(ctx context.Context, id string, nu, old interface{}, typ string, table []byte) error { +func (db *DB) save(_ context.Context, id string, nu, old interface{}, typ string, table []byte) error { var ( err error newB []byte diff --git a/authority/admin/db/nosql/policy.go b/authority/admin/db/nosql/policy.go index 3023a3f6..0a529383 100644 --- a/authority/admin/db/nosql/policy.go +++ b/authority/admin/db/nosql/policy.go @@ -71,7 +71,7 @@ func (dbap *dbAuthorityPolicy) convert() *linkedca.Policy { return dbToLinked(dbap.Policy) } -func (db *DB) getDBAuthorityPolicyBytes(ctx context.Context, authorityID string) ([]byte, error) { +func (db *DB) getDBAuthorityPolicyBytes(_ context.Context, authorityID string) ([]byte, error) { data, err := db.db.Get(authorityPoliciesTable, []byte(authorityID)) if nosql.IsErrNotFound(err) { return nil, admin.NewError(admin.ErrorNotFoundType, "authority policy not found") diff --git a/authority/admin/db/nosql/provisioner.go b/authority/admin/db/nosql/provisioner.go index da116e0b..05b077f3 100644 --- a/authority/admin/db/nosql/provisioner.go +++ b/authority/admin/db/nosql/provisioner.go @@ -70,7 +70,7 @@ func (dbp *dbProvisioner) convert2linkedca() (*linkedca.Provisioner, error) { }, nil } -func (db *DB) getDBProvisionerBytes(ctx context.Context, id string) ([]byte, error) { +func (db *DB) getDBProvisionerBytes(_ context.Context, id string) ([]byte, error) { data, err := db.db.Get(provisionersTable, []byte(id)) if nosql.IsErrNotFound(err) { return nil, admin.NewError(admin.ErrorNotFoundType, "provisioner %s not found", id) @@ -132,7 +132,7 @@ func (db *DB) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisio // GetProvisioners retrieves and unmarshals all active (not deleted) provisioners // from the database. -func (db *DB) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) { +func (db *DB) GetProvisioners(_ context.Context) ([]*linkedca.Provisioner, error) { dbEntries, err := db.db.List(provisionersTable) if err != nil { return nil, errors.Wrap(err, "error loading provisioners") @@ -145,12 +145,10 @@ func (db *DB) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, err if errors.As(err, &ae) { if ae.IsType(admin.ErrorDeletedType) || ae.IsType(admin.ErrorAuthorityMismatchType) { continue - } else { - return nil, err } - } else { return nil, err } + return nil, err } if prov.AuthorityId != db.authorityID { continue diff --git a/authority/authority.go b/authority/authority.go index 7904a7ea..a4a76293 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto" + "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/hex" @@ -61,7 +62,9 @@ type Authority struct { x509Enforcers []provisioner.CertificateEnforcer // SCEP CA - scepService *scep.Service + scepOptions *scep.Options + validateSCEP bool + scepAuthority *scep.Authority // SSH CA sshHostPassword []byte @@ -122,6 +125,7 @@ func New(cfg *config.Config, opts ...Option) (*Authority, error) { var a = &Authority{ config: cfg, certificates: new(sync.Map), + validateSCEP: true, } // Apply options. @@ -261,6 +265,24 @@ func (a *Authority) ReloadAdminResources(ctx context.Context) error { a.config.AuthorityConfig.Admins = adminList a.admins = adminClxn + switch { + case a.requiresSCEP() && a.GetSCEP() == nil: + // TODO(hs): try to initialize SCEP here too? It's a bit + // problematic if this method is called as part of an update + // via Admin API and a password needs to be provided. + case a.requiresSCEP() && a.GetSCEP() != nil: + // update the SCEP Authority with the currently active SCEP + // provisioner names and revalidate the configuration. + a.scepAuthority.UpdateProvisioners(a.getSCEPProvisionerNames()) + if err := a.scepAuthority.Validate(); err != nil { + log.Printf("failed validating SCEP authority: %v\n", err) + } + case !a.requiresSCEP() && a.GetSCEP() != nil: + // TODO(hs): don't remove the authority if we can't also + // reload it. + //a.scepAuthority = nil + } + return nil } @@ -545,50 +567,6 @@ func (a *Authority) init() error { tmplVars.SSH.UserFederatedKeys = append(tmplVars.SSH.UserFederatedKeys, a.sshCAUserFederatedCerts...) } - // Check if a KMS with decryption capability is required and available - if a.requiresDecrypter() { - if _, ok := a.keyManager.(kmsapi.Decrypter); !ok { - return errors.New("keymanager doesn't provide crypto.Decrypter") - } - } - - // TODO: decide if this is a good approach for providing the SCEP functionality - // It currently mirrors the logic for the x509CAService - if a.requiresSCEPService() && a.scepService == nil { - var options scep.Options - - // Read intermediate and create X509 signer and decrypter for default CAS. - options.CertificateChain, err = pemutil.ReadCertificateBundle(a.config.IntermediateCert) - if err != nil { - return err - } - options.CertificateChain = append(options.CertificateChain, a.rootX509Certs...) - options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ - SigningKey: a.config.IntermediateKey, - Password: a.password, - }) - if err != nil { - return err - } - - if km, ok := a.keyManager.(kmsapi.Decrypter); ok { - options.Decrypter, err = km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ - DecryptionKey: a.config.IntermediateKey, - Password: a.password, - }) - if err != nil { - return err - } - } - - a.scepService, err = scep.NewService(ctx, options) - if err != nil { - return err - } - - // TODO: mimick the x509CAService GetCertificateAuthority here too? - } - if a.config.AuthorityConfig.EnableAdmin { // Initialize step-ca Admin Database if it's not already initialized using // WithAdminDB. @@ -684,6 +662,85 @@ func (a *Authority) init() error { return err } + // The SCEP functionality is provided through an instance of + // scep.Authority. It is initialized when the CA is started and + // if it doesn't exist yet. It gets refreshed if it already + // exists. If the SCEP authority is no longer required on reload, + // it gets removed. + // TODO(hs): reloading through SIGHUP doesn't hit these cases. This + // is because an entirely new authority.Authority is created, including + // a new scep.Authority. Look into this to see if we want this to + // keep working like that, or want to reuse a single instance and + // update that. + switch { + case a.requiresSCEP() && a.GetSCEP() == nil: + if a.scepOptions == nil { + options := &scep.Options{ + Roots: a.rootX509Certs, + Intermediates: a.intermediateX509Certs, + SignerCert: a.intermediateX509Certs[0], + } + if options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ + SigningKey: a.config.IntermediateKey, + Password: a.password, + }); err != nil { + return err + } + // TODO(hs): instead of creating the decrypter here, pass the + // intermediate key + chain down to the SCEP authority, + // and only instantiate it when required there. Is that possible? + // Also with entering passwords? + // TODO(hs): if moving the logic, try improving the logic for the + // decrypter password too? Right now it needs to be entered multiple + // times; I've observed it to be three times maximum, every time + // the intermediate key is read. + _, isRSA := options.Signer.Public().(*rsa.PublicKey) + if km, ok := a.keyManager.(kmsapi.Decrypter); ok && isRSA { + if decrypter, err := km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ + DecryptionKey: a.config.IntermediateKey, + Password: a.password, + }); err == nil { + // only pass the decrypter down when it was successfully created, + // meaning it's an RSA key, and `CreateDecrypter` did not fail. + options.Decrypter = decrypter + options.DecrypterCert = options.Intermediates[0] + } + } + + a.scepOptions = options + } + + // provide the current SCEP provisioner names, so that the provisioners + // can be validated when the CA is started. + a.scepOptions.SCEPProvisionerNames = a.getSCEPProvisionerNames() + + // create a new SCEP authority + scepAuthority, err := scep.New(a, *a.scepOptions) + if err != nil { + return err + } + + if a.validateSCEP { + // validate the SCEP authority + if err := scepAuthority.Validate(); err != nil { + a.initLogf("failed validating SCEP authority: %v", err) + } + } + + // set the SCEP authority + a.scepAuthority = scepAuthority + case !a.requiresSCEP() && a.GetSCEP() != nil: + // clear the SCEP authority if it's no longer required + a.scepAuthority = nil + case a.requiresSCEP() && a.GetSCEP() != nil: + // update the SCEP Authority with the currently active SCEP + // provisioner names and revalidate the configuration. + a.scepAuthority.UpdateProvisioners(a.getSCEPProvisionerNames()) + if err := a.scepAuthority.Validate(); err != nil { + log.Printf("failed validating SCEP authority: %v\n", err) + } + } + // Load X509 constraints engine. // // This is currently only available in CA mode. @@ -833,17 +890,9 @@ func (a *Authority) IsRevoked(sn string) (bool, error) { return a.db.IsRevoked(sn) } -// requiresDecrypter returns whether the Authority -// requires a KMS that provides a crypto.Decrypter -// Currently this is only required when SCEP is -// enabled. -func (a *Authority) requiresDecrypter() bool { - return a.requiresSCEPService() -} - -// requiresSCEPService iterates over the configured provisioners -// and determines if one of them is a SCEP provisioner. -func (a *Authority) requiresSCEPService() bool { +// requiresSCEP iterates over the configured provisioners +// and determines if at least one of them is a SCEP provisioner. +func (a *Authority) requiresSCEP() bool { for _, p := range a.config.AuthorityConfig.Provisioners { if p.GetType() == provisioner.TypeSCEP { return true @@ -852,13 +901,21 @@ func (a *Authority) requiresSCEPService() bool { return false } -// GetSCEPService returns the configured SCEP Service. -// -// TODO: this function is intended to exist temporarily in order to make SCEP -// work more easily. It can be made more correct by using the right -// interfaces/abstractions after it works as expected. -func (a *Authority) GetSCEPService() *scep.Service { - return a.scepService +// getSCEPProvisionerNames returns the names of the SCEP provisioners +// that are currently available in the CA. +func (a *Authority) getSCEPProvisionerNames() (names []string) { + for _, p := range a.config.AuthorityConfig.Provisioners { + if p.GetType() == provisioner.TypeSCEP { + names = append(names, p.GetName()) + } + } + + return +} + +// GetSCEP returns the configured SCEP Authority +func (a *Authority) GetSCEP() *scep.Authority { + return a.scepAuthority } func (a *Authority) startCRLGenerator() error { diff --git a/authority/authority_test.go b/authority/authority_test.go index 82a05a3e..45c7cd86 100644 --- a/authority/authority_test.go +++ b/authority/authority_test.go @@ -478,7 +478,7 @@ func testScepAuthority(t *testing.T, opts ...Option) *Authority { return a } -func TestAuthority_GetSCEPService(t *testing.T) { +func TestAuthority_GetSCEP(t *testing.T) { _ = testScepAuthority(t) p := provisioner.List{ &provisioner.SCEP{ @@ -542,7 +542,7 @@ func TestAuthority_GetSCEPService(t *testing.T) { return } if tt.wantService { - if got := a.GetSCEPService(); (got != nil) != tt.wantService { + if got := a.GetSCEP(); (got != nil) != tt.wantService { t.Errorf("Authority.GetSCEPService() = %v, wantService %v", got, tt.wantService) } } diff --git a/authority/authorize.go b/authority/authorize.go index 1e50da89..1e35afe0 100644 --- a/authority/authorize.go +++ b/authority/authorize.go @@ -177,7 +177,7 @@ func (a *Authority) AuthorizeAdminToken(r *http.Request, token string) (*linkedc if !adminFound { return nil, admin.NewError(admin.ErrorUnauthorizedType, "adminHandler.authorizeToken; unable to load admin with subject(s) %s and provisioner '%s'", - adminSANs, claims.Issuer) + adminSANs, prov.GetName()) } if strings.HasPrefix(r.URL.Path, "/admin/admins") && (r.Method != "GET") && adm.Type != linkedca.Admin_SUPER_ADMIN { @@ -315,7 +315,7 @@ func (a *Authority) authorizeRenew(ctx context.Context, cert *x509.Certificate) } // authorizeSSHCertificate returns an error if the given certificate is revoked. -func (a *Authority) authorizeSSHCertificate(ctx context.Context, cert *ssh.Certificate) error { +func (a *Authority) authorizeSSHCertificate(_ context.Context, cert *ssh.Certificate) error { var err error var isRevoked bool @@ -394,7 +394,7 @@ func (a *Authority) authorizeSSHRevoke(ctx context.Context, token string) error // AuthorizeRenewToken validates the renew token and returns the leaf // certificate in the x5cInsecure header. -func (a *Authority) AuthorizeRenewToken(ctx context.Context, ott string) (*x509.Certificate, error) { +func (a *Authority) AuthorizeRenewToken(_ context.Context, ott string) (*x509.Certificate, error) { var claims jose.Claims jwt, chain, err := jose.ParseX5cInsecure(ott, a.rootX509Certs) if err != nil { diff --git a/authority/config/config.go b/authority/config/config.go index 556f5407..ba581d8a 100644 --- a/authority/config/config.go +++ b/authority/config/config.go @@ -1,6 +1,7 @@ package config import ( + "bytes" "encoding/json" "fmt" "net" @@ -35,6 +36,9 @@ var ( // DefaultEnableSSHCA enable SSH CA features per provisioner or globally // for all provisioners. DefaultEnableSSHCA = false + // DefaultDisableSmallstepExtensions is the default value for the + // DisableSmallstepExtensions provisioner claim. + DefaultDisableSmallstepExtensions = false // DefaultCRLCacheDuration is the default cache duration for the CRL. DefaultCRLCacheDuration = &provisioner.Duration{Duration: 24 * time.Hour} // DefaultCRLExpiredDuration is the default duration in which expired @@ -43,18 +47,19 @@ var ( // GlobalProvisionerClaims is the default duration that expired certificates // remain in the CRL after expiration. GlobalProvisionerClaims = provisioner.Claims{ - MinTLSDur: &provisioner.Duration{Duration: 5 * time.Minute}, // TLS certs - MaxTLSDur: &provisioner.Duration{Duration: 24 * time.Hour}, - DefaultTLSDur: &provisioner.Duration{Duration: 24 * time.Hour}, - MinUserSSHDur: &provisioner.Duration{Duration: 5 * time.Minute}, // User SSH certs - MaxUserSSHDur: &provisioner.Duration{Duration: 24 * time.Hour}, - DefaultUserSSHDur: &provisioner.Duration{Duration: 16 * time.Hour}, - MinHostSSHDur: &provisioner.Duration{Duration: 5 * time.Minute}, // Host SSH certs - MaxHostSSHDur: &provisioner.Duration{Duration: 30 * 24 * time.Hour}, - DefaultHostSSHDur: &provisioner.Duration{Duration: 30 * 24 * time.Hour}, - EnableSSHCA: &DefaultEnableSSHCA, - DisableRenewal: &DefaultDisableRenewal, - AllowRenewalAfterExpiry: &DefaultAllowRenewalAfterExpiry, + MinTLSDur: &provisioner.Duration{Duration: 5 * time.Minute}, // TLS certs + MaxTLSDur: &provisioner.Duration{Duration: 24 * time.Hour}, + DefaultTLSDur: &provisioner.Duration{Duration: 24 * time.Hour}, + MinUserSSHDur: &provisioner.Duration{Duration: 5 * time.Minute}, // User SSH certs + MaxUserSSHDur: &provisioner.Duration{Duration: 24 * time.Hour}, + DefaultUserSSHDur: &provisioner.Duration{Duration: 16 * time.Hour}, + MinHostSSHDur: &provisioner.Duration{Duration: 5 * time.Minute}, // Host SSH certs + MaxHostSSHDur: &provisioner.Duration{Duration: 30 * 24 * time.Hour}, + DefaultHostSSHDur: &provisioner.Duration{Duration: 30 * 24 * time.Hour}, + EnableSSHCA: &DefaultEnableSSHCA, + DisableRenewal: &DefaultDisableRenewal, + AllowRenewalAfterExpiry: &DefaultAllowRenewalAfterExpiry, + DisableSmallstepExtensions: &DefaultDisableSmallstepExtensions, } ) @@ -182,7 +187,7 @@ func (c *AuthConfig) init() { } // Validate validates the authority configuration. -func (c *AuthConfig) Validate(audiences provisioner.Audiences) error { +func (c *AuthConfig) Validate(provisioner.Audiences) error { if c == nil { return errors.New("authority cannot be undefined") } @@ -254,15 +259,16 @@ func (c *Config) Init() { // Save saves the configuration to the given filename. func (c *Config) Save(filename string) error { - f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return errors.Wrapf(err, "error opening %s", filename) - } - defer f.Close() - - enc := json.NewEncoder(f) + var b bytes.Buffer + enc := json.NewEncoder(&b) enc.SetIndent("", "\t") - return errors.Wrapf(enc.Encode(c), "error writing %s", filename) + if err := enc.Encode(c); err != nil { + return fmt.Errorf("error encoding configuration: %w", err) + } + if err := os.WriteFile(filename, b.Bytes(), 0600); err != nil { + return fmt.Errorf("error writing %q: %w", filename, err) + } + return nil } // Commit saves the current configuration to the same diff --git a/authority/linkedca.go b/authority/linkedca.go index 78afb243..3eaa76c9 100644 --- a/authority/linkedca.go +++ b/authority/linkedca.go @@ -381,19 +381,19 @@ func (c *linkedCaClient) IsSSHRevoked(serial string) (bool, error) { return resp.Status != linkedca.RevocationStatus_ACTIVE, nil } -func (c *linkedCaClient) CreateAuthorityPolicy(ctx context.Context, policy *linkedca.Policy) error { +func (c *linkedCaClient) CreateAuthorityPolicy(_ context.Context, _ *linkedca.Policy) error { return errors.New("not implemented yet") } -func (c *linkedCaClient) GetAuthorityPolicy(ctx context.Context) (*linkedca.Policy, error) { +func (c *linkedCaClient) GetAuthorityPolicy(context.Context) (*linkedca.Policy, error) { return nil, errors.New("not implemented yet") } -func (c *linkedCaClient) UpdateAuthorityPolicy(ctx context.Context, policy *linkedca.Policy) error { +func (c *linkedCaClient) UpdateAuthorityPolicy(_ context.Context, _ *linkedca.Policy) error { return errors.New("not implemented yet") } -func (c *linkedCaClient) DeleteAuthorityPolicy(ctx context.Context) error { +func (c *linkedCaClient) DeleteAuthorityPolicy(context.Context) error { return errors.New("not implemented yet") } diff --git a/authority/options.go b/authority/options.go index bf443ed6..4fc5a20f 100644 --- a/authority/options.go +++ b/authority/options.go @@ -18,6 +18,7 @@ import ( "github.com/smallstep/certificates/cas" casapi "github.com/smallstep/certificates/cas/apiv1" "github.com/smallstep/certificates/db" + "github.com/smallstep/certificates/scep" ) // Option sets options to the Authority. @@ -205,6 +206,17 @@ func WithX509SignerFunc(fn func() ([]*x509.Certificate, crypto.Signer, error)) O } } +// WithFullSCEPOptions defines the options used for SCEP support. +// +// This feature is EXPERIMENTAL and might change at any time. +func WithFullSCEPOptions(options *scep.Options) Option { + return func(a *Authority) error { + a.scepOptions = options + a.validateSCEP = false + return nil + } +} + // WithSSHUserSigner defines the signer used to sign SSH user certificates. func WithSSHUserSigner(s crypto.Signer) Option { return func(a *Authority) error { diff --git a/authority/policy.go b/authority/policy.go index 38a57bec..986b45b8 100644 --- a/authority/policy.go +++ b/authority/policy.go @@ -154,7 +154,7 @@ func (a *Authority) checkProvisionerPolicy(ctx context.Context, provName string, // checkPolicy checks if a new or updated policy configuration results in the user // locking themselves or other admins out of the CA. -func (a *Authority) checkPolicy(ctx context.Context, currentAdmin *linkedca.Admin, otherAdmins []*linkedca.Admin, p *linkedca.Policy) error { +func (a *Authority) checkPolicy(_ context.Context, currentAdmin *linkedca.Admin, otherAdmins []*linkedca.Admin, p *linkedca.Policy) error { // convert the policy; return early if nil policyOptions := authPolicy.LinkedToCertificates(p) if policyOptions == nil { diff --git a/authority/provisioner/acme.go b/authority/provisioner/acme.go index 38510af7..96f37d58 100644 --- a/authority/provisioner/acme.go +++ b/authority/provisioner/acme.go @@ -133,7 +133,7 @@ func (p *ACME) GetIDForToken() string { } // GetTokenID returns the identifier of the token. -func (p *ACME) GetTokenID(ott string) (string, error) { +func (p *ACME) GetTokenID(string) (string, error) { return "", errors.New("acme provisioner does not implement GetTokenID") } @@ -228,7 +228,7 @@ type ACMEIdentifier struct { // AuthorizeOrderIdentifier verifies the provisioner is allowed to issue a // certificate for an ACME Order Identifier. -func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier ACMEIdentifier) error { +func (p *ACME) AuthorizeOrderIdentifier(_ context.Context, identifier ACMEIdentifier) error { x509Policy := p.ctl.getPolicy().getX509() // identifier is allowed if no policy is configured @@ -253,11 +253,11 @@ func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier ACMEIden // AuthorizeSign does not do any validation, because all validation is handled // in the ACME protocol. This method returns a list of modifiers / constraints // on the resulting certificate. -func (p *ACME) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *ACME) AuthorizeSign(context.Context, string) ([]SignOption, error) { opts := []SignOption{ p, // modifiers / withOptions - newProvisionerExtensionOption(TypeACME, p.Name, ""), + newProvisionerExtensionOption(TypeACME, p.Name, "").WithControllerOptions(p.ctl), newForceCNOption(p.ForceCN), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators @@ -274,7 +274,7 @@ func (p *ACME) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e // the CA. It can be used to authorize revocation of a certificate. With the // ACME protocol, revocation authorization is specified and performed as part // of the client/server interaction, so this is a no-op. -func (p *ACME) AuthorizeRevoke(ctx context.Context, token string) error { +func (p *ACME) AuthorizeRevoke(context.Context, string) error { return nil } @@ -289,7 +289,7 @@ func (p *ACME) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error // IsChallengeEnabled checks if the given challenge is enabled. By default // http-01, dns-01 and tls-alpn-01 are enabled, to disable any of them the // Challenge provisioner property should have at least one element. -func (p *ACME) IsChallengeEnabled(ctx context.Context, challenge ACMEChallenge) bool { +func (p *ACME) IsChallengeEnabled(_ context.Context, challenge ACMEChallenge) bool { enabledChallenges := []ACMEChallenge{ HTTP_01, DNS_01, TLS_ALPN_01, } @@ -307,7 +307,7 @@ func (p *ACME) IsChallengeEnabled(ctx context.Context, challenge ACMEChallenge) // IsAttestationFormatEnabled checks if the given attestation format is enabled. // By default apple, step and tpm are enabled, to disable any of them the // AttestationFormat provisioner property should have at least one element. -func (p *ACME) IsAttestationFormatEnabled(ctx context.Context, format ACMEAttestationFormat) bool { +func (p *ACME) IsAttestationFormatEnabled(_ context.Context, format ACMEAttestationFormat) bool { enabledFormats := []ACMEAttestationFormat{ APPLE, STEP, TPM, } diff --git a/authority/provisioner/aws.go b/authority/provisioner/aws.go index 0560877c..be641973 100644 --- a/authority/provisioner/aws.go +++ b/authority/provisioner/aws.go @@ -24,6 +24,9 @@ import ( "go.step.sm/linkedca" "github.com/smallstep/certificates/errs" + "github.com/smallstep/certificates/webhook" + + _ "embed" ) // awsIssuer is the string used as issuer in the generated tokens. @@ -49,112 +52,10 @@ const awsMetadataTokenHeader = "X-aws-ec2-metadata-token" //nolint:gosec // no c const awsMetadataTokenTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" //nolint:gosec // no credentials here // awsCertificate is the certificate used to validate the instance identity -// signature. -// -// The first certificate is used in: -// -// ap-northeast-2, ap-south-1, ap-southeast-1, ap-southeast-2 -// eu-central-1, eu-north-1, eu-west-1, eu-west-2, eu-west-3 -// us-east-1, us-east-2, us-west-1, us-west-2 -// ca-central-1, sa-east-1 -// -// The second certificate is used in: -// -// eu-south-1 -// -// The third certificate is used in: -// -// ap-east-1 -// -// The fourth certificate is used in: -// -// af-south-1 -// -// The fifth certificate is used in: +// signature. It is embedded in the binary at compile time. // -// me-south-1 -const awsCertificate = `-----BEGIN CERTIFICATE----- -MIIDIjCCAougAwIBAgIJAKnL4UEDMN/FMA0GCSqGSIb3DQEBBQUAMGoxCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRgw -FgYDVQQKEw9BbWF6b24uY29tIEluYy4xGjAYBgNVBAMTEWVjMi5hbWF6b25hd3Mu -Y29tMB4XDTE0MDYwNTE0MjgwMloXDTI0MDYwNTE0MjgwMlowajELMAkGA1UEBhMC -VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxGDAWBgNV -BAoTD0FtYXpvbi5jb20gSW5jLjEaMBgGA1UEAxMRZWMyLmFtYXpvbmF3cy5jb20w -gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIe9GN//SRK2knbjySG0ho3yqQM3 -e2TDhWO8D2e8+XZqck754gFSo99AbT2RmXClambI7xsYHZFapbELC4H91ycihvrD -jbST1ZjkLQgga0NE1q43eS68ZeTDccScXQSNivSlzJZS8HJZjgqzBlXjZftjtdJL -XeE4hwvo0sD4f3j9AgMBAAGjgc8wgcwwHQYDVR0OBBYEFCXWzAgVyrbwnFncFFIs -77VBdlE4MIGcBgNVHSMEgZQwgZGAFCXWzAgVyrbwnFncFFIs77VBdlE4oW6kbDBq -MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2Vh -dHRsZTEYMBYGA1UEChMPQW1hem9uLmNvbSBJbmMuMRowGAYDVQQDExFlYzIuYW1h -em9uYXdzLmNvbYIJAKnL4UEDMN/FMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF -BQADgYEAFYcz1OgEhQBXIwIdsgCOS8vEtiJYF+j9uO6jz7VOmJqO+pRlAbRlvY8T -C1haGgSI/A1uZUKs/Zfnph0oEI0/hu1IIJ/SKBDtN5lvmZ/IzbOPIJWirlsllQIQ -7zvWbGd9c9+Rm3p04oTvhup99la7kZqevJK0QRdD/6NpCKsqP/0= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICNjCCAZ+gAwIBAgIJAOZ3GEIaDcugMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV -BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 -dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0xOTEwMjQx -NTE5MDlaGA8yMTk5MDMyOTE1MTkwOVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgT -EFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0Ft -YXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQCjiPgW3vsXRj4JoA16WQDyoPc/eh3QBARaApJEc4nPIGoUolpAXcjFhWplo2O+ -ivgfCsc4AU9OpYdAPha3spLey/bhHPRi1JZHRNqScKP0hzsCNmKhfnZTIEQCFvsp -DRp4zr91/WS06/flJFBYJ6JHhp0KwM81XQG59lV6kkoW7QIDAQABMA0GCSqGSIb3 -DQEBCwUAA4GBAGLLrY3P+HH6C57dYgtJkuGZGT2+rMkk2n81/abzTJvsqRqGRrWv -XRKRXlKdM/dfiuYGokDGxiC0Mg6TYy6wvsR2qRhtXW1OtZkiHWcQCnOttz+8vpew -wx8JGMvowtuKB1iMsbwyRqZkFYLcvH+Opfb/Aayi20/ChQLdI6M2R5VU ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICSzCCAbQCCQDtQvkVxRvK9TANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJV -UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2VhdHRsZTEYMBYGA1UE -ChMPQW1hem9uLmNvbSBJbmMuMRowGAYDVQQDExFlYzIuYW1hem9uYXdzLmNvbTAe -Fw0xOTAyMDMwMzAwMDZaFw0yOTAyMDIwMzAwMDZaMGoxCzAJBgNVBAYTAlVTMRMw -EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRgwFgYDVQQKEw9B -bWF6b24uY29tIEluYy4xGjAYBgNVBAMTEWVjMi5hbWF6b25hd3MuY29tMIGfMA0G -CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1kkHXYTfc7gY5Q55JJhjTieHAgacaQkiR -Pity9QPDE3b+NXDh4UdP1xdIw73JcIIG3sG9RhWiXVCHh6KkuCTqJfPUknIKk8vs -M3RXflUpBe8Pf+P92pxqPMCz1Fr2NehS3JhhpkCZVGxxwLC5gaG0Lr4rFORubjYY -Rh84dK98VwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAA6xV9f0HMqXjPHuGILDyaNN -dKcvplNFwDTydVg32MNubAGnecoEBtUPtxBsLoVYXCOb+b5/ZMDubPF9tU/vSXuo -TpYM5Bq57gJzDRaBOntQbX9bgHiUxw6XZWaTS/6xjRJDT5p3S1E0mPI3lP/eJv4o -Ezk5zb3eIf10/sqt4756 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICNjCCAZ+gAwIBAgIJAKumfZiRrNvHMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV -BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 -dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0xOTExMjcw -NzE0MDVaGA8yMTk5MDUwMjA3MTQwNVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgT -EFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0Ft -YXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDFd571nUzVtke3rPyRkYfvs3jh0C0EMzzG72boyUNjnfw1+m0TeFraTLKb9T6F -7TuB/ZEN+vmlYqr2+5Va8U8qLbPF0bRH+FdaKjhgWZdYXxGzQzU3ioy5W5ZM1VyB -7iUsxEAlxsybC3ziPYaHI42UiTkQNahmoroNeqVyHNnBpQIDAQABMA0GCSqGSIb3 -DQEBCwUAA4GBAAJLylWyElEgOpW4B1XPyRVD4pAds8Guw2+krgqkY0HxLCdjosuH -RytGDGN+q75aAoXzW5a7SGpxLxk6Hfv0xp3RjDHsoeP0i1d8MD3hAC5ezxS4oukK -s5gbPOnokhKTMPXbTdRn5ZifCbWlx+bYN/mTYKvxho7b5SVg2o1La9aK ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDPDCCAqWgAwIBAgIJAMl6uIV/zqJFMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNV -BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMSAw -HgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzEaMBgGA1UEAwwRZWMyLmFt -YXpvbmF3cy5jb20wIBcNMTkwNDI2MTQzMjQ3WhgPMjE5ODA5MjkxNDMyNDdaMHIx -CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0 -dGxlMSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzEaMBgGA1UEAwwR -ZWMyLmFtYXpvbmF3cy5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALVN -CDTZEnIeoX1SEYqq6k1BV0ZlpY5y3KnoOreCAE589TwS4MX5+8Fzd6AmACmugeBP -Qk7Hm6b2+g/d4tWycyxLaQlcq81DB1GmXehRkZRgGeRge1ePWd1TUA0I8P/QBT7S -gUePm/kANSFU+P7s7u1NNl+vynyi0wUUrw7/wIZTAgMBAAGjgdcwgdQwHQYDVR0O -BBYEFILtMd+T4YgH1cgc+hVsVOV+480FMIGkBgNVHSMEgZwwgZmAFILtMd+T4YgH -1cgc+hVsVOV+480FoXakdDByMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGlu -Z3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEgMB4GA1UECgwXQW1hem9uIFdlYiBTZXJ2 -aWNlcyBMTEMxGjAYBgNVBAMMEWVjMi5hbWF6b25hd3MuY29tggkAyXq4hX/OokUw -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQBhkNTBIFgWFd+ZhC/LhRUY -4OjEiykmbEp6hlzQ79T0Tfbn5A4NYDI2icBP0+hmf6qSnIhwJF6typyd1yPK5Fqt -NTpxxcXmUKquX+pHmIkK1LKDO8rNE84jqxrxRsfDi6by82fjVYf2pgjJW8R1FAw+ -mL5WQRFexbfB5aXhcMo0AA== ------END CERTIFICATE-----` +//go:embed aws_certificates.pem +var awsCertificate string // awsSignatureAlgorithm is the signature algorithm used to verify the identity // document signature. @@ -435,7 +336,7 @@ func (p *AWS) Init(config Config) (err error) { // AuthorizeSign validates the given token and returns the sign options that // will be used on certificate creation. -func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *AWS) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { payload, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "aws.AuthorizeSign") @@ -478,14 +379,18 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er p, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID), + newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID).WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators defaultPublicKeyValidator{}, commonNameValidator(payload.Claims.Subject), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newX509NamePolicyValidator(p.ctl.getPolicy().getX509()), - p.ctl.newWebhookController(data, linkedca.Webhook_X509), + p.ctl.newWebhookController( + data, + linkedca.Webhook_X509, + webhook.WithAuthorizationPrincipal(doc.InstanceID), + ), ), nil } @@ -708,7 +613,7 @@ func (p *AWS) authorizeToken(token string) (*awsPayload, error) { } // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. -func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *AWS) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("aws.AuthorizeSSHSign; ssh ca is disabled for aws provisioner '%s'", p.GetName()) } @@ -768,6 +673,10 @@ func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, // Ensure that all principal names are allowed newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil), // Call webhooks - p.ctl.newWebhookController(data, linkedca.Webhook_SSH), + p.ctl.newWebhookController( + data, + linkedca.Webhook_SSH, + webhook.WithAuthorizationPrincipal(doc.InstanceID), + ), ), nil } diff --git a/authority/provisioner/aws_certificates.pem b/authority/provisioner/aws_certificates.pem new file mode 100644 index 00000000..d9b5f639 --- /dev/null +++ b/authority/provisioner/aws_certificates.pem @@ -0,0 +1,247 @@ +# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/verify-signature.html + +# default certificate for "other regions" +-----BEGIN CERTIFICATE----- +MIIDIjCCAougAwIBAgIJAKnL4UEDMN/FMA0GCSqGSIb3DQEBBQUAMGoxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRgw +FgYDVQQKEw9BbWF6b24uY29tIEluYy4xGjAYBgNVBAMTEWVjMi5hbWF6b25hd3Mu +Y29tMB4XDTE0MDYwNTE0MjgwMloXDTI0MDYwNTE0MjgwMlowajELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxGDAWBgNV +BAoTD0FtYXpvbi5jb20gSW5jLjEaMBgGA1UEAxMRZWMyLmFtYXpvbmF3cy5jb20w +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIe9GN//SRK2knbjySG0ho3yqQM3 +e2TDhWO8D2e8+XZqck754gFSo99AbT2RmXClambI7xsYHZFapbELC4H91ycihvrD +jbST1ZjkLQgga0NE1q43eS68ZeTDccScXQSNivSlzJZS8HJZjgqzBlXjZftjtdJL +XeE4hwvo0sD4f3j9AgMBAAGjgc8wgcwwHQYDVR0OBBYEFCXWzAgVyrbwnFncFFIs +77VBdlE4MIGcBgNVHSMEgZQwgZGAFCXWzAgVyrbwnFncFFIs77VBdlE4oW6kbDBq +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2Vh +dHRsZTEYMBYGA1UEChMPQW1hem9uLmNvbSBJbmMuMRowGAYDVQQDExFlYzIuYW1h +em9uYXdzLmNvbYIJAKnL4UEDMN/FMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF +BQADgYEAFYcz1OgEhQBXIwIdsgCOS8vEtiJYF+j9uO6jz7VOmJqO+pRlAbRlvY8T +C1haGgSI/A1uZUKs/Zfnph0oEI0/hu1IIJ/SKBDtN5lvmZ/IzbOPIJWirlsllQIQ +7zvWbGd9c9+Rm3p04oTvhup99la7kZqevJK0QRdD/6NpCKsqP/0= +-----END CERTIFICATE----- + +# certificate for eu-south-1 +-----BEGIN CERTIFICATE----- +MIICNjCCAZ+gAwIBAgIJAOZ3GEIaDcugMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 +dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0xOTEwMjQx +NTE5MDlaGA8yMTk5MDMyOTE1MTkwOVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgT +EFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0Ft +YXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQCjiPgW3vsXRj4JoA16WQDyoPc/eh3QBARaApJEc4nPIGoUolpAXcjFhWplo2O+ +ivgfCsc4AU9OpYdAPha3spLey/bhHPRi1JZHRNqScKP0hzsCNmKhfnZTIEQCFvsp +DRp4zr91/WS06/flJFBYJ6JHhp0KwM81XQG59lV6kkoW7QIDAQABMA0GCSqGSIb3 +DQEBCwUAA4GBAGLLrY3P+HH6C57dYgtJkuGZGT2+rMkk2n81/abzTJvsqRqGRrWv +XRKRXlKdM/dfiuYGokDGxiC0Mg6TYy6wvsR2qRhtXW1OtZkiHWcQCnOttz+8vpew +wx8JGMvowtuKB1iMsbwyRqZkFYLcvH+Opfb/Aayi20/ChQLdI6M2R5VU +-----END CERTIFICATE----- + +# certificate for ap-east-1 +-----BEGIN CERTIFICATE----- +MIICSzCCAbQCCQDtQvkVxRvK9TANBgkqhkiG9w0BAQsFADBqMQswCQYDVQQGEwJV +UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2VhdHRsZTEYMBYGA1UE +ChMPQW1hem9uLmNvbSBJbmMuMRowGAYDVQQDExFlYzIuYW1hem9uYXdzLmNvbTAe +Fw0xOTAyMDMwMzAwMDZaFw0yOTAyMDIwMzAwMDZaMGoxCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRgwFgYDVQQKEw9B +bWF6b24uY29tIEluYy4xGjAYBgNVBAMTEWVjMi5hbWF6b25hd3MuY29tMIGfMA0G +CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1kkHXYTfc7gY5Q55JJhjTieHAgacaQkiR +Pity9QPDE3b+NXDh4UdP1xdIw73JcIIG3sG9RhWiXVCHh6KkuCTqJfPUknIKk8vs +M3RXflUpBe8Pf+P92pxqPMCz1Fr2NehS3JhhpkCZVGxxwLC5gaG0Lr4rFORubjYY +Rh84dK98VwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAA6xV9f0HMqXjPHuGILDyaNN +dKcvplNFwDTydVg32MNubAGnecoEBtUPtxBsLoVYXCOb+b5/ZMDubPF9tU/vSXuo +TpYM5Bq57gJzDRaBOntQbX9bgHiUxw6XZWaTS/6xjRJDT5p3S1E0mPI3lP/eJv4o +Ezk5zb3eIf10/sqt4756 +-----END CERTIFICATE----- + +# certificate for af-south-1 +-----BEGIN CERTIFICATE----- +MIICNjCCAZ+gAwIBAgIJAKumfZiRrNvHMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 +dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0xOTExMjcw +NzE0MDVaGA8yMTk5MDUwMjA3MTQwNVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgT +EFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0Ft +YXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDFd571nUzVtke3rPyRkYfvs3jh0C0EMzzG72boyUNjnfw1+m0TeFraTLKb9T6F +7TuB/ZEN+vmlYqr2+5Va8U8qLbPF0bRH+FdaKjhgWZdYXxGzQzU3ioy5W5ZM1VyB +7iUsxEAlxsybC3ziPYaHI42UiTkQNahmoroNeqVyHNnBpQIDAQABMA0GCSqGSIb3 +DQEBCwUAA4GBAAJLylWyElEgOpW4B1XPyRVD4pAds8Guw2+krgqkY0HxLCdjosuH +RytGDGN+q75aAoXzW5a7SGpxLxk6Hfv0xp3RjDHsoeP0i1d8MD3hAC5ezxS4oukK +s5gbPOnokhKTMPXbTdRn5ZifCbWlx+bYN/mTYKvxho7b5SVg2o1La9aK +-----END CERTIFICATE----- + +# certificate for me-south-1 +-----BEGIN CERTIFICATE----- +MIIDPDCCAqWgAwIBAgIJAMl6uIV/zqJFMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMSAw +HgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzEaMBgGA1UEAwwRZWMyLmFt +YXpvbmF3cy5jb20wIBcNMTkwNDI2MTQzMjQ3WhgPMjE5ODA5MjkxNDMyNDdaMHIx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0 +dGxlMSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzEaMBgGA1UEAwwR +ZWMyLmFtYXpvbmF3cy5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALVN +CDTZEnIeoX1SEYqq6k1BV0ZlpY5y3KnoOreCAE589TwS4MX5+8Fzd6AmACmugeBP +Qk7Hm6b2+g/d4tWycyxLaQlcq81DB1GmXehRkZRgGeRge1ePWd1TUA0I8P/QBT7S +gUePm/kANSFU+P7s7u1NNl+vynyi0wUUrw7/wIZTAgMBAAGjgdcwgdQwHQYDVR0O +BBYEFILtMd+T4YgH1cgc+hVsVOV+480FMIGkBgNVHSMEgZwwgZmAFILtMd+T4YgH +1cgc+hVsVOV+480FoXakdDByMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGlu +Z3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEgMB4GA1UECgwXQW1hem9uIFdlYiBTZXJ2 +aWNlcyBMTEMxGjAYBgNVBAMMEWVjMi5hbWF6b25hd3MuY29tggkAyXq4hX/OokUw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQBhkNTBIFgWFd+ZhC/LhRUY +4OjEiykmbEp6hlzQ79T0Tfbn5A4NYDI2icBP0+hmf6qSnIhwJF6typyd1yPK5Fqt +NTpxxcXmUKquX+pHmIkK1LKDO8rNE84jqxrxRsfDi6by82fjVYf2pgjJW8R1FAw+ +mL5WQRFexbfB5aXhcMo0AA== +-----END CERTIFICATE----- + +# certificate for cn-north-1, cn-northwest-1 +-----BEGIN CERTIFICATE----- +MIIDCzCCAnSgAwIBAgIJALSOMbOoU2svMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 +dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0yMzA3MDQw +ODM1MzlaFw0yODA3MDIwODM1MzlaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBX +YXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6 +b24gV2ViIFNlcnZpY2VzIExMQzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +uhhUNlqAZdcWWB/OSDVDGk3OA99EFzOn/mJlmciQ/Xwu2dFJWmSCqEAE6gjufCjQ +q3voxAhC2CF+elKtJW/C0Sz/LYo60PUqd6iXF4h+upB9HkOOGuWHXsHBTsvgkgGA +1CGgel4U0Cdq+23eANr8N8m28UzljjSnTlrYCHtzN4sCAwEAAaOB1DCB0TALBgNV +HQ8EBAMCB4AwHQYDVR0OBBYEFBkZu3wT27NnYgrfH+xJz4HJaNJoMIGOBgNVHSME +gYYwgYOAFBkZu3wT27NnYgrfH+xJz4HJaNJooWCkXjBcMQswCQYDVQQGEwJVUzEZ +MBcGA1UECBMQV2FzaGluZ3RvbiBTdGF0ZTEQMA4GA1UEBxMHU2VhdHRsZTEgMB4G +A1UEChMXQW1hem9uIFdlYiBTZXJ2aWNlcyBMTEOCCQC0jjGzqFNrLzASBgNVHRMB +Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4GBAECji43p+oPkYqmzll7e8Hgb +oADS0ph+YUz5P/bUCm61wFjlxaTfwKcuTR3ytj7bFLoW5Bm7Sa+TCl3lOGb2taon +2h+9NirRK6JYk87LMNvbS40HGPFumJL2NzEsGUeK+MRiWu+Oh5/lJGii3qw4YByx +SUDlRyNy1jJFstEZjOhs +-----END CERTIFICATE----- + +# certificate for eu-central-2 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjSGFGiMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MTQyMDM1 +MTJaGA8yMjAwMDQxNDIwMzUxMlowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2 +mdGdps5Rz2jzYcGNsgETTGUthJRrVqSnUWJXTlVaIbkGPLKO6Or7AfWKFp2sgRJ8 +vLsjoBVR5cESVK7cuK1wItjvJyi/opKZAUusJx2hpgU3pUHhlp9ATh/VeVD582jT +d9IY+8t5MDa6Z3fGliByEiXz0LEHdi8MBacLREu1TwIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAILlpoE3k9o7KdALAxsFJNitVS+g3RMzdbiFM+7MA63Nv5fsf+0xgcjS +NBElvPCDKFvTJl4QQhToy056llO5GvdS9RK+H8xrP2mrqngApoKTApv93vHBixgF +Sn5KrczRO0YSm3OjkqbydU7DFlmkXXR7GYE+5jbHvQHYiT1J5sMu +-----END CERTIFICATE----- + +# certificate for ap-south-2 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjwLj9CMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MjAxNjQ3 +NDVaGA8yMjAwMDQyMDE2NDc0NVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDT +wHu0ND+sFcobrjvcAYm0PNRD8f4R1jAzvoLt2+qGeOTAyO1Httj6cmsYN3AP1hN5 +iYuppFiYsl2eNPa/CD0Vg0BAfDFlV5rzjpA0j7TJabVh4kj7JvtD+xYMi6wEQA4x +6SPONY4OeZ2+8o/HS8nucpWDVdPRO6ciWUlMhjmDmwIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAAy6sgTdRkTqELHBeWj69q60xHyUmsWqHAQNXKVc9ApWGG4onzuqlMbG +ETwUZ9mTq2vxlV0KvuetCDNS5u4cJsxe/TGGbYP0yP2qfMl0cCImzRI5W0gn8gog +dervfeT7nH5ih0TWEy/QDWfkQ601L4erm4yh4YQq8vcqAPSkf04N +-----END CERTIFICATE----- + +# certificate for ap-southeast-3 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXbVDG2yMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTAxMDYwMDE1 +MzBaGA8yMjAwMDEwNjAwMTUzMFowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn +CS/Vbt0gQ1ebWcur2hSO7PnJifE4OPxQ7RgSAlc4/spJp1sDP+ZrS0LO1ZJfKhXf +1R9S3AUwLnsc7b+IuVXdY5LK9RKqu64nyXP5dx170zoL8loEyCSuRR2fs+04i2Qs +WBVP+KFNAn7P5L1EHRjkgTO8kjNKviwRV+OkP9ab5wIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAI4WUy6+DKh0JDSzQEZNyBgNlSoSuC2owtMxCwGB6nBfzzfcekWvs6eo +fLTSGovrReX7MtVgrcJBZjmPIentw5dWUs+87w/g9lNwUnUt0ZHYyh2tuBG6hVJu +UEwDJ/z3wDd6wQviLOTF3MITawt9P8siR1hXqLJNxpjRQFZrgHqi +-----END CERTIFICATE----- + +# certificate for ap-southeast-4 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjSh40SMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MTQyMjM2 +NDJaGA8yMjAwMDQxNDIyMzY0MlowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH +ezwQr2VQpQSTW5TXNefiQrP+qWTGAbGsPeMX4hBMjAJUKys2NIRcRZaLM/BCew2F +IPVjNtlaj6Gwn9ipU4Mlz3zIwAMWi1AvGMSreppt+wV6MRtfOjh0Dvj/veJe88aE +ZJMozNgkJFRS+WFWsckQeL56tf6kY6QTlNo8V/0CsQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAF7vpPghH0FRo5gu49EArRNPrIvW1egMdZHrzJNqbztLCtV/wcgkqIww +uXYj+1rhlL+/iMpQWjdVGEqIZSeXn5fLmdx50eegFCwND837r9e8XYTiQS143Sxt +9+Yi6BZ7U7YD8kK9NBWoJxFqUeHdpRCs0O7COjT3gwm7ZxvAmssh +-----END CERTIFICATE----- + +# certificate for eu-south-2 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjwLkiaMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MjAxNjQ3 +NDhaGA8yMjAwMDQyMDE2NDc0OFowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB +/VvR1+45Aey5zn3vPk6xBm5o9grSDL6D2iAuprQnfVXn8CIbSDbWFhA3fi5ippjK +kh3sl8VyCvCOUXKdOaNrYBrPRkrdHdBuL2Tc84RO+3m/rxIUZ2IK1fDlC6sWAjdd +f6sBrV2w2a78H0H8EwuwiSgttURBjwJ7KPPJCqaqrQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAKR+FzqQDzun/iMMzcFucmLMl5BxEblrFXOz7IIuOeiGkndmrqUeDCyk +ztLku45s7hxdNy4ltTuVAaE5aNBdw5J8U1mRvsKvHLy2ThH6hAWKwTqtPAJp7M21 +GDwgDDOkPSz6XVOehg+hBgiphYp84DUbWVYeP8YqLEJSqscKscWC +-----END CERTIFICATE----- + +# certificate for il-central-1 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAX0QQGVLMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTExMTExODI2 +MzVaGA8yMjAwMTExMTE4MjYzNVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr +c24u3AgFxnoPgzxR6yFXOamcPuxYXhYKWmapb+S8vOy5hpLoRe4RkOrY0cM3bN07 +GdEMlin5mU0y1t8y3ct4YewvmkgT42kTyMM+t1K4S0xsqjXxxS716uGYh7eWtkxr +Cihj8AbXN/6pa095h+7TZyl2n83keiNUzM2KoqQVMwIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBADwA6VVEIIZD2YL00F12po40xDLzIc9XvqFPS9iFaWi2ho8wLio7wA49 +VYEFZSI9CR3SGB9tL8DUib97mlxmd1AcGShMmMlhSB29vhuhrUNB/FmU7H8s62/j +D6cOR1A1cClIyZUe1yT1ZbPySCs43J+Thr8i8FSRxzDBSZZi5foW +-----END CERTIFICATE----- + +# certificate for me-central-1 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjRrnDjMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MTQxODM5 +MzNaGA8yMjAwMDQxNDE4MzkzM1owXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDc +aTgW/KyA6zyruJQrYy00a6wqLA7eeUzk3bMiTkLsTeDQfrkaZMfBAjGaaOymRo1C +3qzE4rIenmahvUplu9ZmLwL1idWXMRX2RlSvIt+d2SeoKOKQWoc2UOFZMHYxDue7 +zkyk1CIRaBukTeY13/RIrlc6X61zJ5BBtZXlHwayjQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBABTqTy3R6RXKPW45FA+cgo7YZEj/Cnz5YaoUivRRdX2A83BHuBTvJE2+ +WX00FTEj4hRVjameE1nENoO8Z7fUVloAFDlDo69fhkJeSvn51D1WRrPnoWGgEfr1 ++OfK1bAcKTtfkkkP9r4RdwSjKzO5Zu/B+Wqm3kVEz/QNcz6npmA6 +-----END CERTIFICATE----- + +# certificate for us-gov-east-1 and us-gov-west-1 +-----BEGIN CERTIFICATE----- +MIIDCzCCAnSgAwIBAgIJAIe9Hnq82O7UMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 +dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0yMTA3MTQx +NDI3NTdaFw0yNDA3MTMxNDI3NTdaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBX +YXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6 +b24gV2ViIFNlcnZpY2VzIExMQzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +qaIcGFFTx/SO1W5G91jHvyQdGP25n1Y91aXCuOOWAUTvSvNGpXrI4AXNrQF+CmIO +C4beBASnHCx082jYudWBBl9Wiza0psYc9flrczSzVLMmN8w/c78F/95NfiQdnUQP +pvgqcMeJo82cgHkLR7XoFWgMrZJqrcUK0gnsQcb6kakCAwEAAaOB1DCB0TALBgNV +HQ8EBAMCB4AwHQYDVR0OBBYEFNWV53gWJz72F5B1ZVY4O/dfFYBPMIGOBgNVHSME +gYYwgYOAFNWV53gWJz72F5B1ZVY4O/dfFYBPoWCkXjBcMQswCQYDVQQGEwJVUzEZ +MBcGA1UECBMQV2FzaGluZ3RvbiBTdGF0ZTEQMA4GA1UEBxMHU2VhdHRsZTEgMB4G +A1UEChMXQW1hem9uIFdlYiBTZXJ2aWNlcyBMTEOCCQCHvR56vNju1DASBgNVHRMB +Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4GBACrKjWj460GUPZCGm3/z0dIz +M2BPuH769wcOsqfFZcMKEysSFK91tVtUb1soFwH4/Lb/T0PqNrvtEwD1Nva5k0h2 +xZhNNRmDuhOhW1K9wCcnHGRBwY5t4lYL6hNV6hcrqYwGMjTjcAjBG2yMgznSNFle +Rwi/S3BFXISixNx9cILu +-----END CERTIFICATE----- \ No newline at end of file diff --git a/authority/provisioner/aws_test.go b/authority/provisioner/aws_test.go index 668bc13b..05f51456 100644 --- a/authority/provisioner/aws_test.go +++ b/authority/provisioner/aws_test.go @@ -873,3 +873,27 @@ func TestAWS_AuthorizeRenew(t *testing.T) { }) } } + +func TestAWS_HardcodedCertificates(t *testing.T) { + certBytes := []byte(awsCertificate) + + var certs []*x509.Certificate + for len(certBytes) > 0 { + var block *pem.Block + block, certBytes = pem.Decode(certBytes) + if block == nil { + break + } + if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { + continue + } + + cert, err := x509.ParseCertificate(block.Bytes) + assert.FatalError(t, err) + + // check that the certificate is not expired + assert.True(t, cert.NotAfter.After(time.Now())) + certs = append(certs, cert) + } + assert.Len(t, 14, certs, "expected 14 certificates in aws_certificates.pem") +} diff --git a/authority/provisioner/azure.go b/authority/provisioner/azure.go index fcfbab27..76bcebb6 100644 --- a/authority/provisioner/azure.go +++ b/authority/provisioner/azure.go @@ -20,6 +20,7 @@ import ( "go.step.sm/linkedca" "github.com/smallstep/certificates/errs" + "github.com/smallstep/certificates/webhook" ) // azureOIDCBaseURL is the base discovery url for Microsoft Azure tokens. @@ -182,6 +183,8 @@ func (p *Azure) GetEncryptedKey() (kid, key string, ok bool) { // GetIdentityToken retrieves from the metadata service the identity token and // returns it. func (p *Azure) GetIdentityToken(subject, caURL string) (string, error) { + _, _ = subject, caURL // unused input + // Initialize the config if this method is used from the cli. p.assertConfig() @@ -313,7 +316,7 @@ func (p *Azure) authorizeToken(token string) (*azurePayload, string, string, str // AuthorizeSign validates the given token and returns the sign options that // will be used on certificate creation. -func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *Azure) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { _, name, group, subscription, identityObjectID, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSign") @@ -395,13 +398,17 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption, p, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID), + newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID).WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators defaultPublicKeyValidator{}, newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newX509NamePolicyValidator(p.ctl.getPolicy().getX509()), - p.ctl.newWebhookController(data, linkedca.Webhook_X509), + p.ctl.newWebhookController( + data, + linkedca.Webhook_X509, + webhook.WithAuthorizationPrincipal(identityObjectID), + ), ), nil } @@ -414,12 +421,12 @@ func (p *Azure) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) erro } // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. -func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *Azure) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("azure.AuthorizeSSHSign; sshCA is disabled for provisioner '%s'", p.GetName()) } - _, name, _, _, _, err := p.authorizeToken(token) + _, name, _, _, identityObjectID, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign") } @@ -471,7 +478,11 @@ func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio // Ensure that all principal names are allowed newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil), // Call webhooks - p.ctl.newWebhookController(data, linkedca.Webhook_SSH), + p.ctl.newWebhookController( + data, + linkedca.Webhook_SSH, + webhook.WithAuthorizationPrincipal(identityObjectID), + ), ), nil } diff --git a/authority/provisioner/claims.go b/authority/provisioner/claims.go index b6a5a81e..dcf679b3 100644 --- a/authority/provisioner/claims.go +++ b/authority/provisioner/claims.go @@ -26,6 +26,9 @@ type Claims struct { // Renewal properties DisableRenewal *bool `json:"disableRenewal,omitempty"` AllowRenewalAfterExpiry *bool `json:"allowRenewalAfterExpiry,omitempty"` + + // Other properties + DisableSmallstepExtensions *bool `json:"disableSmallstepExtensions,omitempty"` } // Claimer is the type that controls claims. It provides an interface around the @@ -47,20 +50,22 @@ func (c *Claimer) Claims() Claims { disableRenewal := c.IsDisableRenewal() allowRenewalAfterExpiry := c.AllowRenewalAfterExpiry() enableSSHCA := c.IsSSHCAEnabled() + disableSmallstepExtensions := c.IsDisableSmallstepExtensions() return Claims{ - MinTLSDur: &Duration{c.MinTLSCertDuration()}, - MaxTLSDur: &Duration{c.MaxTLSCertDuration()}, - DefaultTLSDur: &Duration{c.DefaultTLSCertDuration()}, - MinUserSSHDur: &Duration{c.MinUserSSHCertDuration()}, - MaxUserSSHDur: &Duration{c.MaxUserSSHCertDuration()}, - DefaultUserSSHDur: &Duration{c.DefaultUserSSHCertDuration()}, - MinHostSSHDur: &Duration{c.MinHostSSHCertDuration()}, - MaxHostSSHDur: &Duration{c.MaxHostSSHCertDuration()}, - DefaultHostSSHDur: &Duration{c.DefaultHostSSHCertDuration()}, - EnableSSHCA: &enableSSHCA, - DisableRenewal: &disableRenewal, - AllowRenewalAfterExpiry: &allowRenewalAfterExpiry, + MinTLSDur: &Duration{c.MinTLSCertDuration()}, + MaxTLSDur: &Duration{c.MaxTLSCertDuration()}, + DefaultTLSDur: &Duration{c.DefaultTLSCertDuration()}, + MinUserSSHDur: &Duration{c.MinUserSSHCertDuration()}, + MaxUserSSHDur: &Duration{c.MaxUserSSHCertDuration()}, + DefaultUserSSHDur: &Duration{c.DefaultUserSSHCertDuration()}, + MinHostSSHDur: &Duration{c.MinHostSSHCertDuration()}, + MaxHostSSHDur: &Duration{c.MaxHostSSHCertDuration()}, + DefaultHostSSHDur: &Duration{c.DefaultHostSSHCertDuration()}, + EnableSSHCA: &enableSSHCA, + DisableRenewal: &disableRenewal, + AllowRenewalAfterExpiry: &allowRenewalAfterExpiry, + DisableSmallstepExtensions: &disableSmallstepExtensions, } } @@ -110,6 +115,15 @@ func (c *Claimer) IsDisableRenewal() bool { return *c.claims.DisableRenewal } +// IsDisableSmallstepExtensions returns whether Smallstep extensions, such as +// the provisioner extension, should be excluded from the certificate. +func (c *Claimer) IsDisableSmallstepExtensions() bool { + if c.claims == nil || c.claims.DisableSmallstepExtensions == nil { + return *c.global.DisableSmallstepExtensions + } + return *c.claims.DisableSmallstepExtensions +} + // AllowRenewalAfterExpiry returns if the renewal flow is authorized if the // certificate is expired. If the property is not set within the provisioner // then the global value from the authority configuration will be used. diff --git a/authority/provisioner/controller.go b/authority/provisioner/controller.go index ef96639f..09f6a6bb 100644 --- a/authority/provisioner/controller.go +++ b/authority/provisioner/controller.go @@ -4,12 +4,12 @@ import ( "context" "crypto/x509" "net/http" - "regexp" "strings" "time" "github.com/pkg/errors" "github.com/smallstep/certificates/errs" + "github.com/smallstep/certificates/webhook" "go.step.sm/linkedca" "golang.org/x/crypto/ssh" ) @@ -77,7 +77,7 @@ func (c *Controller) AuthorizeSSHRenew(ctx context.Context, cert *ssh.Certificat return DefaultAuthorizeSSHRenew(ctx, c, cert) } -func (c *Controller) newWebhookController(templateData WebhookSetter, certType linkedca.Webhook_CertType) *WebhookController { +func (c *Controller) newWebhookController(templateData WebhookSetter, certType linkedca.Webhook_CertType, opts ...webhook.RequestBodyOption) *WebhookController { client := c.webhookClient if client == nil { client = http.DefaultClient @@ -87,6 +87,7 @@ func (c *Controller) newWebhookController(templateData WebhookSetter, certType l client: client, webhooks: c.webhooks, certType: certType, + options: opts, } } @@ -111,24 +112,22 @@ type AuthorizeSSHRenewFunc func(ctx context.Context, p *Controller, cert *ssh.Ce // DefaultIdentityFunc return a default identity depending on the provisioner // type. For OIDC email is always present and the usernames might // contain empty strings. -func DefaultIdentityFunc(ctx context.Context, p Interface, email string) (*Identity, error) { +func DefaultIdentityFunc(_ context.Context, p Interface, email string) (*Identity, error) { switch k := p.(type) { case *OIDC: // OIDC principals would be: - // ~~1. Preferred usernames.~~ Note: Under discussion, currently disabled - // 2. Sanitized local. - // 3. Raw local (if different). - // 4. Email address. + // ~~1. Preferred usernames.~~ Note: Under discussion, currently disabled + // 2. Sanitized local. + // 3. Raw local (if different). + // 4. Email address. name := SanitizeSSHUserPrincipal(email) - if !sshUserRegex.MatchString(name) { - return nil, errors.Errorf("invalid principal '%s' from email '%s'", name, email) - } usernames := []string{name} if i := strings.LastIndex(email, "@"); i >= 0 { usernames = append(usernames, email[:i]) } usernames = append(usernames, email) return &Identity{ + // Remove duplicated and empty usernames. Usernames: SanitizeStringSlices(usernames), }, nil default: @@ -140,7 +139,7 @@ func DefaultIdentityFunc(ctx context.Context, p Interface, email string) (*Ident // will return an error if the provisioner has the renewal disabled, if the // certificate is not yet valid or if the certificate is expired and renew after // expiry is disabled. -func DefaultAuthorizeRenew(ctx context.Context, p *Controller, cert *x509.Certificate) error { +func DefaultAuthorizeRenew(_ context.Context, p *Controller, cert *x509.Certificate) error { if p.Claimer.IsDisableRenewal() { return errs.Unauthorized("renew is disabled for provisioner '%s'", p.GetName()) } @@ -162,7 +161,7 @@ func DefaultAuthorizeRenew(ctx context.Context, p *Controller, cert *x509.Certif // will return an error if the provisioner has the renewal disabled, if the // certificate is not yet valid or if the certificate is expired and renew after // expiry is disabled. -func DefaultAuthorizeSSHRenew(ctx context.Context, p *Controller, cert *ssh.Certificate) error { +func DefaultAuthorizeSSHRenew(_ context.Context, p *Controller, cert *ssh.Certificate) error { if p.Claimer.IsDisableRenewal() { return errs.Unauthorized("renew is disabled for provisioner '%s'", p.GetName()) } @@ -178,8 +177,6 @@ func DefaultAuthorizeSSHRenew(ctx context.Context, p *Controller, cert *ssh.Cert return nil } -var sshUserRegex = regexp.MustCompile("^[a-z][-a-z0-9_]*$") - // SanitizeStringSlices removes duplicated an empty strings. func SanitizeStringSlices(original []string) []string { output := []string{} diff --git a/authority/provisioner/controller_test.go b/authority/provisioner/controller_test.go index c628f074..cddfb635 100644 --- a/authority/provisioner/controller_test.go +++ b/authority/provisioner/controller_test.go @@ -4,15 +4,18 @@ import ( "context" "crypto/x509" "fmt" + "net/http" "reflect" "testing" "time" + "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x509util" "go.step.sm/linkedca" "golang.org/x/crypto/ssh" "github.com/smallstep/certificates/authority/policy" + "github.com/smallstep/certificates/webhook" ) var trueValue = true @@ -167,6 +170,12 @@ func TestController_GetIdentity(t *testing.T) { }}, args{ctx, "jane@doe.org"}, &Identity{ Usernames: []string{"jane"}, }, false}, + {"ok badname", fields{&OIDC{}, nil}, args{ctx, "1000@doe.org"}, &Identity{ + Usernames: []string{"1000", "1000@doe.org"}, + }, false}, + {"ok sanitized badname", fields{&OIDC{}, nil}, args{ctx, "1000+10@doe.org"}, &Identity{ + Usernames: []string{"1000_10", "1000+10", "1000+10@doe.org"}, + }, false}, {"fail provisioner", fields{&JWK{}, nil}, args{ctx, "jane@doe.org"}, nil, true}, {"fail custom", fields{&OIDC{}, func(ctx context.Context, p Interface, email string) (*Identity, error) { return nil, fmt.Errorf("an error") @@ -449,16 +458,39 @@ func TestDefaultAuthorizeSSHRenew(t *testing.T) { } func Test_newWebhookController(t *testing.T) { - c := &Controller{} - data := x509util.TemplateData{"foo": "bar"} - ctl := c.newWebhookController(data, linkedca.Webhook_X509) - if !reflect.DeepEqual(ctl.TemplateData, data) { - t.Error("Failed to set templateData") + cert, err := pemutil.ReadCertificate("testdata/certs/x5c-leaf.crt", pemutil.WithFirstBlock()) + if err != nil { + t.Fatal(err) + } + opts := []webhook.RequestBodyOption{webhook.WithX5CCertificate(cert)} + + type args struct { + templateData WebhookSetter + certType linkedca.Webhook_CertType + opts []webhook.RequestBodyOption } - if ctl.certType != linkedca.Webhook_X509 { - t.Error("Failed to set certType") + tests := []struct { + name string + args args + want *WebhookController + }{ + {"ok", args{x509util.TemplateData{"foo": "bar"}, linkedca.Webhook_X509, nil}, &WebhookController{ + TemplateData: x509util.TemplateData{"foo": "bar"}, + certType: linkedca.Webhook_X509, + client: http.DefaultClient, + }}, + {"ok with options", args{x509util.TemplateData{"foo": "bar"}, linkedca.Webhook_SSH, opts}, &WebhookController{ + TemplateData: x509util.TemplateData{"foo": "bar"}, + certType: linkedca.Webhook_SSH, + client: http.DefaultClient, + options: opts, + }}, } - if ctl.client == nil { - t.Error("Failed to set client") + for _, tt := range tests { + c := &Controller{} + got := c.newWebhookController(tt.args.templateData, tt.args.certType, tt.args.opts...) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("newWebhookController() = %v, want %v", got, tt.want) + } } } diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index e9b372b2..b6274f8f 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -21,6 +21,7 @@ import ( "go.step.sm/linkedca" "github.com/smallstep/certificates/errs" + "github.com/smallstep/certificates/webhook" ) // gcpCertsURL is the url that serves Google OAuth2 public keys. @@ -169,6 +170,8 @@ func (p *GCP) GetIdentityURL(audience string) string { // GetIdentityToken does an HTTP request to the identity url. func (p *GCP) GetIdentityToken(subject, caURL string) (string, error) { + _ = subject // unused input + audience, err := generateSignAudience(caURL, p.GetIDForToken()) if err != nil { return "", err @@ -220,7 +223,7 @@ func (p *GCP) Init(config Config) (err error) { // AuthorizeSign validates the given token and returns the sign options that // will be used on certificate creation. -func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *GCP) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { claims, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSign") @@ -267,13 +270,17 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er p, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName), + newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName).WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators defaultPublicKeyValidator{}, newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newX509NamePolicyValidator(p.ctl.getPolicy().getX509()), - p.ctl.newWebhookController(data, linkedca.Webhook_X509), + p.ctl.newWebhookController( + data, + linkedca.Webhook_X509, + webhook.WithAuthorizationPrincipal(ce.InstanceID), + ), ), nil } @@ -380,7 +387,7 @@ func (p *GCP) authorizeToken(token string) (*gcpPayload, error) { } // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. -func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *GCP) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("gcp.AuthorizeSSHSign; sshCA is disabled for gcp provisioner '%s'", p.GetName()) } @@ -440,6 +447,10 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, // Ensure that all principal names are allowed newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil), // Call webhooks - p.ctl.newWebhookController(data, linkedca.Webhook_SSH), + p.ctl.newWebhookController( + data, + linkedca.Webhook_SSH, + webhook.WithAuthorizationPrincipal(ce.InstanceID), + ), ), nil } diff --git a/authority/provisioner/jwk.go b/authority/provisioner/jwk.go index 59332996..6c5ee657 100644 --- a/authority/provisioner/jwk.go +++ b/authority/provisioner/jwk.go @@ -143,14 +143,14 @@ func (p *JWK) authorizeToken(token string, audiences []string) (*jwtPayload, err // AuthorizeRevoke returns an error if the provisioner does not have rights to // revoke the certificate with serial number in the `sub` property. -func (p *JWK) AuthorizeRevoke(ctx context.Context, token string) error { +func (p *JWK) AuthorizeRevoke(_ context.Context, token string) error { _, err := p.authorizeToken(token, p.ctl.Audiences.Revoke) // TODO(hs): authorize the SANs using x509 name policy allow/deny rules (also for other provisioners with AuthorizeRevoke) return errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeRevoke") } // AuthorizeSign validates the given token. -func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *JWK) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { claims, err := p.authorizeToken(token, p.ctl.Audiences.Sign) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign") @@ -187,7 +187,7 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er self, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID), + newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID).WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators commonNameValidator(claims.Subject), @@ -209,7 +209,7 @@ func (p *JWK) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error } // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. -func (p *JWK) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *JWK) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("jwk.AuthorizeSSHSign; sshCA is disabled for jwk provisioner '%s'", p.GetName()) } @@ -286,7 +286,7 @@ func (p *JWK) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, } // AuthorizeSSHRevoke returns nil if the token is valid, false otherwise. -func (p *JWK) AuthorizeSSHRevoke(ctx context.Context, token string) error { +func (p *JWK) AuthorizeSSHRevoke(_ context.Context, token string) error { _, err := p.authorizeToken(token, p.ctl.Audiences.SSHRevoke) // TODO(hs): authorize the principals using SSH name policy allow/deny rules (also for other provisioners with AuthorizeSSHRevoke) return errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSSHRevoke") diff --git a/authority/provisioner/k8sSA.go b/authority/provisioner/k8sSA.go index e970616d..96267d1c 100644 --- a/authority/provisioner/k8sSA.go +++ b/authority/provisioner/k8sSA.go @@ -72,7 +72,7 @@ func (p *K8sSA) GetIDForToken() string { } // GetTokenID returns an unimplemented error and does not use the input ott. -func (p *K8sSA) GetTokenID(ott string) (string, error) { +func (p *K8sSA) GetTokenID(string) (string, error) { return "", errors.New("not implemented") } @@ -148,6 +148,7 @@ func (p *K8sSA) Init(config Config) (err error) { // claims for case specific downstream parsing. // e.g. a Sign request will auth/validate different fields than a Revoke request. func (p *K8sSA) authorizeToken(token string, audiences []string) (*k8sSAPayload, error) { + _ = audiences // unused input jwt, err := jose.ParseSigned(token) if err != nil { return nil, errs.Wrap(http.StatusUnauthorized, err, @@ -207,13 +208,13 @@ func (p *K8sSA) authorizeToken(token string, audiences []string) (*k8sSAPayload, // AuthorizeRevoke returns an error if the provisioner does not have rights to // revoke the certificate with serial number in the `sub` property. -func (p *K8sSA) AuthorizeRevoke(ctx context.Context, token string) error { +func (p *K8sSA) AuthorizeRevoke(_ context.Context, token string) error { _, err := p.authorizeToken(token, p.ctl.Audiences.Revoke) return errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeRevoke") } // AuthorizeSign validates the given token. -func (p *K8sSA) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *K8sSA) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { claims, err := p.authorizeToken(token, p.ctl.Audiences.Sign) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeSign") @@ -237,7 +238,7 @@ func (p *K8sSA) AuthorizeSign(ctx context.Context, token string) ([]SignOption, p, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeK8sSA, p.Name, ""), + newProvisionerExtensionOption(TypeK8sSA, p.Name, "").WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators defaultPublicKeyValidator{}, @@ -253,7 +254,7 @@ func (p *K8sSA) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) erro } // AuthorizeSSHSign validates an request for an SSH certificate. -func (p *K8sSA) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *K8sSA) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("k8ssa.AuthorizeSSHSign; sshCA is disabled for k8sSA provisioner '%s'", p.GetName()) } diff --git a/authority/provisioner/nebula.go b/authority/provisioner/nebula.go index 02762a0a..6c24bd00 100644 --- a/authority/provisioner/nebula.go +++ b/authority/provisioner/nebula.go @@ -116,7 +116,7 @@ func (p *Nebula) GetEncryptedKey() (kid, key string, ok bool) { } // AuthorizeSign returns the list of SignOption for a Sign request. -func (p *Nebula) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *Nebula) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { crt, claims, err := p.authorizeToken(token, p.ctl.Audiences.Sign) if err != nil { return nil, err @@ -150,7 +150,7 @@ func (p *Nebula) AuthorizeSign(ctx context.Context, token string) ([]SignOption, p, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeNebula, p.Name, ""), + newProvisionerExtensionOption(TypeNebula, p.Name, "").WithControllerOptions(p.ctl), profileLimitDuration{ def: p.ctl.Claimer.DefaultTLSCertDuration(), notBefore: crt.Details.NotBefore, @@ -171,7 +171,7 @@ func (p *Nebula) AuthorizeSign(ctx context.Context, token string) ([]SignOption, // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. // Currently the Nebula provisioner only grants host SSH certificates. -func (p *Nebula) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *Nebula) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("ssh is disabled for nebula provisioner '%s'", p.Name) } @@ -275,12 +275,12 @@ func (p *Nebula) AuthorizeRenew(ctx context.Context, crt *x509.Certificate) erro } // AuthorizeRevoke returns an error if the token is not valid. -func (p *Nebula) AuthorizeRevoke(ctx context.Context, token string) error { +func (p *Nebula) AuthorizeRevoke(_ context.Context, token string) error { return p.validateToken(token, p.ctl.Audiences.Revoke) } // AuthorizeSSHRevoke returns an error if SSH is disabled or the token is invalid. -func (p *Nebula) AuthorizeSSHRevoke(ctx context.Context, token string) error { +func (p *Nebula) AuthorizeSSHRevoke(_ context.Context, token string) error { if !p.ctl.Claimer.IsSSHCAEnabled() { return errs.Unauthorized("ssh is disabled for nebula provisioner '%s'", p.Name) } @@ -291,12 +291,12 @@ func (p *Nebula) AuthorizeSSHRevoke(ctx context.Context, token string) error { } // AuthorizeSSHRenew returns an unauthorized error. -func (p *Nebula) AuthorizeSSHRenew(ctx context.Context, token string) (*ssh.Certificate, error) { +func (p *Nebula) AuthorizeSSHRenew(context.Context, string) (*ssh.Certificate, error) { return nil, errs.Unauthorized("nebula provisioner does not support SSH renew") } // AuthorizeSSHRekey returns an unauthorized error. -func (p *Nebula) AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error) { +func (p *Nebula) AuthorizeSSHRekey(context.Context, string) (*ssh.Certificate, []SignOption, error) { return nil, nil, errs.Unauthorized("nebula provisioner does not support SSH rekey") } diff --git a/authority/provisioner/noop.go b/authority/provisioner/noop.go index bba64eb8..0c523afa 100644 --- a/authority/provisioner/noop.go +++ b/authority/provisioner/noop.go @@ -18,7 +18,7 @@ func (p *noop) GetIDForToken() string { return "noop" } -func (p *noop) GetTokenID(token string) (string, error) { +func (p *noop) GetTokenID(string) (string, error) { return "", nil } @@ -33,35 +33,35 @@ func (p *noop) GetEncryptedKey() (kid, key string, ok bool) { return "", "", false } -func (p *noop) Init(config Config) error { +func (p *noop) Init(Config) error { return nil } -func (p *noop) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *noop) AuthorizeSign(context.Context, string) ([]SignOption, error) { return []SignOption{p}, nil } -func (p *noop) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error { +func (p *noop) AuthorizeRenew(context.Context, *x509.Certificate) error { return nil } -func (p *noop) AuthorizeRevoke(ctx context.Context, token string) error { +func (p *noop) AuthorizeRevoke(context.Context, string) error { return nil } -func (p *noop) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *noop) AuthorizeSSHSign(context.Context, string) ([]SignOption, error) { return []SignOption{p}, nil } -func (p *noop) AuthorizeSSHRenew(ctx context.Context, token string) (*ssh.Certificate, error) { +func (p *noop) AuthorizeSSHRenew(context.Context, string) (*ssh.Certificate, error) { //nolint:nilnil // fine for noop return nil, nil } -func (p *noop) AuthorizeSSHRevoke(ctx context.Context, token string) error { +func (p *noop) AuthorizeSSHRevoke(context.Context, string) error { return nil } -func (p *noop) AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error) { +func (p *noop) AuthorizeSSHRekey(context.Context, string) (*ssh.Certificate, []SignOption, error) { return nil, []SignOption{}, nil } diff --git a/authority/provisioner/oidc.go b/authority/provisioner/oidc.go index 01881de6..06823e2f 100644 --- a/authority/provisioner/oidc.go +++ b/authority/provisioner/oidc.go @@ -292,7 +292,7 @@ func (o *OIDC) authorizeToken(token string) (*openIDPayload, error) { // AuthorizeRevoke returns an error if the provisioner does not have rights to // revoke the certificate with serial number in the `sub` property. // Only tokens generated by an admin have the right to revoke a certificate. -func (o *OIDC) AuthorizeRevoke(ctx context.Context, token string) error { +func (o *OIDC) AuthorizeRevoke(_ context.Context, token string) error { claims, err := o.authorizeToken(token) if err != nil { return errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeRevoke") @@ -307,7 +307,7 @@ func (o *OIDC) AuthorizeRevoke(ctx context.Context, token string) error { } // AuthorizeSign validates the given token. -func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (o *OIDC) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { claims, err := o.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSign") @@ -351,7 +351,7 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e o, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID), + newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID).WithControllerOptions(o.ctl), profileDefaultDuration(o.ctl.Claimer.DefaultTLSCertDuration()), // validators defaultPublicKeyValidator{}, @@ -463,7 +463,7 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption } // AuthorizeSSHRevoke returns nil if the token is valid, false otherwise. -func (o *OIDC) AuthorizeSSHRevoke(ctx context.Context, token string) error { +func (o *OIDC) AuthorizeSSHRevoke(_ context.Context, token string) error { claims, err := o.authorizeToken(token) if err != nil { return errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSSHRevoke") diff --git a/authority/provisioner/options.go b/authority/provisioner/options.go index 702666a4..cbce43de 100644 --- a/authority/provisioner/options.go +++ b/authority/provisioner/options.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" + "go.step.sm/cli-utils/step" "go.step.sm/crypto/jose" "go.step.sm/crypto/x509util" @@ -160,7 +161,7 @@ func CustomTemplateOptions(o *Options, data x509util.TemplateData, defaultTempla // Load a template from a file if Template is not defined. if opts.Template == "" && opts.TemplateFile != "" { return []x509util.Option{ - x509util.WithTemplateFile(opts.TemplateFile, data), + x509util.WithTemplateFile(step.Abs(opts.TemplateFile), data), } } diff --git a/authority/provisioner/provisioner.go b/authority/provisioner/provisioner.go index 9d65d585..a9b17066 100644 --- a/authority/provisioner/provisioner.go +++ b/authority/provisioner/provisioner.go @@ -10,8 +10,9 @@ import ( "strings" "github.com/pkg/errors" - "github.com/smallstep/certificates/errs" "golang.org/x/crypto/ssh" + + "github.com/smallstep/certificates/errs" ) // Interface is the interface that all provisioner types must implement. @@ -297,43 +298,43 @@ type base struct{} // AuthorizeSign returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for signing x509 Certificates. -func (b *base) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (b *base) AuthorizeSign(context.Context, string) ([]SignOption, error) { return nil, errs.Unauthorized("provisioner.AuthorizeSign not implemented") } // AuthorizeRevoke returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for revoking x509 Certificates. -func (b *base) AuthorizeRevoke(ctx context.Context, token string) error { +func (b *base) AuthorizeRevoke(context.Context, string) error { return errs.Unauthorized("provisioner.AuthorizeRevoke not implemented") } // AuthorizeRenew returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for renewing x509 Certificates. -func (b *base) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error { +func (b *base) AuthorizeRenew(context.Context, *x509.Certificate) error { return errs.Unauthorized("provisioner.AuthorizeRenew not implemented") } // AuthorizeSSHSign returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for signing SSH Certificates. -func (b *base) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (b *base) AuthorizeSSHSign(context.Context, string) ([]SignOption, error) { return nil, errs.Unauthorized("provisioner.AuthorizeSSHSign not implemented") } // AuthorizeRevoke returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for revoking SSH Certificates. -func (b *base) AuthorizeSSHRevoke(ctx context.Context, token string) error { +func (b *base) AuthorizeSSHRevoke(context.Context, string) error { return errs.Unauthorized("provisioner.AuthorizeSSHRevoke not implemented") } // AuthorizeSSHRenew returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for renewing SSH Certificates. -func (b *base) AuthorizeSSHRenew(ctx context.Context, token string) (*ssh.Certificate, error) { +func (b *base) AuthorizeSSHRenew(context.Context, string) (*ssh.Certificate, error) { return nil, errs.Unauthorized("provisioner.AuthorizeSSHRenew not implemented") } // AuthorizeSSHRekey returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for rekeying SSH Certificates. -func (b *base) AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error) { +func (b *base) AuthorizeSSHRekey(context.Context, string) (*ssh.Certificate, []SignOption, error) { return nil, nil, errs.Unauthorized("provisioner.AuthorizeSSHRekey not implemented") } diff --git a/authority/provisioner/provisioner_test.go b/authority/provisioner/provisioner_test.go index 65fb8e1d..865e5291 100644 --- a/authority/provisioner/provisioner_test.go +++ b/authority/provisioner/provisioner_test.go @@ -76,13 +76,6 @@ func TestDefaultIdentityFunc(t *testing.T) { err: errors.New("provisioner type '*provisioner.X5C' not supported by identity function"), } }, - "fail/bad-ssh-regex": func(t *testing.T) test { - return test{ - p: &OIDC{}, - email: "$%^#_>@smallstep.com", - err: errors.New("invalid principal '______' from email '$%^#_>@smallstep.com'"), - } - }, "ok": func(t *testing.T) test { return test{ p: &OIDC{}, @@ -142,6 +135,13 @@ func TestDefaultIdentityFunc(t *testing.T) { identity: &Identity{Usernames: []string{"john", "john@smallstep.com"}}, } }, + "ok/badname": func(t *testing.T) test { + return test{ + p: &OIDC{}, + email: "$%^#_>@smallstep.com", + identity: &Identity{Usernames: []string{"______", "$%^#_>", "$%^#_>@smallstep.com"}}, + } + }, } for name, get := range tests { t.Run(name, func(t *testing.T) { diff --git a/authority/provisioner/scep.go b/authority/provisioner/scep.go index 0f27b206..7862a311 100644 --- a/authority/provisioner/scep.go +++ b/authority/provisioner/scep.go @@ -2,10 +2,23 @@ package provisioner import ( "context" + "crypto" + "crypto/rsa" + "crypto/subtle" + "crypto/x509" + "encoding/pem" + "fmt" + "net/http" "time" "github.com/pkg/errors" + + "go.step.sm/crypto/kms" + kmsapi "go.step.sm/crypto/kms/apiv1" + "go.step.sm/crypto/kms/uri" "go.step.sm/linkedca" + + "github.com/smallstep/certificates/webhook" ) // SCEP is the SCEP provisioner type, an entity that can authorize the @@ -23,9 +36,19 @@ type SCEP struct { // intermediate in the GetCACerts response IncludeRoot bool `json:"includeRoot,omitempty"` + // ExcludeIntermediate makes the provisioner skip the intermediate CA in the + // GetCACerts response + ExcludeIntermediate bool `json:"excludeIntermediate,omitempty"` + // MinimumPublicKeyLength is the minimum length for public keys in CSRs MinimumPublicKeyLength int `json:"minimumPublicKeyLength,omitempty"` + // TODO(hs): also support a separate signer configuration? + DecrypterCertificate []byte `json:"decrypterCertificate,omitempty"` + DecrypterKeyPEM []byte `json:"decrypterKeyPEM,omitempty"` + DecrypterKeyURI string `json:"decrypterKey,omitempty"` + DecrypterKeyPassword string `json:"decrypterKeyPassword,omitempty"` + // Numerical identifier for the ContentEncryptionAlgorithm as defined in github.com/mozilla-services/pkcs7 // at https://github.com/mozilla-services/pkcs7/blob/33d05740a3526e382af6395d3513e73d4e66d1cb/encrypt.go#L63 // Defaults to 0, being DES-CBC @@ -33,8 +56,14 @@ type SCEP struct { Options *Options `json:"options,omitempty"` Claims *Claims `json:"claims,omitempty"` ctl *Controller - secretChallengePassword string encryptionAlgorithm int + challengeValidationController *challengeValidationController + notificationController *notificationController + keyManager kmsapi.KeyManager + decrypter crypto.Decrypter + decrypterCertificate *x509.Certificate + signer crypto.Signer + signerCertificate *x509.Certificate } // GetID returns the provisioner unique identifier. @@ -67,7 +96,7 @@ func (s *SCEP) GetEncryptedKey() (string, string, bool) { } // GetTokenID returns the identifier of the token. -func (s *SCEP) GetTokenID(ott string) (string, error) { +func (s *SCEP) GetTokenID(string) (string, error) { return "", errors.New("scep provisioner does not implement GetTokenID") } @@ -82,6 +111,127 @@ func (s *SCEP) DefaultTLSCertDuration() time.Duration { return s.ctl.Claimer.DefaultTLSCertDuration() } +type challengeValidationController struct { + client *http.Client + webhooks []*Webhook +} + +// newChallengeValidationController creates a new challengeValidationController +// that performs challenge validation through webhooks. +func newChallengeValidationController(client *http.Client, webhooks []*Webhook) *challengeValidationController { + scepHooks := []*Webhook{} + for _, wh := range webhooks { + if wh.Kind != linkedca.Webhook_SCEPCHALLENGE.String() { + continue + } + if !isCertTypeOK(wh) { + continue + } + scepHooks = append(scepHooks, wh) + } + return &challengeValidationController{ + client: client, + webhooks: scepHooks, + } +} + +var ( + ErrSCEPChallengeInvalid = errors.New("webhook server did not allow request") + ErrSCEPNotificationFailed = errors.New("scep notification failed") +) + +// Validate executes zero or more configured webhooks to +// validate the SCEP challenge. If at least one of them indicates +// the challenge value is accepted, validation succeeds. In +// that case, the other webhooks will be skipped. If none of +// the webhooks indicates the value of the challenge was accepted, +// an error is returned. +func (c *challengeValidationController) Validate(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error { + for _, wh := range c.webhooks { + req, err := webhook.NewRequestBody(webhook.WithX509CertificateRequest(csr)) + if err != nil { + return fmt.Errorf("failed creating new webhook request: %w", err) + } + req.SCEPChallenge = challenge + req.SCEPTransactionID = transactionID + resp, err := wh.DoWithContext(ctx, c.client, req, nil) // TODO(hs): support templated URL? Requires some refactoring + if err != nil { + return fmt.Errorf("failed executing webhook request: %w", err) + } + if resp.Allow { + return nil // return early when response is positive + } + } + + return ErrSCEPChallengeInvalid +} + +type notificationController struct { + client *http.Client + webhooks []*Webhook +} + +// newNotificationController creates a new notificationController +// that performs SCEP notifications through webhooks. +func newNotificationController(client *http.Client, webhooks []*Webhook) *notificationController { + scepHooks := []*Webhook{} + for _, wh := range webhooks { + if wh.Kind != linkedca.Webhook_NOTIFYING.String() { + continue + } + if !isCertTypeOK(wh) { + continue + } + scepHooks = append(scepHooks, wh) + } + return ¬ificationController{ + client: client, + webhooks: scepHooks, + } +} + +func (c *notificationController) Success(ctx context.Context, csr *x509.CertificateRequest, cert *x509.Certificate, transactionID string) error { + for _, wh := range c.webhooks { + req, err := webhook.NewRequestBody(webhook.WithX509CertificateRequest(csr), webhook.WithX509Certificate(nil, cert)) // TODO(hs): pass in the x509util.Certifiate too? + if err != nil { + return fmt.Errorf("failed creating new webhook request: %w", err) + } + req.X509Certificate.Raw = cert.Raw // adding the full certificate DER bytes + req.SCEPTransactionID = transactionID + if _, err = wh.DoWithContext(ctx, c.client, req, nil); err != nil { + return fmt.Errorf("failed executing webhook request: %w: %w", ErrSCEPNotificationFailed, err) + } + } + + return nil +} + +func (c *notificationController) Failure(ctx context.Context, csr *x509.CertificateRequest, transactionID string, errorCode int, errorDescription string) error { + for _, wh := range c.webhooks { + req, err := webhook.NewRequestBody(webhook.WithX509CertificateRequest(csr)) + if err != nil { + return fmt.Errorf("failed creating new webhook request: %w", err) + } + req.SCEPTransactionID = transactionID + req.SCEPErrorCode = errorCode + req.SCEPErrorDescription = errorDescription + if _, err = wh.DoWithContext(ctx, c.client, req, nil); err != nil { + return fmt.Errorf("failed executing webhook request: %w: %w", ErrSCEPNotificationFailed, err) + } + } + + return nil +} + +// isCertTypeOK returns whether or not the webhook can be used +// with the SCEP challenge validation webhook controller. +func isCertTypeOK(wh *Webhook) bool { + if wh.CertType == linkedca.Webhook_ALL.String() || wh.CertType == "" { + return true + } + return linkedca.Webhook_X509.String() == wh.CertType +} + // Init initializes and validates the fields of a SCEP type. func (s *SCEP) Init(config Config) (err error) { switch { @@ -91,24 +241,143 @@ func (s *SCEP) Init(config Config) (err error) { return errors.New("provisioner name cannot be empty") } - // Mask the actual challenge value, so it won't be marshaled - s.secretChallengePassword = s.ChallengePassword - s.ChallengePassword = "*** redacted ***" - // Default to 2048 bits minimum public key length (for CSRs) if not set if s.MinimumPublicKeyLength == 0 { s.MinimumPublicKeyLength = 2048 } - if s.MinimumPublicKeyLength%8 != 0 { return errors.Errorf("%d bits is not exactly divisible by 8", s.MinimumPublicKeyLength) } + // Set the encryption algorithm to use s.encryptionAlgorithm = s.EncryptionAlgorithmIdentifier // TODO(hs): we might want to upgrade the default security to AES-CBC? if s.encryptionAlgorithm < 0 || s.encryptionAlgorithm > 4 { return errors.New("only encryption algorithm identifiers from 0 to 4 are valid") } + // Prepare the SCEP challenge validator + s.challengeValidationController = newChallengeValidationController( + config.WebhookClient, + s.GetOptions().GetWebhooks(), + ) + + // Prepare the SCEP notification controller + s.notificationController = newNotificationController( + config.WebhookClient, + s.GetOptions().GetWebhooks(), + ) + + // parse the decrypter key PEM contents if available + if decryptionKeyPEM := s.DecrypterKeyPEM; len(decryptionKeyPEM) > 0 { + // try reading the PEM for validation + block, rest := pem.Decode(decryptionKeyPEM) + if len(rest) > 0 { + return errors.New("failed parsing decrypter key: trailing data") + } + if block == nil { + return errors.New("failed parsing decrypter key: no PEM block found") + } + opts := kms.Options{ + Type: kmsapi.SoftKMS, + } + if s.keyManager, err = kms.New(context.Background(), opts); err != nil { + return fmt.Errorf("failed initializing kms: %w", err) + } + kmsDecrypter, ok := s.keyManager.(kmsapi.Decrypter) + if !ok { + return fmt.Errorf("%q is not a kmsapi.Decrypter", opts.Type) + } + if s.decrypter, err = kmsDecrypter.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ + DecryptionKeyPEM: decryptionKeyPEM, + Password: []byte(s.DecrypterKeyPassword), + PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, + }); err != nil { + return fmt.Errorf("failed creating decrypter: %w", err) + } + if s.signer, err = s.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ + SigningKeyPEM: decryptionKeyPEM, // TODO(hs): support distinct signer key in the future? + Password: []byte(s.DecrypterKeyPassword), + PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, + }); err != nil { + return fmt.Errorf("failed creating signer: %w", err) + } + } + + if decryptionKeyURI := s.DecrypterKeyURI; len(decryptionKeyURI) > 0 { + u, err := uri.Parse(s.DecrypterKeyURI) + if err != nil { + return fmt.Errorf("failed parsing decrypter key: %w", err) + } + var kmsType kmsapi.Type + switch { + case u.Scheme != "": + kmsType = kms.Type(u.Scheme) + default: + kmsType = kmsapi.SoftKMS + } + opts := kms.Options{ + Type: kmsType, + URI: s.DecrypterKeyURI, + } + if s.keyManager, err = kms.New(context.Background(), opts); err != nil { + return fmt.Errorf("failed initializing kms: %w", err) + } + kmsDecrypter, ok := s.keyManager.(kmsapi.Decrypter) + if !ok { + return fmt.Errorf("%q is not a kmsapi.Decrypter", opts.Type) + } + if kmsType != "softkms" { // TODO(hs): this should likely become more transparent? + decryptionKeyURI = u.Opaque + } + if s.decrypter, err = kmsDecrypter.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ + DecryptionKey: decryptionKeyURI, + Password: []byte(s.DecrypterKeyPassword), + PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, + }); err != nil { + return fmt.Errorf("failed creating decrypter: %w", err) + } + if s.signer, err = s.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ + SigningKey: decryptionKeyURI, // TODO(hs): support distinct signer key in the future? + Password: []byte(s.DecrypterKeyPassword), + PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, + }); err != nil { + return fmt.Errorf("failed creating signer: %w", err) + } + } + + // parse the decrypter certificate contents if available + if len(s.DecrypterCertificate) > 0 { + block, rest := pem.Decode(s.DecrypterCertificate) + if len(rest) > 0 { + return errors.New("failed parsing decrypter certificate: trailing data") + } + if block == nil { + return errors.New("failed parsing decrypter certificate: no PEM block found") + } + if s.decrypterCertificate, err = x509.ParseCertificate(block.Bytes); err != nil { + return fmt.Errorf("failed parsing decrypter certificate: %w", err) + } + // the decrypter certificate is also the signer certificate + s.signerCertificate = s.decrypterCertificate + } + + // TODO(hs): alternatively, check if the KMS keyManager is a CertificateManager + // and load the certificate corresponding to the decryption key? + + // Final validation for the decrypter. + if s.decrypter != nil { + decrypterPublicKey, ok := s.decrypter.Public().(*rsa.PublicKey) + if !ok { + return fmt.Errorf("only RSA keys are supported") + } + if s.decrypterCertificate == nil { + return fmt.Errorf("provisioner %q does not have a decrypter certificate set", s.Name) + } + if !decrypterPublicKey.Equal(s.decrypterCertificate.PublicKey) { + return errors.New("mismatch between decrypter certificate and decrypter public keys") + } + } + // TODO: add other, SCEP specific, options? s.ctl, err = NewController(s, s.Claims, config, s.Options) @@ -118,11 +387,11 @@ func (s *SCEP) Init(config Config) (err error) { // AuthorizeSign does not do any verification, because all verification is handled // in the SCEP protocol. This method returns a list of modifiers / constraints // on the resulting certificate. -func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (s *SCEP) AuthorizeSign(context.Context, string) ([]SignOption, error) { return []SignOption{ s, // modifiers / withOptions - newProvisionerExtensionOption(TypeSCEP, s.Name, ""), + newProvisionerExtensionOption(TypeSCEP, s.Name, "").WithControllerOptions(s.ctl), newForceCNOption(s.ForceCN), profileDefaultDuration(s.ctl.Claimer.DefaultTLSCertDuration()), // validators @@ -133,11 +402,6 @@ func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e }, nil } -// GetChallengePassword returns the challenge password -func (s *SCEP) GetChallengePassword() string { - return s.secretChallengePassword -} - // GetCapabilities returns the CA capabilities func (s *SCEP) GetCapabilities() []string { return s.Capabilities @@ -151,8 +415,88 @@ func (s *SCEP) ShouldIncludeRootInChain() bool { return s.IncludeRoot } +// ShouldIncludeIntermediateInChain indicates if the +// CA should include the intermediate CA certificate in the +// GetCACerts response. This is true by default, but can be +// overridden through configuration in case SCEP clients +// don't pick the right recipient. +func (s *SCEP) ShouldIncludeIntermediateInChain() bool { + return !s.ExcludeIntermediate +} + // GetContentEncryptionAlgorithm returns the numeric identifier // for the pkcs7 package encryption algorithm to use. func (s *SCEP) GetContentEncryptionAlgorithm() int { return s.encryptionAlgorithm } + +// ValidateChallenge validates the provided challenge. It starts by +// selecting the validation method to use, then performs validation +// according to that method. +func (s *SCEP) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error { + if s.challengeValidationController == nil { + return fmt.Errorf("provisioner %q wasn't initialized", s.Name) + } + switch s.selectValidationMethod() { + case validationMethodWebhook: + return s.challengeValidationController.Validate(ctx, csr, challenge, transactionID) + default: + if subtle.ConstantTimeCompare([]byte(s.ChallengePassword), []byte(challenge)) == 0 { + return errors.New("invalid challenge password provided") + } + return nil + } +} + +func (s *SCEP) NotifySuccess(ctx context.Context, csr *x509.CertificateRequest, cert *x509.Certificate, transactionID string) error { + if s.notificationController == nil { + return fmt.Errorf("provisioner %q wasn't initialized", s.Name) + } + return s.notificationController.Success(ctx, csr, cert, transactionID) +} + +func (s *SCEP) NotifyFailure(ctx context.Context, csr *x509.CertificateRequest, transactionID string, errorCode int, errorDescription string) error { + if s.notificationController == nil { + return fmt.Errorf("provisioner %q wasn't initialized", s.Name) + } + return s.notificationController.Failure(ctx, csr, transactionID, errorCode, errorDescription) +} + +type validationMethod string + +const ( + validationMethodNone validationMethod = "none" + validationMethodStatic validationMethod = "static" + validationMethodWebhook validationMethod = "webhook" +) + +// selectValidationMethod returns the method to validate SCEP +// challenges. If a webhook is configured with kind `SCEPCHALLENGE`, +// the webhook method will be used. If a challenge password is set, +// the static method is used. It will default to the `none` method. +func (s *SCEP) selectValidationMethod() validationMethod { + if len(s.challengeValidationController.webhooks) > 0 { + return validationMethodWebhook + } + if s.ChallengePassword != "" { + return validationMethodStatic + } + return validationMethodNone +} + +// GetDecrypter returns the provisioner specific decrypter, +// used to decrypt SCEP request messages sent by a SCEP client. +// The decrypter consists of a crypto.Decrypter (a private key) +// and a certificate for the public key corresponding to the +// private key. +func (s *SCEP) GetDecrypter() (*x509.Certificate, crypto.Decrypter) { + return s.decrypterCertificate, s.decrypter +} + +// GetSigner returns the provisioner specific signer, used to +// sign SCEP response messages for the client. The signer consists +// of a crypto.Signer and a certificate for the public key +// corresponding to the private key. +func (s *SCEP) GetSigner() (*x509.Certificate, crypto.Signer) { + return s.signerCertificate, s.signer +} diff --git a/authority/provisioner/scep_test.go b/authority/provisioner/scep_test.go new file mode 100644 index 00000000..4efb3dd8 --- /dev/null +++ b/authority/provisioner/scep_test.go @@ -0,0 +1,359 @@ +package provisioner + +import ( + "context" + "crypto/x509" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.step.sm/linkedca" + + "github.com/smallstep/certificates/webhook" +) + +func Test_challengeValidationController_Validate(t *testing.T) { + dummyCSR := &x509.CertificateRequest{ + Raw: []byte{1}, + } + type request struct { + Request *webhook.X509CertificateRequest `json:"x509CertificateRequest,omitempty"` + Challenge string `json:"scepChallenge"` + TransactionID string `json:"scepTransactionID"` + } + type response struct { + Allow bool `json:"allow"` + } + nokServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + req := &request{} + err := json.NewDecoder(r.Body).Decode(req) + require.NoError(t, err) + assert.Equal(t, "not-allowed", req.Challenge) + assert.Equal(t, "transaction-1", req.TransactionID) + b, err := json.Marshal(response{Allow: false}) + require.NoError(t, err) + w.WriteHeader(200) + w.Write(b) + })) + okServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + req := &request{} + err := json.NewDecoder(r.Body).Decode(req) + require.NoError(t, err) + assert.Equal(t, "challenge", req.Challenge) + assert.Equal(t, "transaction-1", req.TransactionID) + if assert.NotNil(t, req.Request) { + assert.Equal(t, []byte{1}, req.Request.Raw) + } + b, err := json.Marshal(response{Allow: true}) + require.NoError(t, err) + w.WriteHeader(200) + w.Write(b) + })) + type fields struct { + client *http.Client + webhooks []*Webhook + } + type args struct { + challenge string + transactionID string + } + tests := []struct { + name string + fields fields + args args + server *httptest.Server + expErr error + }{ + { + name: "fail/no-webhook", + fields: fields{http.DefaultClient, nil}, + args: args{"no-webhook", "transaction-1"}, + expErr: errors.New("webhook server did not allow request"), + }, + { + name: "fail/wrong-cert-type", + fields: fields{http.DefaultClient, []*Webhook{ + { + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + CertType: linkedca.Webhook_SSH.String(), + }, + }}, + args: args{"wrong-cert-type", "transaction-1"}, + expErr: errors.New("webhook server did not allow request"), + }, + { + name: "fail/wrong-secret-value", + fields: fields{http.DefaultClient, []*Webhook{ + { + ID: "webhook-id-1", + Name: "webhook-name-1", + Secret: "{{}}", + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + CertType: linkedca.Webhook_X509.String(), + URL: okServer.URL, + }, + }}, + args: args{ + challenge: "wrong-secret-value", + transactionID: "transaction-1", + }, + expErr: errors.New("failed executing webhook request: illegal base64 data at input byte 0"), + }, + { + name: "fail/not-allowed", + fields: fields{http.DefaultClient, []*Webhook{ + { + ID: "webhook-id-1", + Name: "webhook-name-1", + Secret: "MTIzNAo=", + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + CertType: linkedca.Webhook_X509.String(), + URL: nokServer.URL, + }, + }}, + args: args{ + challenge: "not-allowed", + transactionID: "transaction-1", + }, + server: nokServer, + expErr: errors.New("webhook server did not allow request"), + }, + { + name: "ok", + fields: fields{http.DefaultClient, []*Webhook{ + { + ID: "webhook-id-1", + Name: "webhook-name-1", + Secret: "MTIzNAo=", + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + CertType: linkedca.Webhook_X509.String(), + URL: okServer.URL, + }, + }}, + args: args{ + challenge: "challenge", + transactionID: "transaction-1", + }, + server: okServer, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := newChallengeValidationController(tt.fields.client, tt.fields.webhooks) + + if tt.server != nil { + defer tt.server.Close() + } + + ctx := context.Background() + err := c.Validate(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID) + + if tt.expErr != nil { + assert.EqualError(t, err, tt.expErr.Error()) + return + } + + assert.NoError(t, err) + }) + } +} + +func TestController_isCertTypeOK(t *testing.T) { + assert.True(t, isCertTypeOK(&Webhook{CertType: linkedca.Webhook_X509.String()})) + assert.True(t, isCertTypeOK(&Webhook{CertType: linkedca.Webhook_ALL.String()})) + assert.True(t, isCertTypeOK(&Webhook{CertType: ""})) + assert.False(t, isCertTypeOK(&Webhook{CertType: linkedca.Webhook_SSH.String()})) +} + +func Test_selectValidationMethod(t *testing.T) { + tests := []struct { + name string + p *SCEP + want validationMethod + }{ + {"webhooks", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{ + Webhooks: []*Webhook{ + { + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + }, + }, + }, + }, "webhook"}, + {"challenge", &SCEP{ + Name: "SCEP", + Type: "SCEP", + ChallengePassword: "pass", + }, "static"}, + {"challenge-with-different-webhook", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{ + Webhooks: []*Webhook{ + { + Kind: linkedca.Webhook_AUTHORIZING.String(), + }, + }, + }, + ChallengePassword: "pass", + }, "static"}, + {"none", &SCEP{ + Name: "SCEP", + Type: "SCEP", + }, "none"}, + {"none-with-different-webhook", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{ + Webhooks: []*Webhook{ + { + Kind: linkedca.Webhook_AUTHORIZING.String(), + }, + }, + }, + }, "none"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.p.Init(Config{Claims: globalProvisionerClaims}) + require.NoError(t, err) + got := tt.p.selectValidationMethod() + assert.Equal(t, tt.want, got) + }) + } +} + +func TestSCEP_ValidateChallenge(t *testing.T) { + dummyCSR := &x509.CertificateRequest{ + Raw: []byte{1}, + } + type request struct { + Request *webhook.X509CertificateRequest `json:"x509CertificateRequest,omitempty"` + Challenge string `json:"scepChallenge"` + TransactionID string `json:"scepTransactionID"` + } + type response struct { + Allow bool `json:"allow"` + } + okServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + req := &request{} + err := json.NewDecoder(r.Body).Decode(req) + require.NoError(t, err) + assert.Equal(t, "webhook-challenge", req.Challenge) + assert.Equal(t, "webhook-transaction-1", req.TransactionID) + if assert.NotNil(t, req.Request) { + assert.Equal(t, []byte{1}, req.Request.Raw) + } + b, err := json.Marshal(response{Allow: true}) + require.NoError(t, err) + w.WriteHeader(200) + w.Write(b) + })) + type args struct { + challenge string + transactionID string + } + tests := []struct { + name string + p *SCEP + server *httptest.Server + args args + expErr error + }{ + {"ok/webhooks", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{ + Webhooks: []*Webhook{ + { + ID: "webhook-id-1", + Name: "webhook-name-1", + Secret: "MTIzNAo=", + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + CertType: linkedca.Webhook_X509.String(), + URL: okServer.URL, + }, + }, + }, + }, okServer, args{"webhook-challenge", "webhook-transaction-1"}, + nil, + }, + {"fail/webhooks-secret-configuration", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{ + Webhooks: []*Webhook{ + { + ID: "webhook-id-1", + Name: "webhook-name-1", + Secret: "{{}}", + Kind: linkedca.Webhook_SCEPCHALLENGE.String(), + CertType: linkedca.Webhook_X509.String(), + URL: okServer.URL, + }, + }, + }, + }, nil, args{"webhook-challenge", "webhook-transaction-1"}, + errors.New("failed executing webhook request: illegal base64 data at input byte 0"), + }, + {"ok/static-challenge", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{}, + ChallengePassword: "secret-static-challenge", + }, nil, args{"secret-static-challenge", "static-transaction-1"}, + nil, + }, + {"fail/wrong-static-challenge", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{}, + ChallengePassword: "secret-static-challenge", + }, nil, args{"the-wrong-challenge-secret", "static-transaction-1"}, + errors.New("invalid challenge password provided"), + }, + {"ok/no-challenge", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{}, + ChallengePassword: "", + }, nil, args{"", "static-transaction-1"}, + nil, + }, + {"fail/no-challenge-but-provided", &SCEP{ + Name: "SCEP", + Type: "SCEP", + Options: &Options{}, + ChallengePassword: "", + }, nil, args{"a-challenge-value", "static-transaction-1"}, + errors.New("invalid challenge password provided"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + if tt.server != nil { + defer tt.server.Close() + } + + err := tt.p.Init(Config{Claims: globalProvisionerClaims, WebhookClient: http.DefaultClient}) + require.NoError(t, err) + ctx := context.Background() + + err = tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID) + if tt.expErr != nil { + assert.EqualError(t, err, tt.expErr.Error()) + return + } + + assert.NoError(t, err) + }) + } +} diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index c3db239a..782a3598 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -430,6 +430,7 @@ func (o *forceCNOption) Modify(cert *x509.Certificate, _ SignOptions) error { type provisionerExtensionOption struct { Extension + Disabled bool } func newProvisionerExtensionOption(typ Type, name, credentialID string, keyValuePairs ...string) *provisionerExtensionOption { @@ -443,7 +444,19 @@ func newProvisionerExtensionOption(typ Type, name, credentialID string, keyValue } } +// WithControllerOptions updates the provisionerExtensionOption with options +// from the controller. Currently only the DisableSmallstepExtensions +// provisioner claim is used. +func (o *provisionerExtensionOption) WithControllerOptions(c *Controller) *provisionerExtensionOption { + o.Disabled = c.Claimer.IsDisableSmallstepExtensions() + return o +} + func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ SignOptions) error { + if o.Disabled { + return nil + } + ext, err := o.ToExtension() if err != nil { return errs.NewError(http.StatusInternalServerError, err, "error creating certificate") diff --git a/authority/provisioner/sign_options_test.go b/authority/provisioner/sign_options_test.go index 01d2a0cd..e36d051f 100644 --- a/authority/provisioner/sign_options_test.go +++ b/authority/provisioner/sign_options_test.go @@ -604,14 +604,24 @@ func Test_newProvisionerExtension_Option(t *testing.T) { t.Fatal(err) } + // Claims with smallstep extensions disabled. + claimer, err := NewClaimer(&Claims{ + DisableSmallstepExtensions: &trueValue, + }, globalProvisionerClaims) + if err != nil { + t.Fatal(err) + } + type test struct { - cert *x509.Certificate - valid func(*x509.Certificate) + modifier *provisionerExtensionOption + cert *x509.Certificate + valid func(*x509.Certificate) } tests := map[string]func() test{ "ok/one-element": func() test { return test{ - cert: new(x509.Certificate), + modifier: newProvisionerExtensionOption(TypeJWK, "name", "credentialId", "key", "value"), + cert: new(x509.Certificate), valid: func(cert *x509.Certificate) { if assert.Len(t, 1, cert.ExtraExtensions) { ext := cert.ExtraExtensions[0] @@ -625,7 +635,8 @@ func Test_newProvisionerExtension_Option(t *testing.T) { }, "ok/replace": func() test { return test{ - cert: &x509.Certificate{ExtraExtensions: []pkix.Extension{{Id: StepOIDProvisioner, Critical: true}, {Id: []int{1, 2, 3}}}}, + modifier: newProvisionerExtensionOption(TypeJWK, "name", "credentialId", "key", "value"), + cert: &x509.Certificate{ExtraExtensions: []pkix.Extension{{Id: StepOIDProvisioner, Critical: true}, {Id: []int{1, 2, 3}}}}, valid: func(cert *x509.Certificate) { if assert.Len(t, 2, cert.ExtraExtensions) { ext := cert.ExtraExtensions[0] @@ -636,11 +647,22 @@ func Test_newProvisionerExtension_Option(t *testing.T) { }, } }, + "ok/disabled": func() test { + return test{ + modifier: newProvisionerExtensionOption(TypeJWK, "name", "credentialId", "key", "value").WithControllerOptions(&Controller{ + Claimer: claimer, + }), + cert: new(x509.Certificate), + valid: func(cert *x509.Certificate) { + assert.Len(t, 0, cert.ExtraExtensions) + }, + } + }, } for name, run := range tests { t.Run(name, func(t *testing.T) { tt := run() - assert.FatalError(t, newProvisionerExtensionOption(TypeJWK, "name", "credentialId", "key", "value").Modify(tt.cert, SignOptions{})) + assert.FatalError(t, tt.modifier.Modify(tt.cert, SignOptions{})) tt.valid(tt.cert) }) } diff --git a/authority/provisioner/sign_ssh_options.go b/authority/provisioner/sign_ssh_options.go index f027c3a6..ee74ded3 100644 --- a/authority/provisioner/sign_ssh_options.go +++ b/authority/provisioner/sign_ssh_options.go @@ -311,7 +311,7 @@ type sshCertDefaultValidator struct{} // Valid returns an error if the given certificate does not contain the // necessary fields. We skip ValidPrincipals and Extensions as with custom // templates you can set them empty. -func (v *sshCertDefaultValidator) Valid(cert *ssh.Certificate, o SignSSHOptions) error { +func (v *sshCertDefaultValidator) Valid(cert *ssh.Certificate, _ SignSSHOptions) error { switch { case len(cert.Nonce) == 0: return errs.Forbidden("ssh certificate nonce cannot be empty") @@ -346,7 +346,7 @@ type sshDefaultPublicKeyValidator struct{} // TODO: this is the only validator that checks the key type. We should execute // this before the signing. We should add a new validations interface or extend // SSHCertOptionsValidator with the key. -func (v sshDefaultPublicKeyValidator) Valid(cert *ssh.Certificate, o SignSSHOptions) error { +func (v sshDefaultPublicKeyValidator) Valid(cert *ssh.Certificate, _ SignSSHOptions) error { if cert.Key == nil { return errs.BadRequest("ssh certificate key cannot be nil") } diff --git a/authority/provisioner/ssh_options.go b/authority/provisioner/ssh_options.go index 93633a21..e870ff30 100644 --- a/authority/provisioner/ssh_options.go +++ b/authority/provisioner/ssh_options.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/pkg/errors" + "go.step.sm/cli-utils/step" "go.step.sm/crypto/sshutil" "github.com/smallstep/certificates/authority/policy" @@ -144,7 +145,7 @@ func CustomSSHTemplateOptions(o *Options, data sshutil.TemplateData, defaultTemp // Load a template from a file if Template is not defined. if opts.Template == "" && opts.TemplateFile != "" { return []sshutil.Option{ - sshutil.WithTemplateFile(opts.TemplateFile, data), + sshutil.WithTemplateFile(step.Abs(opts.TemplateFile), data), } } diff --git a/authority/provisioner/sshpop.go b/authority/provisioner/sshpop.go index c0246729..3c7528a2 100644 --- a/authority/provisioner/sshpop.go +++ b/authority/provisioner/sshpop.go @@ -187,7 +187,7 @@ func (p *SSHPOP) authorizeToken(token string, audiences []string, checkValidity // AuthorizeSSHRevoke validates the authorization token and extracts/validates // the SSH certificate from the ssh-pop header. -func (p *SSHPOP) AuthorizeSSHRevoke(ctx context.Context, token string) error { +func (p *SSHPOP) AuthorizeSSHRevoke(_ context.Context, token string) error { claims, err := p.authorizeToken(token, p.ctl.Audiences.SSHRevoke, true) if err != nil { return errs.Wrap(http.StatusInternalServerError, err, "sshpop.AuthorizeSSHRevoke") @@ -213,7 +213,7 @@ func (p *SSHPOP) AuthorizeSSHRenew(ctx context.Context, token string) (*ssh.Cert // AuthorizeSSHRekey validates the authorization token and extracts/validates // the SSH certificate from the ssh-pop header. -func (p *SSHPOP) AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error) { +func (p *SSHPOP) AuthorizeSSHRekey(_ context.Context, token string) (*ssh.Certificate, []SignOption, error) { claims, err := p.authorizeToken(token, p.ctl.Audiences.SSHRekey, true) if err != nil { return nil, nil, errs.Wrap(http.StatusInternalServerError, err, "sshpop.AuthorizeSSHRekey") diff --git a/authority/provisioner/utils_test.go b/authority/provisioner/utils_test.go index 55fdfe6f..a599a835 100644 --- a/authority/provisioner/utils_test.go +++ b/authority/provisioner/utils_test.go @@ -24,22 +24,24 @@ import ( ) var ( - defaultDisableRenewal = false - defaultAllowRenewalAfterExpiry = false - defaultEnableSSHCA = true - globalProvisionerClaims = Claims{ - MinTLSDur: &Duration{5 * time.Minute}, - MaxTLSDur: &Duration{24 * time.Hour}, - DefaultTLSDur: &Duration{24 * time.Hour}, - MinUserSSHDur: &Duration{Duration: 5 * time.Minute}, // User SSH certs - MaxUserSSHDur: &Duration{Duration: 24 * time.Hour}, - DefaultUserSSHDur: &Duration{Duration: 16 * time.Hour}, - MinHostSSHDur: &Duration{Duration: 5 * time.Minute}, // Host SSH certs - MaxHostSSHDur: &Duration{Duration: 30 * 24 * time.Hour}, - DefaultHostSSHDur: &Duration{Duration: 30 * 24 * time.Hour}, - EnableSSHCA: &defaultEnableSSHCA, - DisableRenewal: &defaultDisableRenewal, - AllowRenewalAfterExpiry: &defaultAllowRenewalAfterExpiry, + defaultDisableRenewal = false + defaultAllowRenewalAfterExpiry = false + defaultEnableSSHCA = true + defaultDisableSmallstepExtensions = false + globalProvisionerClaims = Claims{ + MinTLSDur: &Duration{5 * time.Minute}, + MaxTLSDur: &Duration{24 * time.Hour}, + DefaultTLSDur: &Duration{24 * time.Hour}, + MinUserSSHDur: &Duration{Duration: 5 * time.Minute}, // User SSH certs + MaxUserSSHDur: &Duration{Duration: 24 * time.Hour}, + DefaultUserSSHDur: &Duration{Duration: 16 * time.Hour}, + MinHostSSHDur: &Duration{Duration: 5 * time.Minute}, // Host SSH certs + MaxHostSSHDur: &Duration{Duration: 30 * 24 * time.Hour}, + DefaultHostSSHDur: &Duration{Duration: 30 * 24 * time.Hour}, + EnableSSHCA: &defaultEnableSSHCA, + DisableRenewal: &defaultDisableRenewal, + AllowRenewalAfterExpiry: &defaultAllowRenewalAfterExpiry, + DisableSmallstepExtensions: &defaultDisableSmallstepExtensions, } testAudiences = Audiences{ Sign: []string{"https://ca.smallstep.com/1.0/sign", "https://ca.smallstep.com/sign"}, diff --git a/authority/provisioner/webhook.go b/authority/provisioner/webhook.go index ea02da35..4b517bb6 100644 --- a/authority/provisioner/webhook.go +++ b/authority/provisioner/webhook.go @@ -30,6 +30,7 @@ type WebhookController struct { client *http.Client webhooks []*Webhook certType linkedca.Webhook_CertType + options []webhook.RequestBodyOption TemplateData WebhookSetter } @@ -39,6 +40,14 @@ func (wc *WebhookController) Enrich(req *webhook.RequestBody) error { if wc == nil { return nil } + + // Apply extra options in the webhook controller + for _, fn := range wc.options { + if err := fn(req); err != nil { + return err + } + } + for _, wh := range wc.webhooks { if wh.Kind != linkedca.Webhook_ENRICHING.String() { continue @@ -63,6 +72,14 @@ func (wc *WebhookController) Authorize(req *webhook.RequestBody) error { if wc == nil { return nil } + + // Apply extra options in the webhook controller + for _, fn := range wc.options { + if err := fn(req); err != nil { + return err + } + } + for _, wh := range wc.webhooks { if wh.Kind != linkedca.Webhook_AUTHORIZING.String() { continue @@ -107,6 +124,13 @@ type Webhook struct { } func (w *Webhook) Do(client *http.Client, reqBody *webhook.RequestBody, data any) (*webhook.ResponseBody, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + + return w.DoWithContext(ctx, client, reqBody, data) +} + +func (w *Webhook) DoWithContext(ctx context.Context, client *http.Client, reqBody *webhook.RequestBody, data any) (*webhook.ResponseBody, error) { tmpl, err := template.New("url").Funcs(templates.StepFuncMap()).Parse(w.URL) if err != nil { return nil, err @@ -129,8 +153,6 @@ func (w *Webhook) Do(client *http.Client, reqBody *webhook.RequestBody, data any reqBody.Token = tmpl[sshutil.TokenKey] } */ - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() reqBody.Timestamp = time.Now() @@ -151,7 +173,9 @@ retry: if err != nil { return nil, err } - sig := hmac.New(sha256.New, secret).Sum(reqBytes) + h := hmac.New(sha256.New, secret) + h.Write(reqBytes) + sig := h.Sum(nil) req.Header.Set("X-Smallstep-Signature", hex.EncodeToString(sig)) req.Header.Set("X-Smallstep-Webhook-ID", w.ID) diff --git a/authority/provisioner/webhook_test.go b/authority/provisioner/webhook_test.go index a7895638..9a2b62f0 100644 --- a/authority/provisioner/webhook_test.go +++ b/authority/provisioner/webhook_test.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/sha256" "crypto/tls" + "crypto/x509" "encoding/base64" "encoding/hex" "encoding/json" @@ -16,6 +17,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/assert" "github.com/smallstep/certificates/webhook" + "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x509util" "go.step.sm/linkedca" ) @@ -96,12 +98,18 @@ func TestWebhookController_isCertTypeOK(t *testing.T) { } func TestWebhookController_Enrich(t *testing.T) { + cert, err := pemutil.ReadCertificate("testdata/certs/x5c-leaf.crt", pemutil.WithFirstBlock()) + if err != nil { + t.Fatal(err) + } + type test struct { ctl *WebhookController req *webhook.RequestBody responses []*webhook.ResponseBody expectErr bool expectTemplateData any + assertRequest func(t *testing.T, req *webhook.RequestBody) } tests := map[string]test{ "ok/no enriching webhooks": { @@ -170,6 +178,29 @@ func TestWebhookController_Enrich(t *testing.T) { }, }, }, + "ok/with options": { + ctl: &WebhookController{ + client: http.DefaultClient, + webhooks: []*Webhook{{Name: "people", Kind: "ENRICHING"}}, + TemplateData: x509util.TemplateData{}, + options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(cert)}, + }, + req: &webhook.RequestBody{}, + responses: []*webhook.ResponseBody{{Allow: true, Data: map[string]any{"role": "bar"}}}, + expectErr: false, + expectTemplateData: x509util.TemplateData{"Webhooks": map[string]any{"people": map[string]any{"role": "bar"}}}, + assertRequest: func(t *testing.T, req *webhook.RequestBody) { + key, err := x509.MarshalPKIXPublicKey(cert.PublicKey) + assert.FatalError(t, err) + assert.Equals(t, &webhook.X5CCertificate{ + Raw: cert.Raw, + PublicKey: key, + PublicKeyAlgorithm: cert.PublicKeyAlgorithm.String(), + NotBefore: cert.NotBefore, + NotAfter: cert.NotAfter, + }, req.X5CCertificate) + }, + }, "deny": { ctl: &WebhookController{ client: http.DefaultClient, @@ -181,6 +212,20 @@ func TestWebhookController_Enrich(t *testing.T) { expectErr: true, expectTemplateData: x509util.TemplateData{}, }, + "fail/with options": { + ctl: &WebhookController{ + client: http.DefaultClient, + webhooks: []*Webhook{{Name: "people", Kind: "ENRICHING"}}, + TemplateData: x509util.TemplateData{}, + options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(&x509.Certificate{ + PublicKey: []byte("bad"), + })}, + }, + req: &webhook.RequestBody{}, + responses: []*webhook.ResponseBody{{Allow: false}}, + expectErr: true, + expectTemplateData: x509util.TemplateData{}, + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { @@ -200,16 +245,25 @@ func TestWebhookController_Enrich(t *testing.T) { t.Fatalf("Got err %v, want %v", err, test.expectErr) } assert.Equals(t, test.expectTemplateData, test.ctl.TemplateData) + if test.assertRequest != nil { + test.assertRequest(t, test.req) + } }) } } func TestWebhookController_Authorize(t *testing.T) { + cert, err := pemutil.ReadCertificate("testdata/certs/x5c-leaf.crt", pemutil.WithFirstBlock()) + if err != nil { + t.Fatal(err) + } + type test struct { - ctl *WebhookController - req *webhook.RequestBody - responses []*webhook.ResponseBody - expectErr bool + ctl *WebhookController + req *webhook.RequestBody + responses []*webhook.ResponseBody + expectErr bool + assertRequest func(t *testing.T, req *webhook.RequestBody) } tests := map[string]test{ "ok/no enriching webhooks": { @@ -240,6 +294,27 @@ func TestWebhookController_Authorize(t *testing.T) { responses: []*webhook.ResponseBody{{Allow: false}}, expectErr: false, }, + "ok/with options": { + ctl: &WebhookController{ + client: http.DefaultClient, + webhooks: []*Webhook{{Name: "people", Kind: "AUTHORIZING"}}, + options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(cert)}, + }, + req: &webhook.RequestBody{}, + responses: []*webhook.ResponseBody{{Allow: true}}, + expectErr: false, + assertRequest: func(t *testing.T, req *webhook.RequestBody) { + key, err := x509.MarshalPKIXPublicKey(cert.PublicKey) + assert.FatalError(t, err) + assert.Equals(t, &webhook.X5CCertificate{ + Raw: cert.Raw, + PublicKey: key, + PublicKeyAlgorithm: cert.PublicKeyAlgorithm.String(), + NotBefore: cert.NotBefore, + NotAfter: cert.NotAfter, + }, req.X5CCertificate) + }, + }, "deny": { ctl: &WebhookController{ client: http.DefaultClient, @@ -249,6 +324,18 @@ func TestWebhookController_Authorize(t *testing.T) { responses: []*webhook.ResponseBody{{Allow: false}}, expectErr: true, }, + "fail/with options": { + ctl: &WebhookController{ + client: http.DefaultClient, + webhooks: []*Webhook{{Name: "people", Kind: "AUTHORIZING"}}, + options: []webhook.RequestBodyOption{webhook.WithX5CCertificate(&x509.Certificate{ + PublicKey: []byte("bad"), + })}, + }, + req: &webhook.RequestBody{}, + responses: []*webhook.ResponseBody{{Allow: false}}, + expectErr: true, + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { @@ -267,6 +354,9 @@ func TestWebhookController_Authorize(t *testing.T) { if (err != nil) != test.expectErr { t.Fatalf("Got err %v, want %v", err, test.expectErr) } + if test.assertRequest != nil { + test.assertRequest(t, test.req) + } }) } } @@ -392,7 +482,9 @@ func TestWebhook_Do(t *testing.T) { secret, err := base64.StdEncoding.DecodeString(tc.webhook.Secret) assert.FatalError(t, err) - mac := hmac.New(sha256.New, secret).Sum(body) + h := hmac.New(sha256.New, secret) + h.Write(body) + mac := h.Sum(nil) assert.True(t, hmac.Equal(sig, mac)) switch { diff --git a/authority/provisioner/x5c.go b/authority/provisioner/x5c.go index e60533b7..b6e78697 100644 --- a/authority/provisioner/x5c.go +++ b/authority/provisioner/x5c.go @@ -15,6 +15,7 @@ import ( "go.step.sm/linkedca" "github.com/smallstep/certificates/errs" + "github.com/smallstep/certificates/webhook" ) // x5cPayload extends jwt.Claims with step attributes. @@ -187,13 +188,13 @@ func (p *X5C) authorizeToken(token string, audiences []string) (*x5cPayload, err // AuthorizeRevoke returns an error if the provisioner does not have rights to // revoke the certificate with serial number in the `sub` property. -func (p *X5C) AuthorizeRevoke(ctx context.Context, token string) error { +func (p *X5C) AuthorizeRevoke(_ context.Context, token string) error { _, err := p.authorizeToken(token, p.ctl.Audiences.Revoke) return errs.Wrap(http.StatusInternalServerError, err, "x5c.AuthorizeRevoke") } // AuthorizeSign validates the given token. -func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *X5C) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { claims, err := p.authorizeToken(token, p.ctl.Audiences.Sign) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "x5c.AuthorizeSign") @@ -215,7 +216,8 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // The X509 certificate will be available using the template variable // AuthorizationCrt. For example {{ .AuthorizationCrt.DNSNames }} can be // used to get all the domains. - data.SetAuthorizationCertificate(claims.chains[0][0]) + x5cLeaf := claims.chains[0][0] + data.SetAuthorizationCertificate(x5cLeaf) templateOptions, err := TemplateOptions(p.Options, data) if err != nil { @@ -235,10 +237,10 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er self, templateOptions, // modifiers / withOptions - newProvisionerExtensionOption(TypeX5C, p.Name, ""), + newProvisionerExtensionOption(TypeX5C, p.Name, "").WithControllerOptions(p.ctl), profileLimitDuration{ p.ctl.Claimer.DefaultTLSCertDuration(), - claims.chains[0][0].NotBefore, claims.chains[0][0].NotAfter, + x5cLeaf.NotBefore, x5cLeaf.NotAfter, }, // validators commonNameValidator(claims.Subject), @@ -246,7 +248,12 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er defaultPublicKeyValidator{}, newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newX509NamePolicyValidator(p.ctl.getPolicy().getX509()), - p.ctl.newWebhookController(data, linkedca.Webhook_X509), + p.ctl.newWebhookController( + data, + linkedca.Webhook_X509, + webhook.WithX5CCertificate(x5cLeaf), + webhook.WithAuthorizationPrincipal(x5cLeaf.Subject.CommonName), + ), }, nil } @@ -256,7 +263,7 @@ func (p *X5C) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error } // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. -func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { +func (p *X5C) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { if !p.ctl.Claimer.IsSSHCAEnabled() { return nil, errs.Unauthorized("x5c.AuthorizeSSHSign; sshCA is disabled for x5c provisioner '%s'", p.GetName()) } @@ -305,7 +312,8 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, // The X509 certificate will be available using the template variable // AuthorizationCrt. For example {{ .AuthorizationCrt.DNSNames }} can be // used to get all the domains. - data.SetAuthorizationCertificate(claims.chains[0][0]) + x5cLeaf := claims.chains[0][0] + data.SetAuthorizationCertificate(x5cLeaf) templateOptions, err := TemplateSSHOptions(p.Options, data) if err != nil { @@ -325,7 +333,7 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, return append(signOptions, p, // Checks the validity bounds, and set the validity if has not been set. - &sshLimitDuration{p.ctl.Claimer, claims.chains[0][0].NotAfter}, + &sshLimitDuration{p.ctl.Claimer, x5cLeaf.NotAfter}, // Validate public key. &sshDefaultPublicKeyValidator{}, // Validate the validity period. @@ -335,6 +343,11 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, // Ensure that all principal names are allowed newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), p.ctl.getPolicy().getSSHUser()), // Call webhooks - p.ctl.newWebhookController(data, linkedca.Webhook_SSH), + p.ctl.newWebhookController( + data, + linkedca.Webhook_SSH, + webhook.WithX5CCertificate(x5cLeaf), + webhook.WithAuthorizationPrincipal(x5cLeaf.Subject.CommonName), + ), ), nil } diff --git a/authority/provisioner/x5c_test.go b/authority/provisioner/x5c_test.go index 72f9f947..f9a2604b 100644 --- a/authority/provisioner/x5c_test.go +++ b/authority/provisioner/x5c_test.go @@ -12,6 +12,7 @@ import ( "go.step.sm/crypto/jose" "go.step.sm/crypto/pemutil" "go.step.sm/crypto/randutil" + "go.step.sm/linkedca" "github.com/smallstep/assert" "github.com/smallstep/certificates/api/render" @@ -497,6 +498,8 @@ func TestX5C_AuthorizeSign(t *testing.T) { assert.Equals(t, nil, v.policyEngine) case *WebhookController: assert.Len(t, 0, v.webhooks) + assert.Equals(t, linkedca.Webhook_X509, v.certType) + assert.Len(t, 2, v.options) default: assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v)) } @@ -801,6 +804,8 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) { case *sshDefaultPublicKeyValidator, *sshCertDefaultValidator, sshCertificateOptionsFunc: case *WebhookController: assert.Len(t, 0, v.webhooks) + assert.Equals(t, linkedca.Webhook_SSH, v.certType) + assert.Len(t, 2, v.options) default: assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v)) } diff --git a/authority/provisioners.go b/authority/provisioners.go index 24d25caa..c5105bb6 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -235,7 +235,7 @@ func (a *Authority) StoreProvisioner(ctx context.Context, prov *linkedca.Provisi } if err := certProv.Init(provisionerConfig); err != nil { - return admin.WrapError(admin.ErrorBadRequestType, err, "error validating configuration for provisioner %s", prov.Name) + return admin.WrapError(admin.ErrorBadRequestType, err, "error validating configuration for provisioner %q", prov.Name) } // Store to database -- this will set the ID. @@ -646,8 +646,9 @@ func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) { } pc := &provisioner.Claims{ - DisableRenewal: &c.DisableRenewal, - AllowRenewalAfterExpiry: &c.AllowRenewalAfterExpiry, + DisableRenewal: &c.DisableRenewal, + AllowRenewalAfterExpiry: &c.AllowRenewalAfterExpiry, + DisableSmallstepExtensions: &c.DisableSmallstepExtensions, } var err error @@ -686,6 +687,7 @@ func claimsToLinkedca(c *provisioner.Claims) *linkedca.Claims { disableRenewal := config.DefaultDisableRenewal allowRenewalAfterExpiry := config.DefaultAllowRenewalAfterExpiry + disableSmallstepExtensions := config.DefaultDisableSmallstepExtensions if c.DisableRenewal != nil { disableRenewal = *c.DisableRenewal @@ -693,10 +695,14 @@ func claimsToLinkedca(c *provisioner.Claims) *linkedca.Claims { if c.AllowRenewalAfterExpiry != nil { allowRenewalAfterExpiry = *c.AllowRenewalAfterExpiry } + if c.DisableSmallstepExtensions != nil { + disableSmallstepExtensions = *c.DisableSmallstepExtensions + } lc := &linkedca.Claims{ - DisableRenewal: disableRenewal, - AllowRenewalAfterExpiry: allowRenewalAfterExpiry, + DisableRenewal: disableRenewal, + AllowRenewalAfterExpiry: allowRenewalAfterExpiry, + DisableSmallstepExtensions: disableSmallstepExtensions, } if c.DefaultTLSDur != nil || c.MinTLSDur != nil || c.MaxTLSDur != nil { @@ -748,13 +754,17 @@ func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, * } if p.X509.Template != "" { - x509Template.Template = []byte(p.SSH.Template) + x509Template.Template = []byte(p.X509.Template) } else if p.X509.TemplateFile != "" { filename := step.Abs(p.X509.TemplateFile) if x509Template.Template, err = os.ReadFile(filename); err != nil { return nil, nil, nil, errors.Wrap(err, "error reading x509 template") } } + + if p.X509.TemplateData != nil { + x509Template.Data = p.X509.TemplateData + } } if p.SSH != nil && p.SSH.HasTemplate() { @@ -771,6 +781,10 @@ func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, * return nil, nil, nil, errors.Wrap(err, "error reading ssh template") } } + + if p.SSH.TemplateData != nil { + sshTemplate.Data = p.SSH.TemplateData + } } var webhooks []*linkedca.Webhook @@ -960,7 +974,7 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, }, nil case *linkedca.ProvisionerDetails_SCEP: cfg := d.SCEP - return &provisioner.SCEP{ + s := &provisioner.SCEP{ ID: p.Id, Type: p.Type.String(), Name: p.Name, @@ -968,11 +982,19 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, ChallengePassword: cfg.Challenge, Capabilities: cfg.Capabilities, IncludeRoot: cfg.IncludeRoot, + ExcludeIntermediate: cfg.ExcludeIntermediate, MinimumPublicKeyLength: int(cfg.MinimumPublicKeyLength), EncryptionAlgorithmIdentifier: int(cfg.EncryptionAlgorithmIdentifier), Claims: claims, Options: options, - }, nil + } + if decrypter := cfg.GetDecrypter(); decrypter != nil { + s.DecrypterCertificate = decrypter.Certificate + s.DecrypterKeyPEM = decrypter.Key + s.DecrypterKeyURI = decrypter.KeyUri + s.DecrypterKeyPassword = string(decrypter.KeyPassword) + } + return s, nil case *linkedca.ProvisionerDetails_Nebula: var roots []byte for i, root := range d.Nebula.GetRoots() { @@ -1223,11 +1245,18 @@ func ProvisionerToLinkedca(p provisioner.Interface) (*linkedca.Provisioner, erro Data: &linkedca.ProvisionerDetails_SCEP{ SCEP: &linkedca.SCEPProvisioner{ ForceCn: p.ForceCN, - Challenge: p.GetChallengePassword(), + Challenge: p.ChallengePassword, Capabilities: p.Capabilities, MinimumPublicKeyLength: int32(p.MinimumPublicKeyLength), IncludeRoot: p.IncludeRoot, + ExcludeIntermediate: p.ExcludeIntermediate, EncryptionAlgorithmIdentifier: int32(p.EncryptionAlgorithmIdentifier), + Decrypter: &linkedca.SCEPDecrypter{ + Certificate: p.DecrypterCertificate, + Key: p.DecrypterKeyPEM, + KeyUri: p.DecrypterKeyURI, + KeyPassword: []byte(p.DecrypterKeyPassword), + }, }, }, }, diff --git a/authority/provisioners_test.go b/authority/provisioners_test.go index 7901de6a..f6af6f54 100644 --- a/authority/provisioners_test.go +++ b/authority/provisioners_test.go @@ -9,14 +9,17 @@ import ( "testing" "time" + "go.step.sm/crypto/jose" + "go.step.sm/crypto/keyutil" + "go.step.sm/linkedca" + + "github.com/stretchr/testify/require" + "github.com/smallstep/assert" "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority/admin" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/db" - "go.step.sm/crypto/jose" - "go.step.sm/crypto/keyutil" - "go.step.sm/linkedca" ) func TestGetEncryptedKey(t *testing.T) { @@ -29,9 +32,9 @@ func TestGetEncryptedKey(t *testing.T) { tests := map[string]func(t *testing.T) *ek{ "ok": func(t *testing.T) *ek { c, err := LoadConfiguration("../ca/testdata/ca.json") - assert.FatalError(t, err) + require.NoError(t, err) a, err := New(c) - assert.FatalError(t, err) + require.NoError(t, err) return &ek{ a: a, kid: c.AuthorityConfig.Provisioners[1].(*provisioner.JWK).Key.KeyID, @@ -39,9 +42,9 @@ func TestGetEncryptedKey(t *testing.T) { }, "fail-not-found": func(t *testing.T) *ek { c, err := LoadConfiguration("../ca/testdata/ca.json") - assert.FatalError(t, err) + require.NoError(t, err) a, err := New(c) - assert.FatalError(t, err) + require.NoError(t, err) return &ek{ a: a, kid: "foo", @@ -95,9 +98,16 @@ func TestGetProvisioners(t *testing.T) { tests := map[string]func(t *testing.T) *gp{ "ok": func(t *testing.T) *gp { c, err := LoadConfiguration("../ca/testdata/ca.json") - assert.FatalError(t, err) + require.NoError(t, err) a, err := New(c) - assert.FatalError(t, err) + require.NoError(t, err) + return &gp{a: a} + }, + "ok/rsa": func(t *testing.T) *gp { + c, err := LoadConfiguration("../ca/testdata/rsaca.json") + require.NoError(t, err) + a, err := New(c) + require.NoError(t, err) return &gp{a: a} }, } @@ -111,13 +121,13 @@ func TestGetProvisioners(t *testing.T) { if assert.NotNil(t, tc.err) { var sc render.StatusCodedError if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") { - assert.Equals(t, sc.StatusCode(), tc.code) + assert.Equals(t, tc.code, sc.StatusCode()) } - assert.HasPrefix(t, err.Error(), tc.err.Error()) + assert.HasPrefix(t, tc.err.Error(), err.Error()) } } else { if assert.Nil(t, tc.err) { - assert.Equals(t, ps, tc.a.config.AuthorityConfig.Provisioners) + assert.Equals(t, tc.a.config.AuthorityConfig.Provisioners, ps) assert.Equals(t, "", next) } } @@ -127,20 +137,20 @@ func TestGetProvisioners(t *testing.T) { func TestAuthority_LoadProvisionerByCertificate(t *testing.T) { _, priv, err := keyutil.GenerateDefaultKeyPair() - assert.FatalError(t, err) + require.NoError(t, err) csr := getCSR(t, priv) sign := func(a *Authority, extraOpts ...provisioner.SignOption) *x509.Certificate { key, err := jose.ReadKey("testdata/secrets/step_cli_key_priv.jwk", jose.WithPassword([]byte("pass"))) - assert.FatalError(t, err) + require.NoError(t, err) token, err := generateToken("smallstep test", "step-cli", testAudiences.Sign[0], []string{"test.smallstep.com"}, time.Now(), key) - assert.FatalError(t, err) + require.NoError(t, err) ctx := provisioner.NewContextWithMethod(context.Background(), provisioner.SignMethod) opts, err := a.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) opts = append(opts, extraOpts...) certs, err := a.Sign(csr, provisioner.SignOptions{}, opts...) - assert.FatalError(t, err) + require.NoError(t, err) return certs[0] } getProvisioner := func(a *Authority, name string) provisioner.Interface { @@ -169,9 +179,7 @@ func TestAuthority_LoadProvisionerByCertificate(t *testing.T) { }, MGetCertificateData: func(serialNumber string) (*db.CertificateData, error) { p, err := a1.LoadProvisionerByName("dev") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return &db.CertificateData{ Provisioner: &db.ProvisionerData{ ID: p.GetID(), @@ -186,9 +194,7 @@ func TestAuthority_LoadProvisionerByCertificate(t *testing.T) { a2.adminDB = &mockAdminDB{ MGetCertificateData: (func(s string) (*db.CertificateData, error) { p, err := a2.LoadProvisionerByName("dev") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return &db.CertificateData{ Provisioner: &db.ProvisionerData{ ID: p.GetID(), diff --git a/authority/ssh.go b/authority/ssh.go index 7d990904..f9371d60 100644 --- a/authority/ssh.go +++ b/authority/ssh.go @@ -52,7 +52,7 @@ func (a *Authority) GetSSHFederation(context.Context) (*config.SSHKeys, error) { } // GetSSHConfig returns rendered templates for clients (user) or servers (host). -func (a *Authority) GetSSHConfig(ctx context.Context, typ string, data map[string]string) ([]templates.Output, error) { +func (a *Authority) GetSSHConfig(_ context.Context, typ string, data map[string]string) ([]templates.Output, error) { if a.sshCAUserCertSignKey == nil && a.sshCAHostCertSignKey == nil { return nil, errs.NotFound("getSSHConfig: ssh is not configured") } @@ -146,7 +146,7 @@ func (a *Authority) GetSSHBastion(ctx context.Context, user, hostname string) (* } // SignSSH creates a signed SSH certificate with the given public key and options. -func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { +func (a *Authority) SignSSH(_ context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { var ( certOptions []sshutil.Option mods []provisioner.SSHCertModifier @@ -663,11 +663,7 @@ func callEnrichingWebhooksSSH(webhookCtl webhookController, cr sshutil.Certifica if err != nil { return err } - if err := webhookCtl.Enrich(whEnrichReq); err != nil { - return err - } - - return nil + return webhookCtl.Enrich(whEnrichReq) } func callAuthorizingWebhooksSSH(webhookCtl webhookController, cert *sshutil.Certificate, certTpl *ssh.Certificate) error { @@ -680,9 +676,5 @@ func callAuthorizingWebhooksSSH(webhookCtl webhookController, cert *sshutil.Cert if err != nil { return err } - if err := webhookCtl.Authorize(whAuthBody); err != nil { - return err - } - - return nil + return webhookCtl.Authorize(whAuthBody) } diff --git a/authority/ssh_test.go b/authority/ssh_test.go index b24be941..9a5c0d09 100644 --- a/authority/ssh_test.go +++ b/authority/ssh_test.go @@ -55,7 +55,7 @@ func (m sshTestModifier) Modify(cert *ssh.Certificate, _ provisioner.SignSSHOpti type sshTestCertModifier string -func (m sshTestCertModifier) Modify(cert *ssh.Certificate, opts provisioner.SignSSHOptions) error { +func (m sshTestCertModifier) Modify(*ssh.Certificate, provisioner.SignSSHOptions) error { if m == "" { return nil } @@ -64,7 +64,7 @@ func (m sshTestCertModifier) Modify(cert *ssh.Certificate, opts provisioner.Sign type sshTestCertValidator string -func (v sshTestCertValidator) Valid(crt *ssh.Certificate, opts provisioner.SignSSHOptions) error { +func (v sshTestCertValidator) Valid(*ssh.Certificate, provisioner.SignSSHOptions) error { if v == "" { return nil } @@ -73,7 +73,7 @@ func (v sshTestCertValidator) Valid(crt *ssh.Certificate, opts provisioner.SignS type sshTestOptionsValidator string -func (v sshTestOptionsValidator) Valid(opts provisioner.SignSSHOptions) error { +func (v sshTestOptionsValidator) Valid(provisioner.SignSSHOptions) error { if v == "" { return nil } @@ -82,7 +82,7 @@ func (v sshTestOptionsValidator) Valid(opts provisioner.SignSSHOptions) error { type sshTestOptionsModifier string -func (m sshTestOptionsModifier) Modify(cert *ssh.Certificate, opts provisioner.SignSSHOptions) error { +func (m sshTestOptionsModifier) Modify(*ssh.Certificate, provisioner.SignSSHOptions) error { if m == "" { return nil } diff --git a/authority/tls.go b/authority/tls.go index b7531ce3..6e967920 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -303,7 +303,7 @@ func (a *Authority) isAllowedToSignX509Certificate(cert *x509.Certificate) error // AreSANsAllowed evaluates the provided sans against the // authority X.509 policy. -func (a *Authority) AreSANsAllowed(ctx context.Context, sans []string) error { +func (a *Authority) AreSANsAllowed(_ context.Context, sans []string) error { return a.policyEngine.AreSANsAllowed(sans) } @@ -969,11 +969,7 @@ func callEnrichingWebhooksX509(webhookCtl webhookController, attData *provisione if err != nil { return err } - if err := webhookCtl.Enrich(whEnrichReq); err != nil { - return err - } - - return nil + return webhookCtl.Enrich(whEnrichReq) } func callAuthorizingWebhooksX509(webhookCtl webhookController, cert *x509util.Certificate, leaf *x509.Certificate, attData *provisioner.AttestationData) error { @@ -993,9 +989,5 @@ func callAuthorizingWebhooksX509(webhookCtl webhookController, cert *x509util.Ce if err != nil { return err } - if err := webhookCtl.Authorize(whAuthBody); err != nil { - return err - } - - return nil + return webhookCtl.Authorize(whAuthBody) } diff --git a/authority/tls_test.go b/authority/tls_test.go index 5d63b3dd..efcb78f8 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -1146,18 +1146,17 @@ func TestAuthority_Renew(t *testing.T) { assert.False(t, reflect.DeepEqual(ext1, ext2)) } continue - } else { - found := false - for _, ext2 := range leaf.Extensions { - if reflect.DeepEqual(ext1, ext2) { - found = true - break - } - } - if !found { - t.Errorf("x509 extension %s not found in renewed certificate", ext1.Id.String()) + } + found := false + for _, ext2 := range leaf.Extensions { + if reflect.DeepEqual(ext1, ext2) { + found = true + break } } + if !found { + t.Errorf("x509 extension %s not found in renewed certificate", ext1.Id.String()) + } } } @@ -1363,18 +1362,17 @@ func TestAuthority_Rekey(t *testing.T) { assert.False(t, reflect.DeepEqual(ext1, ext2)) } continue - } else { - found := false - for _, ext2 := range leaf.Extensions { - if reflect.DeepEqual(ext1, ext2) { - found = true - break - } - } - if !found { - t.Errorf("x509 extension %s not found in renewed certificate", ext1.Id.String()) + } + found := false + for _, ext2 := range leaf.Extensions { + if reflect.DeepEqual(ext1, ext2) { + found = true + break } } + if !found { + t.Errorf("x509 extension %s not found in renewed certificate", ext1.Id.String()) + } } } @@ -1936,14 +1934,14 @@ func TestAuthority_CRL(t *testing.T) { tc := f() t.Run(name, func(t *testing.T) { if crlBytes, err := tc.auth.GetCertificateRevocationList(); err == nil { - crl, parseErr := x509.ParseCRL(crlBytes) + crl, parseErr := x509.ParseRevocationList(crlBytes) if parseErr != nil { t.Errorf("x509.ParseCertificateRequest() error = %v, wantErr %v", parseErr, nil) return } var cmpList []string - for _, c := range crl.TBSCertList.RevokedCertificates { + for _, c := range crl.RevokedCertificates { cmpList = append(cmpList, c.SerialNumber.String()) } diff --git a/authority/webhook_test.go b/authority/webhook_test.go index b80c8f66..0e713af7 100644 --- a/authority/webhook_test.go +++ b/authority/webhook_test.go @@ -14,7 +14,7 @@ type mockWebhookController struct { var _ webhookController = &mockWebhookController{} -func (wc *mockWebhookController) Enrich(req *webhook.RequestBody) error { +func (wc *mockWebhookController) Enrich(*webhook.RequestBody) error { for key, data := range wc.respData { wc.templateData.SetWebhook(key, data) } @@ -22,6 +22,6 @@ func (wc *mockWebhookController) Enrich(req *webhook.RequestBody) error { return wc.enrichErr } -func (wc *mockWebhookController) Authorize(req *webhook.RequestBody) error { +func (wc *mockWebhookController) Authorize(*webhook.RequestBody) error { return wc.authorizeErr } diff --git a/ca/adminClient.go b/ca/adminClient.go index 5cfaaf15..18221146 100644 --- a/ca/adminClient.go +++ b/ca/adminClient.go @@ -269,7 +269,7 @@ retry: } // GetAdmins returns all admins from the GET /admin/admins request to the CA. -func (c *AdminClient) GetAdmins(opts ...AdminOption) ([]*linkedca.Admin, error) { +func (c *AdminClient) GetAdmins(...AdminOption) ([]*linkedca.Admin, error) { var ( cursor = "" admins = []*linkedca.Admin{} @@ -474,7 +474,7 @@ retry: } // GetProvisioners returns all admins from the GET /admin/admins request to the CA. -func (c *AdminClient) GetProvisioners(opts ...AdminOption) (provisioner.List, error) { +func (c *AdminClient) GetProvisioners(...AdminOption) (provisioner.List, error) { var ( cursor = "" provs = provisioner.List{} diff --git a/ca/bootstrap_test.go b/ca/bootstrap_test.go index 974ba1f1..62c422d4 100644 --- a/ca/bootstrap_test.go +++ b/ca/bootstrap_test.go @@ -35,7 +35,7 @@ func newLocalListener() net.Listener { return l } -func setMinCertDuration(d time.Duration) func() { +func setMinCertDuration(time.Duration) func() { tmp := minCertDuration minCertDuration = 1 * time.Second return func() { @@ -606,7 +606,13 @@ func doReload(ca *CA) error { } // Use same address in new server newCA.srv.Addr = ca.srv.Addr - return ca.srv.Reload(newCA.srv) + if err := ca.srv.Reload(newCA.srv); err != nil { + return err + } + + // Wait a few ms until the http server calls listener.Accept() + time.Sleep(100 * time.Millisecond) + return nil } func TestBootstrapListener(t *testing.T) { diff --git a/ca/ca.go b/ca/ca.go index 33f81200..7baf2419 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -15,8 +15,8 @@ import ( "sync" "time" - "github.com/go-chi/chi" - "github.com/go-chi/chi/middleware" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" "github.com/pkg/errors" "github.com/smallstep/certificates/acme" acmeAPI "github.com/smallstep/certificates/acme/api" @@ -196,7 +196,11 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { api.Route(r) }) - //Add ACME api endpoints in /acme and /1.0/acme + // Mount the CRL to the insecure mux + insecureMux.Get("/crl", api.CRL) + insecureMux.Get("/1.0/crl", api.CRL) + + // Add ACME api endpoints in /acme and /1.0/acme dns := cfg.DNSNames[0] u, err := url.Parse("https://" + cfg.Address) if err != nil { @@ -246,19 +250,14 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { var scepAuthority *scep.Authority if ca.shouldServeSCEPEndpoints() { - scepPrefix := "scep" - scepAuthority, err = scep.New(auth, scep.AuthorityOptions{ - Service: auth.GetSCEPService(), - DNS: dns, - Prefix: scepPrefix, - }) - if err != nil { - return nil, errors.Wrap(err, "error creating SCEP authority") - } + // get the SCEP authority configuration. Validation is + // performed within the authority instantiation process. + scepAuthority = auth.GetSCEP() // According to the RFC (https://tools.ietf.org/html/rfc8894#section-7.10), // SCEP operations are performed using HTTP, so that's why the API is mounted // to the insecure mux. + scepPrefix := "scep" insecureMux.Route("/"+scepPrefix, func(r chi.Router) { scepAPI.Route(r) }) @@ -276,6 +275,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { // helpful routine for logging all routes //dumpRoutes(mux) + //dumpRoutes(insecureMux) // Add monitoring if configured if len(cfg.Monitoring) > 0 { @@ -307,7 +307,7 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { // only start the insecure server if the insecure address is configured // and, currently, also only when it should serve SCEP endpoints. - if ca.shouldServeSCEPEndpoints() && cfg.InsecureAddress != "" { + if ca.shouldServeInsecureServer() { // TODO: instead opt for having a single server.Server but two // http.Servers handling the HTTP and HTTPS handler? The latter // will probably introduce more complexity in terms of graceful @@ -321,6 +321,23 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { return ca, nil } +// shouldServeInsecureServer returns whether or not the insecure +// server should also be started. This is (currently) only the case +// if the insecure address has been configured AND when a SCEP +// provisioner is configured or when a CRL is configured. +func (ca *CA) shouldServeInsecureServer() bool { + switch { + case ca.config.InsecureAddress == "": + return false + case ca.shouldServeSCEPEndpoints(): + return true + case ca.config.CRL.IsEnabled(): + return true + default: + return false + } +} + // buildContext builds the server base context. func buildContext(a *authority.Authority, scepAuthority *scep.Authority, acmeDB acme.DB, acmeLinker acme.Linker) context.Context { ctx := authority.NewContext(context.Background(), a) @@ -562,10 +579,10 @@ func (ca *CA) getTLSConfig(auth *authority.Authority) (*tls.Config, *tls.Config, // shouldServeSCEPEndpoints returns if the CA should be // configured with endpoints for SCEP. This is assumed to be -// true if a SCEPService exists, which is true in case a -// SCEP provisioner was configured. +// true if a SCEPService exists, which is true in case at +// least one SCEP provisioner was configured. func (ca *CA) shouldServeSCEPEndpoints() bool { - return ca.auth.GetSCEPService() != nil + return ca.auth.GetSCEP() != nil } //nolint:unused // useful for debugging diff --git a/ca/client_test.go b/ca/client_test.go index dff7fd41..6292e3ea 100644 --- a/ca/client_test.go +++ b/ca/client_test.go @@ -126,7 +126,7 @@ func parseCertificate(data string) *x509.Certificate { return cert } -func parseCertificateRequest(data string) *x509.CertificateRequest { +func parseCertificateRequest(string) *x509.CertificateRequest { block, _ := pem.Decode([]byte(csrPEM)) if block == nil { panic("failed to parse certificate request PEM") diff --git a/ca/identity/identity_test.go b/ca/identity/identity_test.go index 9a2422b3..6e71a1fd 100644 --- a/ca/identity/identity_test.go +++ b/ca/identity/identity_test.go @@ -367,7 +367,7 @@ func (r *renewer) GetRootCAs() *x509.CertPool { return r.pool } -func (r *renewer) Renew(tr http.RoundTripper) (*api.SignResponse, error) { +func (r *renewer) Renew(http.RoundTripper) (*api.SignResponse, error) { return r.sign, r.err } diff --git a/ca/renew.go b/ca/renew.go index ea4c5764..9385e1df 100644 --- a/ca/renew.go +++ b/ca/renew.go @@ -109,7 +109,7 @@ func (r *TLSRenewer) Stop() bool { // GetCertificate returns the current server certificate. // // This method is set in the tls.Config GetCertificate property. -func (r *TLSRenewer) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { +func (r *TLSRenewer) GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) { return r.getCertificate(), nil } @@ -118,7 +118,7 @@ func (r *TLSRenewer) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Cert // request. It's intended to be use by the certificate authority server. // // This method is set in the tls.Config GetCertificate property. -func (r *TLSRenewer) GetCertificateForCA(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { +func (r *TLSRenewer) GetCertificateForCA(*tls.ClientHelloInfo) (*tls.Certificate, error) { return r.getCertificateForCA(), nil } diff --git a/ca/testdata/rsaca.json b/ca/testdata/rsaca.json new file mode 100644 index 00000000..2e3acdb1 --- /dev/null +++ b/ca/testdata/rsaca.json @@ -0,0 +1,47 @@ +{ + "root": "../ca/testdata/secrets/rsa_root_ca.crt", + "federatedRoots": [], + "crt": "../ca/testdata/secrets/rsa_intermediate_ca.crt", + "key": "../ca/testdata/secrets/rsa_intermediate_ca_key", + "password": "1234", + "address": "127.0.0.1:0", + "dnsNames": ["127.0.0.1"], + "_logger": {"format": "text"}, + "tls": { + "minVersion": 1.2, + "maxVersion": 1.3, + "renegotiation": false, + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ] + }, + "authority": { + "backdate": "0s", + "provisioners": [ + { + "name": "scep", + "type": "scep", + "challenge": "not-so-secret" + }, { + "name": "step-cli", + "type": "jwk", + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlhOdmYxQjgxSUlLMFA2NUkwcmtGTGcifQ.XaN9zcPQeWt49zchUDm34FECUTHfQTn_.tmNHPQDqR3ebsWfd.9WZr3YVdeOyJh36vvx0VlRtluhvYp4K7jJ1KGDr1qypwZ3ziBVSNbYYQ71du7fTtrnfG1wgGTVR39tWSzBU-zwQ5hdV3rpMAaEbod5zeW6SHd95H3Bvcb43YiiqJFNL5sGZzFb7FqzVmpsZ1efiv6sZaGDHtnCAL6r12UG5EZuqGfM0jGCZitUz2m9TUKXJL5DJ7MOYbFfkCEsUBPDm_TInliSVn2kMJhFa0VOe5wZk5YOuYM3lNYW64HGtbf-llN2Xk-4O9TfeSPizBx9ZqGpeu8pz13efUDT2WL9tWo6-0UE-CrG0bScm8lFTncTkHcu49_a5NaUBkYlBjEiw.thPcx3t1AUcWuEygXIY3Fg", + "key": { + "use": "sig", + "kty": "EC", + "kid": "4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc", + "crv": "P-256", + "alg": "ES256", + "x": "7ZdAAMZCFU4XwgblI5RfZouBi8lYmF6DlZusNNnsbm8", + "y": "sQr2JdzwD2fgyrymBEXWsxDxFNjjqN64qLLSbLdLZ9Y" + } + } + ], + "template": { + "country": "US", + "locality": "San Francisco", + "organization": "Smallstep" + } + } +} diff --git a/ca/testdata/secrets/rsa_intermediate_ca.crt b/ca/testdata/secrets/rsa_intermediate_ca.crt new file mode 100644 index 00000000..a575b91f --- /dev/null +++ b/ca/testdata/secrets/rsa_intermediate_ca.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFJTCCAw2gAwIBAgIRAMBEHdXQtHUla+J13aUn/0gwDQYJKoZIhvcNAQELBQAw +FjEUMBIGA1UEAxMLcnNhLXJvb3QtY2EwHhcNMjIxMjAyMTE0MzE2WhcNMzIxMTI5 +MTE0MzE2WjAeMRwwGgYDVQQDExNyc2EtaW50ZXJtZWRpYXRlLWNhMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArxVkidtUrM6KIdGZ8a2QtJWezrTxTiEM +lDeYqLd4CKp1bjQ7JOi1uc0mBG0Y4u5NwQRDk3L2aulLrENsPx4PMsPwMPXZgw67 +zTTuug1/uec8phW9IvEqu8FDQhFCMzZZMmc/0UTLmhJq5NZhIU8SQ6XYF/5s11Gm +zBbBG1CEV6KcwVul8+T/GcHr60h2/X4uRkibEdUsDy0jHFLMPOWMeKQXoA8hVWHc +QRYInRS5q+aFZ79YqMTUFT2tKdgSCiDsm6MqAPhFVB20ZrxMU6zco67+DBKAzSGy +qO0H6fxkStN4RBrCFTgUdyUPwSe5xCOVfR4JbF8pXMI9cA7iCT0Mw9ZgbTncKVdn +epwIZfqqYMP0C3EL+BZOSfEQeXIq7qlmHKwRRkc010ZaLmbKB9Kug/HcsS3CevU2 +J0Efosi2xfMcfhi11rAfKvZpyAuOVap7BONro3yYXjv6Co9sDWtyK6VkLsczp2MM +NHxhzjGXAcQdnU79UbGxO67imZm6FYLTwcg/6SVrfh+slLJ5nCyXqC/LaQ+Mc7Q+ +mdibgOzHSYg/QHVamic0uqn4BLw8QjICIZAnWWJHYjVgCieZrvK/7BGOjQ8+LT/8 +NhjI6MSuNMcXLxyOciiPw1r8fT/NUbJZblMDhibGTaOFCoMc3niY/fwxPb3p1J8I +tmOLoK8HCysCAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFO0ULj6Dt1RakbRqV4rVFUdRHK3KMB8GA1UdIwQYMBaA +FCd9WZYMPpfDLBKjySFENwIXJpuzMA0GCSqGSIb3DQEBCwUAA4ICAQCiWxrj4HqV +J9tGj59Ea2cMZUcBfGPYh4dZ0af6IlNZnqW9ZlmNNF/h0VvCpd28STZlkW7hp2Xb +RcJ0tXs3MvnU0Sqzw8ZTevJgIIbiOIwndfmi4apfSC63JXftBkThP0xpR5LI/4pH +UPYyeGA13fynH4YmO4QBsGEXlKMKSYSjwrheYKkSB73AYlc7r8OqE/NAVHc1xzov +9GT4p7w+tF6vrgzUtwqpAEVM/3USmSx4rgSdkI4DPkrYb1HEqT8ixOIH/3IG42ag +UZgICckBPqcki8UbnU4nbxWVGJd18FE2n4wC2erewlBL+1PJFTmgDEKmOlcabot8 +QEk/YOpMThCm79VGuFB7frXoFefLCl5q1K5yV1eDsmr79ZFIy2WM2alnVk2Cvk/9 +oJQQ42AWRVHGFuaIrG+hLLtwq17MnoeyQ/A2IRlpWu7DpaCVfuPA+3yQC06qo98u +A3vGpifN8eohTSEMYNGQAsUsArYPwMEp/QrP4EwK8YnaJtd2HCnG4VS3D+RenRIF +04b8EXX64ePD07uzPh7dKpWfmdJf1xj8GSndw2vk14KYDOvjrXirVkNCXFxgU9jp +uTLGU/7Panm81xQgjeNwRaXxWvvDSrQaKMZ1QL6i0U7OTso0Q4VHivGG7IDhYSkA +zNRdjmJnuap8XWGs/4xKjMJcv12UtnaMgw== +-----END CERTIFICATE----- diff --git a/ca/testdata/secrets/rsa_intermediate_ca_key b/ca/testdata/secrets/rsa_intermediate_ca_key new file mode 100644 index 00000000..673df81b --- /dev/null +++ b/ca/testdata/secrets/rsa_intermediate_ca_key @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,03e26f42f8642e55946bcad62fef0c2e + +54jydVXdnixOccnF90L9pkfsy4mrRC9xyl4BbZMaYwplZC+LE+U80GAdXOqSxBEo +sQBz+OTYaq2bmT2MDnoHty8I4vdDTVmxovc+NdtCJdC+etc2bSEKt68K57BPEqa0 +o7SE5Lk39zSDIFkyltQeYNII8sCX7H26kRsfZhmDYPoFXGCfnxrEQoASaF8S9n3l +9yERxk4untsVpvOPPde6Vn3b40ALqg0J0PaqzIbWifbWL8Uu3IeP27VHJLS4AH23 +emkWaZiT1bjWNevwWiU0REZ1CxyShaggJa4YwXPJJyRcQlvnVMZ8+DjXoQ1EdSGA +EGMfG6i5zDrRAdRDRgbJM56wZqIWup+/Kd0WyVGOteGFhzyl8Pad65NGYP9saPE/ +P0/Wi51t30KllF6i6XHATeAKPgGAMkl8E9x9KCQVqGEWi8Ceu3w5AMxC1tcwB0Xy +1X9NBipHaDh0DneTTdRRpwGCEIkZefDwy0z4rgsxrbKyY0YP1NKsFt+rNFkdNSnK +RevnejtYHSDjOyGImnLRJ0c2nxwet93hfY1g3yzagKtWUp/TXOO7EkggqUPObQhC +n9U5tkPxvHTCXSzeK3QqrbReyb3AlEay8Th8R8roxcClV83E4vcjjuvitcJ0MbSW ++/jCU1WhCanat67je749MB19msA95XYxNsAmCn17vJIVRI/QBS9HQCkf7UW1Jptm +hU06/7sytuOFboXh/xhfoQUomlx8Hl/GqV2yGZyL7SsH4sxoT9cVCO2vXCnr/r63 +Uo1nkEHQNddbBCR7yvjoeeq5PypGxZibC7YzWx87Hwcr8dEhBwzoqeIFkhnEVMyq +Y3xFIilqqRaLwG1c77wy5jReTv/OTJ2OU2VFDu3Pf7zAOcGtcQazcNv7PMkiqunK +Bp/vDLL+LiaWO/5Zl49DFPTGkRj5kNK/aNajfHyw0hvYYytiaGaH9DM3L+7kC7YG +2le8eLbUgZ7tqw3P2KueCK1F6Ef5X2It2sjxv/w5hz6lDtGfEIVXJuOamSUEewkY +9xM9njmqFhQjb71Khm3+/HUoxvmOebpuQ884xORfvzJ1rl8IHA84VTo8/XKp3EST +yMC39rGhtVuADHvNz3Y/WAWIbrJkkdZvMXyYKoOTosNVeFjJxyfKlz8ZMYmy6cM6 +mjOcsaI8xYUslYtpj/7vAjtcF4tJv94cQB/KGdUc/Z5JQ3r8zooG8ghEPt/5jiEr +4ECCK7btew0mexVv+HY3rX7UiPCHugfX6+XEIxQ8+AsM27FNFaKxjxTE2r9h95mP +jmcWO7YqyqyeEZmKoxNo5oLMKXIDKxzK6ianJYg65xMnT+cH5vcnVaQKaC2QcnMI +TiLOz/+ZdJSz2FiyE4myjnp9COKQhsDOfQA/1xzPF/4dqWMyWijGnlcozCHlU0i+ +2oG7izmDl9zn79v8VH6y0WjeEywoH5XlrF5eKBA2g7AtB8MCJTpIRVazTRbvhjaP +EXr+Zk6vPVlDS0KOIUJ4V8iYcatdoaJz1fM3XjVZ6Wwy8TaYd9EBwWlWdFDx6r3s +1aT5fDDyZNjnTx80OHyWT2IS/+/FrColWGc9s/t5raFm3KEnvVpFc+7/AKOV3keB ++3KVSg4ILLDYf7PfMrT2IPrWObuUXZ2InZPEG3T7BOtbbdO8BDbDng1xLxPGDFgQ +zKUFngsPO90PoDmNUZ9dBZ/oOI54e38hqUGB7vdTsNlX+VTK4n+qb8w7GzNhGgnR +fTP927HeuFBdq8Y2ngxt2i6vg9yo7Ojd+nG5OLj2T7uyNraKdaaBx4Nd9ZUZbNGt +4EueDSHCALKBsimLl4DfnMDnUK3G79dsoazs/nUr5y7kaUlkBGNZ/iSuoqpgeTKU +jsTmVjRj4W5opC+UUBiY/tE7qHGczLDw/mw/NP14nQ5iFdwi6EJv3viprYL+zL/A +zRTkcQ0KqBfc1ChVWhvxIg7QCsnPT6+y0yn2k6n4a9cUvQXcOQKqF5eOJWPE3ZeC +7fgIwt7ZdqHPZHyMxAnwWbmsj1Tn09SBW1b7S4t50aAPTRjDmrp5iC4vK59L7qPZ +ekoft0VduaJlKqq90Bh5ouRvTO6ytDI261bbEIGQqH1nJVt12bhNA6h3xI3Iwn/E +qlMLAN1M36LenUEp9l77AfiFU1f+d8ZP2U6bJo4FKTnRR33R6+89sezUmVEuqozt +qONJo0DE9XSAVhxpVX1QF91RjrJSiQtNyRkaOEyTsw2VvJpQNI5GAQN0TbcqgCVD +aUqPUuwntC7Wx7PkF6OR07rVxSIvhXs1NlG09nPZVByVCRJf/zKp9jMcRVJSXp16 ++Sqw4qifz/INEPGPgM3vr0GdvEN27S1IEFUZDU0M+e6KcHeIoLEPnhQPnZfO/kPT +69gRFOZAcONvnGyP+Fj74fRWpWWIIN6b8oIzPN8tez9g+DdmXHf/LnD0fGIfhqPI +GjjZcNJ8oa2F2qZfmwtrYs8UIChJxfZXK/lV7Jgf48ZDSF73war8nGHA/Sir4NsF +9cp3TxTSpXo2iXqb8ZH679q7OJ3UE7OiVKr2XzVEo7T/QSPnV4l9eiq9lDb/1cnS +AFfm3m0+Zqy+uE+Qfkigt5jWXBLQ3DbJEUNriumsit5dMeh2zCMwtYsWC8fumJw1 +6kJVZ7yEFXhFggTkHrgTZCI/9ym8FxCcz7W9qNy47h3aDOMs+yRidyl279FsKMR3 +gkjZmvGyAuZRqNttqldexMGwH1qVPIwDtCHdwesdefAydr/9h/ElDzAyBG31u3zN +7Bp5/JkN9OycTvUB7SIMR80Q7wwPJngovRu1wdKQVZC+y/snJR6tQx9u+OuSHrB+ +X0J4LFuxSj5PjsTH5y2o3UFbuKzxaIwbEibPvUc7FqW7O9/N4gYZaANgcodo0ozb +ZjhcL+oE90AGQyKSKGna5bZWdokLQBOUyro442gKXAOVARMzEHwIIWwD3bm6Mj0a +AmaMta3/LoCj54ESPFqRm7lCTmTj4gR6t5TED810hEimbxE8CBB6yrGTyj+vn+nH +9Wn1D+Pgo0QuHp1yBZI5xrFtX2Dm6TW7cKuv0oohgjd2WFKNIqzDhOeIslk3K9TL +kcBqeYMDJ5xi/R5/dfE5yLg7WhsPcH5QcMO2I6Sm+smXWytB8zo3NkX5UXUTdWNp +-----END RSA PRIVATE KEY----- diff --git a/ca/testdata/secrets/rsa_root_ca.crt b/ca/testdata/secrets/rsa_root_ca.crt new file mode 100644 index 00000000..8c2a72f5 --- /dev/null +++ b/ca/testdata/secrets/rsa_root_ca.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE/DCCAuSgAwIBAgIRAOFB5q6CzRilW0ERurTeSQ4wDQYJKoZIhvcNAQELBQAw +FjEUMBIGA1UEAxMLcnNhLXJvb3QtY2EwHhcNMjIxMjAyMTE0MjI1WhcNMzIxMTI5 +MTE0MjI1WjAWMRQwEgYDVQQDEwtyc2Etcm9vdC1jYTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBALIcD6VfJ6NZLWOhrLHr9au3WhKOmvt2gp+l53rjmwP3 +PLApSnFi3PGE9gvwzdGd0XeIIithgj+FiZEk/gdWfjx3abjpNM4uTsjBweQ4d3uT +zgH5h/AmGbSVUweqOCvmK5cingcvc2UGVbDo5VOP50bZR8O9NY2OQNgFHig7Z+xT +eZSkGF7Sxm1zNMNU7BZqBNofFcwYDIaR/sBFuE9Im2qXj0duHbC1GXuVivE+iTDI +ir52qsuobnXwEQyGe3EOwIAD9AMPsmmJ/vZSaVLFO0dIbSwTqB3nXaNC8+hA/dyX +a9gEdVsSzKUiXfsk5awAOHOAEpCusywyJzZhhIyqot4rr3A3nuVOmg5utvJX2jMr +wtGT7n7YhJWJVIcB/ahx/G7qwkcphEM7jnfweVgdDGTjcJ2tZchqx4U0axo+5wQy +hebLz6z9QLkmfIMW0qjV6JcrYz2U1T4xSFmyNBhOrJQw4OFufSEWqYSJxoUHHOBn +Dy4V98AhoIkK5UDTeTrQea5QJRGRhiCfl6VpuO1YAP/4oNrJa+rWrzYPU5bq3FF2 +z2aCb9MAxnDQmfHfCSn6avioM2BcRQ8SfVVj1XsI4JtS7i7kqsHzuezJp28Jvll5 +sOTGp6CNASLJg2zRE3LZbNuuZ3JlVDZPDHqOqci7Gw8xwNXZv1SNNVDBDLsN3sSd +AgMBAAGjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMB0G +A1UdDgQWBBQnfVmWDD6XwywSo8khRDcCFyabszANBgkqhkiG9w0BAQsFAAOCAgEA +mV/q1xjM9k+2Z9MhC7RXT0a/9bMVry9RiWp4xD09bPLRso+T9Pys/m222DxTjW6+ +JAM1fwm6HKESeWHToIBnB1htIG2jMSC5wn2/oKfEFnJU16f4lE7aoFMHP6Pxhf9w +dGXvb7Pbze1MHNtNabx5x2uVp5DLTjOjL2o7pufSXNpB3djx20jADx5KqqXQiIqk +rMDi1rpWRnNT/IqkkmDdGbG9WyKp28z8HPW2Iyq80zp1d3diJvtRZTeDTBrc8NGk +96RpK1IVY0c8Z56UfecILuthm18ChSxm8DTXdc1CA1e89fiZ/pfEXPrbYLdcq8/b +WQjA39z0zTiGC6gjd0g5hGeXZ5ThuW0s1EwpWmcF5bvHOxK2SOtYzxxy6bhbOzU7 +4J0uCj+GIR7eKtdrHdRv0cHFPE4/XDEI/93UCJjOphNekSKGUiQKzTZhjP7g6DdM +bBtsdEwkVckqFTrOlHy1aDfoUzuOB8DDwSs/59h/0a2MtGBq1MAjLaZUlDAUUbYO +x8VbloQHxcEdrUYmIGEhoI+zPz6Bm2xsaIs72R10y9PfFV5xY9JcsnA9AvJ2KOHo +RH7gmqh7GyqCNcQf7bfhC2SLMa8luEn0tQFVx7F/vbO1rzpvsEvtsvHka1SEEqS/ +ctNS8RyWPh92jaJQ4U9nWMHOJJZ4LYW38gsMc/om7+k= +-----END CERTIFICATE----- diff --git a/ca/testdata/secrets/rsa_root_ca_key b/ca/testdata/secrets/rsa_root_ca_key new file mode 100644 index 00000000..b0dba1db --- /dev/null +++ b/ca/testdata/secrets/rsa_root_ca_key @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,2b2138d58dc4fe659251306226ee53ef + +f6H0Rvs3FmbjNk31qTe/CikGW6oFT3p+6A/g6E7gnloHuxVv4HdM0RDHOUvSMG49 +hb2kLYfbztJ7+RyGdc5JhozgfwRJsSP+iT0JbDQyHlTWzG5YasMnGrMbeLayn0Bw +fhawiDOaBzK36hBFnx3aE5D3MOEbJM81/tZ7SoAovvgLZmhTH5w6cGYSJle6Fgey +47skoiuRX4JJ1Us6aiME203l6AdPEs01XVPRQFZHMdbTCQ5ZVeH/BS2GHn2vfosg +PLJ6RUQIILuBytRwiWZIXoVZDI7T0d6eiUizj2cyIi58rypkGDDeDvN6Uzq/r8Or +epwo28YlIDRz4H40XIGVDnD8LcIbAmcfe2FTz+TbTTcQcBySnuQQJhJ6aGDnE2LG +5QPSZOLAStlMP6ceGB6oeo7nBYLnqxUbDyeNeeIfBmf2NDgFpIwjgjs+QMXg1XFP +/Z0BnKm/bmKKc94w3BwsAsZ0RwZTS+WyK+xKoXpQNVRoECKZt2oDTIPUX5no7dQO +CQPOvJoYjGd+IS1jykvViYZYW4Lae08thWOMbWVTyV882/wpR7DN697w38VFLw2x +q9dhd4wFZfzwGndO6xUq5h3qHGXg5xPS/ArvK5KGRXFusHI0HKqK5TeJwW2NBFky +AhYPr/wdGdyL+mjU4ynjG4AekdAUi8t2Jpxf7+NuWGIbD/J00GPExOUuM68gqmuw +9wGXj0EaPEyBSWc7Sq95o5+eg5VjwLsGnEKLtYLJRuwOnQ+6LZddOsaNNHgafP3N +yrDN4Xu2NBowzrbAPv4nFxQF6pNkAJTtTOimRQA5qwf04Er1KSw3SAs0s8WXTDnp +kySMpvSibBo4CQE+XvjGISg+yTY7/Uj6lZrJFzwrl4Nne1k960qofY7B6D8sGSxk +8DZpsNkfY86juIBUri9pp2+nqEmj8NcK0gGpNgomYbPQHoQuudfWKER8JEX5hp9g +ik3RZIpes3yKJYbzEKpeAOMRy2yS75B9DOpvIO7YPfUsjGVWnV55Cqni+z2QUOWR +laRnRReQRQ/C3sinoFCEDZNmw5W5ex+iaGxj7d88tolFzvN6P7JdJTrq9kZ6pEIV +yJnWT6dxoabxtyArpOAIwsEbeVXyFq1o0UF5x8Y1xOJOvlWallj0cZo/mHO+sFVT +VLR1Ijh+klcKjJnU1s7yk/Ls/eRMJzSnk3iAV9WJuuOFyvpzmO26uTQh0f1rSrk/ +k4DA9Klywo9OFlCvGU5xuRhISDEBBrxtKQMkefFQRBxclqZldDmbss2Zr4vfmhjx +5JdETi7q40Nt0kWsXi/XXIriEILvVIShYuER84aYSG2LQw3kOREA2BLOfJXYvRxc +g3UzHviOYRpzPb7fJmOsSa1sRMWTKbZn1eBwFZbmqZmFboVzUmYUiFqFFCMGaPq0 +afhkZGmM/dPgStruKEyXCcAHnsIFruNZGICnDUbQyAwXlw66fJG/IwL0FbTdhr3i +68wlLKA3uAAdTPkNQvef9Ed5b2xu9Yazt3ub93sKTbSzv1PZU+VVyrfmCVXXRrku +ybRoLd4HAeuMKZ7jF4dLNzPDvJ6SfdMP7Qw/NoeCBogbtsstsHe+3hOEmBYlPZpT ++AyXV/BNEvli9uBUlwy9B7B6s0hj1bxMnxHTCxEuCBf3EYgRlwcIRqSCi7EV6FuT +1ScpROJP3U1+FSF8b2pP7W23xAGtXUOBSoGvMlZcxF3+xB4L3zVMqfqwlbLXvSix +QoXKYtESBmVVLT5jc+sWUelEynXowG+YaDVUyEBx99vlXAznQ3D99rD1dzvzx9Um +TI0aV2IjeUgOXWP5b7rVs+GJ82DDUBBsZYEYK6JIpiBtdhAYhWbplusJCwdOAmyj ++9JtfLrdJTohAn1smp285wHrHgdhLECEotaHqh8Cubrw5u66couCw7ibVSDrmshi +8xiPL3hp0jWbE10Lah4MK5pMLfjq2wOta435RuD3HNJu1nGGvEIb/+Malef8JzBW +y7iABGlAHPNhcOheNQX/nXuTnUOwv69N03/i+/hWzGHIjYH/nI02EZ+CHtuCbeUd +JCP3Ia1xCDEZJEtb2GmswgB5P06U7z2rZemb2HIWC6/Sors72WlEZhtis1y9/mRF +1pmGFsqmQCHk7XNrdZB56KjB4Kkj7eOE5xO01ALdZXs7nIhB7S9Sqk6Rtf+Th85N +1BT/esB3d30ORVu3TbV1uashC71ThtdNEpYNi441Yfs8u/c/c+7NtUoxBcIIvMEs +FMCLs4Nqt1y2UxocWGQtii2EvjwStAgtNIGhq+/6SZVRIU3CyYm3RRx5eQ1VdfNh +i+bOJlf5l8/gZXsaWwD2tBOCibml9GbFJeGPQi9Rc6AUUeTGmNRnA1PUcwbs96uz +F/lmo1dms5jiV2+d+SFQgAujrJSRsST4GxpqDlU3T/anIknusTkOyyuP3Z3EY6eA +LiY6sdKYj40IFdpM3aLl6LAIgkTXS1ji4nvfu5CAdBAsntTRVRB2Ew3ux8+ZsShg +Rg/LMEmEP8oMq1JFrx9q2rlBghWyUdY5M+ZY/e8hGheMuaUGs8SeqWlI513+CvLw +sWOUwnox+j9rjvj43Q3ac9mbqjwjykMpBDAMhAeJkW5FSK5gc6LPmRvUhfyv0De7 +bgA6dpQYh6+l3yKoWmNQdFZ0YtuEc+wzzgbyUE1s/BOTB3WDLaBnUAw7R3nkTUyX +05t5b1NCcrj2fpe0DhRa7KqNQTVazEgZIkd0nPVGP8bmfMEMCXw2ri0wls0F4KkB +Y52Ctx+/kQkP8HYJMV79RURNvI9204C8a+w09++w9rmHuUlGXfJ7/iVADRaXI1pM +E+N4q7KrhcQYlRWthmwsol2unqtnTHjSyHiYtHeagNTt2eNkAqG61E+mtYsjQ6Al ++aL3vi73hJ6oNLpT8Cb2S4XYDziIlKTtX4biZYJgkc/P4Ado0Z5ZhXqLnt+BsrDv +FuqpZoHp0BA9qaCPuocL7Ne6cVTY1PGKS+Gkh9u+QWmrp1QGltNQNUiNUiuSKP79 +41tdta3UYstwtuTydQPGbg71YPSXM6CqEUuYINP5yVSiO3k1aPA82Uxr3TYdnym7 +D54ctp9HHk3SYpA/zdT5clNwyNiTv/bZ2Wa0DUpBRK3epvLVB6fyGlmSFnOtyelP +-----END RSA PRIVATE KEY----- diff --git a/ca/tls_test.go b/ca/tls_test.go index 946a6cb5..dbcc6023 100644 --- a/ca/tls_test.go +++ b/ca/tls_test.go @@ -59,9 +59,13 @@ func generateOTT(subject string) string { return raw } -func startTestServer(tlsConfig *tls.Config, handler http.Handler) *httptest.Server { +func startTestServer(baseContext context.Context, tlsConfig *tls.Config, handler http.Handler) *httptest.Server { srv := httptest.NewUnstartedServer(handler) srv.TLS = tlsConfig + // Base context MUST be set before the start of the server + srv.Config.BaseContext = func(l net.Listener) context.Context { + return baseContext + } srv.StartTLS() // Force the use of GetCertificate on IPs srv.TLS.Certificates = nil @@ -78,11 +82,8 @@ func startCATestServer() *httptest.Server { panic(err) } // Use a httptest.Server instead - srv := startTestServer(ca.srv.TLSConfig, ca.srv.Handler) baseContext := buildContext(ca.auth, nil, nil, nil) - srv.Config.BaseContext = func(net.Listener) context.Context { - return baseContext - } + srv := startTestServer(baseContext, ca.srv.TLSConfig, ca.srv.Handler) return srv } @@ -153,7 +154,7 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) { if err != nil { t.Fatalf("Client.GetServerTLSConfig() error = %v", err) } - srvMTLS := startTestServer(tlsConfig, serverHandler(t, clientDomain)) + srvMTLS := startTestServer(context.Background(), tlsConfig, serverHandler(t, clientDomain)) defer srvMTLS.Close() // Create TLS server @@ -163,7 +164,7 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) { if err != nil { t.Fatalf("Client.GetServerTLSConfig() error = %v", err) } - srvTLS := startTestServer(tlsConfig, serverHandler(t, clientDomain)) + srvTLS := startTestServer(context.Background(), tlsConfig, serverHandler(t, clientDomain)) defer srvTLS.Close() tests := []struct { @@ -229,7 +230,7 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) { defer resp.Body.Close() b, err := io.ReadAll(resp.Body) if err != nil { - t.Fatalf("ioutil.RealAdd() error = %v", err) + t.Fatalf("io.ReadAll() error = %v", err) } if !bytes.Equal(b, []byte("ok")) { t.Errorf("response body unexpected, got %s, want ok", b) @@ -258,7 +259,7 @@ func TestClient_GetServerTLSConfig_renew(t *testing.T) { if err != nil { t.Fatalf("Client.GetServerTLSConfig() error = %v", err) } - srvMTLS := startTestServer(tlsConfig, serverHandler(t, clientDomain)) + srvMTLS := startTestServer(context.Background(), tlsConfig, serverHandler(t, clientDomain)) defer srvMTLS.Close() // Start TLS server @@ -268,7 +269,7 @@ func TestClient_GetServerTLSConfig_renew(t *testing.T) { if err != nil { t.Fatalf("Client.GetServerTLSConfig() error = %v", err) } - srvTLS := startTestServer(tlsConfig, serverHandler(t, clientDomain)) + srvTLS := startTestServer(context.Background(), tlsConfig, serverHandler(t, clientDomain)) defer srvTLS.Close() // Transport @@ -343,7 +344,7 @@ func TestClient_GetServerTLSConfig_renew(t *testing.T) { defer resp.Body.Close() b, err := io.ReadAll(resp.Body) if err != nil { - t.Errorf("ioutil.RealAdd() error = %v", err) + t.Errorf("io.ReadAll() error = %v", err) return } if !bytes.Equal(b, []byte("ok")) { diff --git a/cas/apiv1/options_test.go b/cas/apiv1/options_test.go index 2442b0af..d48b63df 100644 --- a/cas/apiv1/options_test.go +++ b/cas/apiv1/options_test.go @@ -12,18 +12,19 @@ type testCAS struct { name string } -func (t *testCAS) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) { +func (t *testCAS) CreateCertificate(*CreateCertificateRequest) (*CreateCertificateResponse, error) { return nil, nil } -func (t *testCAS) RenewCertificate(req *RenewCertificateRequest) (*RenewCertificateResponse, error) { +func (t *testCAS) RenewCertificate(*RenewCertificateRequest) (*RenewCertificateResponse, error) { return nil, nil } -func (t *testCAS) RevokeCertificate(req *RevokeCertificateRequest) (*RevokeCertificateResponse, error) { +func (t *testCAS) RevokeCertificate(*RevokeCertificateRequest) (*RevokeCertificateResponse, error) { return nil, nil } +//nolint:gocritic // ignore sloppy test func name func mockRegister(t *testing.T) { t.Helper() Register(SoftCAS, func(ctx context.Context, opts Options) (CertificateAuthorityService, error) { diff --git a/cas/cas_test.go b/cas/cas_test.go index f971c5a8..9fc06567 100644 --- a/cas/cas_test.go +++ b/cas/cas_test.go @@ -18,15 +18,15 @@ import ( type mockCAS struct{} -func (m *mockCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1.CreateCertificateResponse, error) { +func (m *mockCAS) CreateCertificate(*apiv1.CreateCertificateRequest) (*apiv1.CreateCertificateResponse, error) { panic("not implemented") } -func (m *mockCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) { +func (m *mockCAS) RenewCertificate(*apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) { panic("not implemented") } -func (m *mockCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { +func (m *mockCAS) RevokeCertificate(*apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { panic("not implemented") } diff --git a/cas/cloudcas/cloudcas_test.go b/cas/cloudcas/cloudcas_test.go index d4e92a32..95446ee6 100644 --- a/cas/cloudcas/cloudcas_test.go +++ b/cas/cloudcas/cloudcas_test.go @@ -194,43 +194,43 @@ func (b *badSigner) Public() crypto.PublicKey { return b.pub } -func (b *badSigner) Sign(rnd io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { +func (b *badSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) { return nil, fmt.Errorf("💥") } -func (c *testClient) CreateCertificate(ctx context.Context, req *pb.CreateCertificateRequest, opts ...gax.CallOption) (*pb.Certificate, error) { +func (c *testClient) CreateCertificate(context.Context, *pb.CreateCertificateRequest, ...gax.CallOption) (*pb.Certificate, error) { return c.certificate, c.err } -func (c *testClient) RevokeCertificate(ctx context.Context, req *pb.RevokeCertificateRequest, opts ...gax.CallOption) (*pb.Certificate, error) { +func (c *testClient) RevokeCertificate(context.Context, *pb.RevokeCertificateRequest, ...gax.CallOption) (*pb.Certificate, error) { return c.certificate, c.err } -func (c *testClient) GetCertificateAuthority(ctx context.Context, req *pb.GetCertificateAuthorityRequest, opts ...gax.CallOption) (*pb.CertificateAuthority, error) { +func (c *testClient) GetCertificateAuthority(context.Context, *pb.GetCertificateAuthorityRequest, ...gax.CallOption) (*pb.CertificateAuthority, error) { return c.certificateAuthority, c.err } -func (c *testClient) CreateCertificateAuthority(ctx context.Context, req *pb.CreateCertificateAuthorityRequest, opts ...gax.CallOption) (*privateca.CreateCertificateAuthorityOperation, error) { +func (c *testClient) CreateCertificateAuthority(context.Context, *pb.CreateCertificateAuthorityRequest, ...gax.CallOption) (*privateca.CreateCertificateAuthorityOperation, error) { return nil, errors.New("use NewMockCertificateAuthorityClient") } -func (c *testClient) FetchCertificateAuthorityCsr(ctx context.Context, req *pb.FetchCertificateAuthorityCsrRequest, opts ...gax.CallOption) (*pb.FetchCertificateAuthorityCsrResponse, error) { +func (c *testClient) FetchCertificateAuthorityCsr(context.Context, *pb.FetchCertificateAuthorityCsrRequest, ...gax.CallOption) (*pb.FetchCertificateAuthorityCsrResponse, error) { return nil, errors.New("use NewMockCertificateAuthorityClient") } -func (c *testClient) ActivateCertificateAuthority(ctx context.Context, req *pb.ActivateCertificateAuthorityRequest, opts ...gax.CallOption) (*privateca.ActivateCertificateAuthorityOperation, error) { +func (c *testClient) ActivateCertificateAuthority(context.Context, *pb.ActivateCertificateAuthorityRequest, ...gax.CallOption) (*privateca.ActivateCertificateAuthorityOperation, error) { return nil, errors.New("use NewMockCertificateAuthorityClient") } -func (c *testClient) EnableCertificateAuthority(ctx context.Context, req *pb.EnableCertificateAuthorityRequest, opts ...gax.CallOption) (*privateca.EnableCertificateAuthorityOperation, error) { +func (c *testClient) EnableCertificateAuthority(context.Context, *pb.EnableCertificateAuthorityRequest, ...gax.CallOption) (*privateca.EnableCertificateAuthorityOperation, error) { return nil, errors.New("use NewMockCertificateAuthorityClient") } -func (c *testClient) GetCaPool(ctx context.Context, req *pb.GetCaPoolRequest, opts ...gax.CallOption) (*pb.CaPool, error) { +func (c *testClient) GetCaPool(context.Context, *pb.GetCaPoolRequest, ...gax.CallOption) (*pb.CaPool, error) { return nil, errors.New("use NewMockCertificateAuthorityClient") } -func (c *testClient) CreateCaPool(ctx context.Context, req *pb.CreateCaPoolRequest, opts ...gax.CallOption) (*privateca.CreateCaPoolOperation, error) { +func (c *testClient) CreateCaPool(context.Context, *pb.CreateCaPoolRequest, ...gax.CallOption) (*privateca.CreateCaPoolOperation, error) { return nil, errors.New("use NewMockCertificateAuthorityClient") } diff --git a/cas/softcas/softcas.go b/cas/softcas/softcas.go index 6eae9e9e..58be8aab 100644 --- a/cas/softcas/softcas.go +++ b/cas/softcas/softcas.go @@ -36,7 +36,7 @@ type SoftCAS struct { // New creates a new CertificateAuthorityService implementation using Golang or KMS // crypto. -func New(ctx context.Context, opts apiv1.Options) (*SoftCAS, error) { +func New(_ context.Context, opts apiv1.Options) (*SoftCAS, error) { if !opts.IsCreator { switch { case len(opts.CertificateChain) == 0 && opts.CertificateSigner == nil: diff --git a/cas/softcas/softcas_test.go b/cas/softcas/softcas_test.go index 5c8a2f1f..11bf217a 100644 --- a/cas/softcas/softcas_test.go +++ b/cas/softcas/softcas_test.go @@ -101,7 +101,7 @@ type mockKeyManager struct { errClose error } -func (m *mockKeyManager) GetPublicKey(req *kmsapi.GetPublicKeyRequest) (crypto.PublicKey, error) { +func (m *mockKeyManager) GetPublicKey(*kmsapi.GetPublicKeyRequest) (crypto.PublicKey, error) { signer := testSigner if m.signer != nil { signer = m.signer @@ -121,7 +121,7 @@ func (m *mockKeyManager) CreateKey(req *kmsapi.CreateKeyRequest) (*kmsapi.Create }, m.errCreateKey } -func (m *mockKeyManager) CreateSigner(req *kmsapi.CreateSignerRequest) (crypto.Signer, error) { +func (m *mockKeyManager) CreateSigner(*kmsapi.CreateSignerRequest) (crypto.Signer, error) { signer := testSigner if m.signer != nil { signer = m.signer @@ -129,7 +129,7 @@ func (m *mockKeyManager) CreateSigner(req *kmsapi.CreateSignerRequest) (crypto.S return signer, m.errCreatesigner } -func (m *mockKeyManager) CreateDecrypter(req *kmsapi.CreateDecrypterRequest) (crypto.Decrypter, error) { +func (m *mockKeyManager) CreateDecrypter(*kmsapi.CreateDecrypterRequest) (crypto.Decrypter, error) { return nil, nil } @@ -147,6 +147,7 @@ func (b *badSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, er return nil, fmt.Errorf("💥") } +//nolint:gocritic // ignore sloppy test func name func mockNow(t *testing.T) { tmp := now now = func() time.Time { diff --git a/cas/stepcas/issuer_test.go b/cas/stepcas/issuer_test.go index ff4f45f5..2a47d885 100644 --- a/cas/stepcas/issuer_test.go +++ b/cas/stepcas/issuer_test.go @@ -15,11 +15,11 @@ import ( type mockErrIssuer struct{} -func (m mockErrIssuer) SignToken(subject string, sans []string, info *raInfo) (string, error) { +func (m mockErrIssuer) SignToken(string, []string, *raInfo) (string, error) { return "", apiv1.NotImplementedError{} } -func (m mockErrIssuer) RevokeToken(subject string) (string, error) { +func (m mockErrIssuer) RevokeToken(string) (string, error) { return "", apiv1.NotImplementedError{} } @@ -29,7 +29,7 @@ func (m mockErrIssuer) Lifetime(d time.Duration) time.Duration { type mockErrSigner struct{} -func (s *mockErrSigner) Sign(payload []byte) (*jose.JSONWebSignature, error) { +func (s *mockErrSigner) Sign([]byte) (*jose.JSONWebSignature, error) { return nil, apiv1.NotImplementedError{} } diff --git a/cas/stepcas/stepcas.go b/cas/stepcas/stepcas.go index 7c0dc86f..9f94c6ae 100644 --- a/cas/stepcas/stepcas.go +++ b/cas/stepcas/stepcas.go @@ -157,7 +157,7 @@ func (s *StepCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1 // GetCertificateAuthority returns the root certificate of the certificate // authority using the configured fingerprint. -func (s *StepCAS) GetCertificateAuthority(req *apiv1.GetCertificateAuthorityRequest) (*apiv1.GetCertificateAuthorityResponse, error) { +func (s *StepCAS) GetCertificateAuthority(*apiv1.GetCertificateAuthorityRequest) (*apiv1.GetCertificateAuthorityResponse, error) { resp, err := s.client.Root(s.fingerprint) if err != nil { return nil, err diff --git a/cas/stepcas/x5c_issuer_test.go b/cas/stepcas/x5c_issuer_test.go index 3f7f372f..c32490ef 100644 --- a/cas/stepcas/x5c_issuer_test.go +++ b/cas/stepcas/x5c_issuer_test.go @@ -22,10 +22,11 @@ func (b noneSigner) Public() crypto.PublicKey { return []byte(b) } -func (b noneSigner) Sign(rnd io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { +func (b noneSigner) Sign(_ io.Reader, digest []byte, _ crypto.SignerOpts) (signature []byte, err error) { return digest, nil } +//nolint:gocritic // ignore sloppy test func name func fakeTime(t *testing.T) { t.Helper() tmp := timeNow diff --git a/cas/vaultcas/vaultcas.go b/cas/vaultcas/vaultcas.go index c618a0a0..5908cb7d 100644 --- a/cas/vaultcas/vaultcas.go +++ b/cas/vaultcas/vaultcas.go @@ -37,6 +37,7 @@ type VaultOptions struct { PKIRoleEd25519 string `json:"pkiRoleEd25519,omitempty"` AuthType string `json:"authType,omitempty"` AuthMountPath string `json:"authMountPath,omitempty"` + Namespace string `json:"namespace,omitempty"` AuthOptions json.RawMessage `json:"authOptions,omitempty"` } @@ -90,6 +91,10 @@ func New(ctx context.Context, opts apiv1.Options) (*VaultCAS, error) { return nil, fmt.Errorf("unable to configure %s auth method: %w", vc.AuthType, err) } + if vc.Namespace != "" { + client.SetNamespace(vc.Namespace) + } + authInfo, err := client.Auth().Login(ctx, method) if err != nil { return nil, fmt.Errorf("unable to login to %s auth method: %w", vc.AuthType, err) @@ -127,7 +132,7 @@ func (v *VaultCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv // GetCertificateAuthority returns the root certificate of the certificate // authority using the configured fingerprint. -func (v *VaultCAS) GetCertificateAuthority(req *apiv1.GetCertificateAuthorityRequest) (*apiv1.GetCertificateAuthorityResponse, error) { +func (v *VaultCAS) GetCertificateAuthority(*apiv1.GetCertificateAuthorityRequest) (*apiv1.GetCertificateAuthorityResponse, error) { secret, err := v.client.Logical().Read(v.config.PKIMountPath + "/cert/ca_chain") if err != nil { return nil, fmt.Errorf("error reading ca chain: %w", err) @@ -161,7 +166,7 @@ func (v *VaultCAS) GetCertificateAuthority(req *apiv1.GetCertificateAuthorityReq // RenewCertificate will always return a non-implemented error as renewals // are not supported yet. -func (v *VaultCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) { +func (v *VaultCAS) RenewCertificate(*apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) { return nil, apiv1.NotImplementedError{Message: "vaultCAS does not support renewals"} } @@ -215,7 +220,7 @@ func (v *VaultCAS) createCertificate(cr *x509.CertificateRequest, lifetime time. Bytes: cr.Raw, })), "format": "pem_bundle", - "ttl": lifetime.Seconds(), + "ttl": lifetime.String(), } secret, err := v.client.Logical().Write(v.config.PKIMountPath+"/sign/"+vaultPKIRole, vaultReq) diff --git a/cmd/step-ca/main.go b/cmd/step-ca/main.go index 11756b93..289815ef 100644 --- a/cmd/step-ca/main.go +++ b/cmd/step-ca/main.go @@ -5,7 +5,6 @@ import ( "fmt" "html" "log" - "math/rand" "net/http" "os" "reflect" @@ -52,7 +51,6 @@ var ( func init() { step.Set("Smallstep CA", Version, BuildTime) authority.GlobalVersion.Version = Version - rand.Seed(time.Now().UnixNano()) // Add support for asking passwords pemutil.PromptPassword = func(msg string) ([]byte, error) { return ui.PromptPassword(msg) @@ -102,6 +100,12 @@ Please send us a sentence or two, good or bad: **feedback@smallstep.com** or htt ` func main() { + // initialize step environment. + if err := step.Init(); err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + // Initialize windows terminal ui.Init() diff --git a/db/db.go b/db/db.go index b3137a50..03295f22 100644 --- a/db/db.go +++ b/db/db.go @@ -119,7 +119,7 @@ func New(c *Config) (AuthDB, error) { db, err := nosql.New(c.Type, c.DataSource, opts...) if err != nil { - return nil, errors.Wrapf(err, "Error opening database of Type %s with source %s", c.Type, c.DataSource) + return nil, errors.Wrapf(err, "Error opening database of Type %s", c.Type) } tables := [][]byte{ diff --git a/db/simple.go b/db/simple.go index 6321e86f..dbef2d61 100644 --- a/db/simple.go +++ b/db/simple.go @@ -20,24 +20,24 @@ type SimpleDB struct { usedTokens *sync.Map } -func newSimpleDB(c *Config) (*SimpleDB, error) { +func newSimpleDB(*Config) (*SimpleDB, error) { db := &SimpleDB{} db.usedTokens = new(sync.Map) return db, nil } // IsRevoked noop -func (s *SimpleDB) IsRevoked(sn string) (bool, error) { +func (s *SimpleDB) IsRevoked(string) (bool, error) { return false, nil } // IsSSHRevoked noop -func (s *SimpleDB) IsSSHRevoked(sn string) (bool, error) { +func (s *SimpleDB) IsSSHRevoked(string) (bool, error) { return false, nil } // Revoke returns a "NotImplemented" error. -func (s *SimpleDB) Revoke(rci *RevokedCertificateInfo) error { +func (s *SimpleDB) Revoke(*RevokedCertificateInfo) error { return ErrNotImplemented } @@ -52,22 +52,22 @@ func (s *SimpleDB) GetCRL() (*CertificateRevocationListInfo, error) { } // StoreCRL returns a "NotImplemented" error. -func (s *SimpleDB) StoreCRL(crlInfo *CertificateRevocationListInfo) error { +func (s *SimpleDB) StoreCRL(*CertificateRevocationListInfo) error { return ErrNotImplemented } // RevokeSSH returns a "NotImplemented" error. -func (s *SimpleDB) RevokeSSH(rci *RevokedCertificateInfo) error { +func (s *SimpleDB) RevokeSSH(*RevokedCertificateInfo) error { return ErrNotImplemented } // GetCertificate returns a "NotImplemented" error. -func (s *SimpleDB) GetCertificate(serialNumber string) (*x509.Certificate, error) { +func (s *SimpleDB) GetCertificate(string) (*x509.Certificate, error) { return nil, ErrNotImplemented } // StoreCertificate returns a "NotImplemented" error. -func (s *SimpleDB) StoreCertificate(crt *x509.Certificate) error { +func (s *SimpleDB) StoreCertificate(*x509.Certificate) error { return ErrNotImplemented } @@ -90,12 +90,12 @@ func (s *SimpleDB) UseToken(id, tok string) (bool, error) { } // IsSSHHost returns a "NotImplemented" error. -func (s *SimpleDB) IsSSHHost(principal string) (bool, error) { +func (s *SimpleDB) IsSSHHost(string) (bool, error) { return false, ErrNotImplemented } // StoreSSHCertificate returns a "NotImplemented" error. -func (s *SimpleDB) StoreSSHCertificate(crt *ssh.Certificate) error { +func (s *SimpleDB) StoreSSHCertificate(*ssh.Certificate) error { return ErrNotImplemented } @@ -112,7 +112,7 @@ func (s *SimpleDB) Shutdown() error { // nosql.DB interface implementation // // Open opens the database available with the given options. -func (s *SimpleDB) Open(dataSourceName string, opt ...database.Option) error { +func (s *SimpleDB) Open(string, ...database.Option) error { return ErrNotImplemented } @@ -122,43 +122,43 @@ func (s *SimpleDB) Close() error { } // Get returns the value stored in the given table/bucket and key. -func (s *SimpleDB) Get(bucket, key []byte) ([]byte, error) { +func (s *SimpleDB) Get([]byte, []byte) ([]byte, error) { return nil, ErrNotImplemented } // Set sets the given value in the given table/bucket and key. -func (s *SimpleDB) Set(bucket, key, value []byte) error { +func (s *SimpleDB) Set([]byte, []byte, []byte) error { return ErrNotImplemented } // CmpAndSwap swaps the value at the given bucket and key if the current // value is equivalent to the oldValue input. Returns 'true' if the // swap was successful and 'false' otherwise. -func (s *SimpleDB) CmpAndSwap(bucket, key, oldValue, newValue []byte) ([]byte, bool, error) { +func (s *SimpleDB) CmpAndSwap([]byte, []byte, []byte, []byte) ([]byte, bool, error) { return nil, false, ErrNotImplemented } // Del deletes the data in the given table/bucket and key. -func (s *SimpleDB) Del(bucket, key []byte) error { +func (s *SimpleDB) Del([]byte, []byte) error { return ErrNotImplemented } // List returns a list of all the entries in a given table/bucket. -func (s *SimpleDB) List(bucket []byte) ([]*database.Entry, error) { +func (s *SimpleDB) List([]byte) ([]*database.Entry, error) { return nil, ErrNotImplemented } // Update performs a transaction with multiple read-write commands. -func (s *SimpleDB) Update(tx *database.Tx) error { +func (s *SimpleDB) Update(*database.Tx) error { return ErrNotImplemented } // CreateTable creates a table or a bucket in the database. -func (s *SimpleDB) CreateTable(bucket []byte) error { +func (s *SimpleDB) CreateTable([]byte) error { return ErrNotImplemented } // DeleteTable deletes a table or a bucket in the database. -func (s *SimpleDB) DeleteTable(bucket []byte) error { +func (s *SimpleDB) DeleteTable([]byte) error { return ErrNotImplemented } diff --git a/docker/Dockerfile.hsm b/docker/Dockerfile.hsm index 8ae1e7c7..c5a54d8c 100644 --- a/docker/Dockerfile.hsm +++ b/docker/Dockerfile.hsm @@ -6,7 +6,7 @@ COPY . . RUN apt-get update RUN apt-get install -y --no-install-recommends \ gcc pkgconf libpcsclite-dev libcap2-bin -RUN make V=1 GOFLAGS="" bin/step-ca +RUN make V=1 GO_ENVS="CGO_ENABLED=1" bin/step-ca RUN setcap CAP_NET_BIND_SERVICE=+eip bin/step-ca FROM smallstep/step-kms-plugin:bullseye AS kms diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 93312ca8..33a14b4d 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -46,7 +46,10 @@ function step_ca_init () { --provisioner-password-file "${STEPPATH}/provisioner_password" --address "${DOCKER_STEPCA_INIT_ADDRESS}" ) - if [ -n "${DOCKER_STEPCA_INIT_PASSWORD}" ]; then + if [ -n "${DOCKER_STEPCA_INIT_PASSWORD_FILE}" ]; then + cat < "${DOCKER_STEPCA_INIT_PASSWORD_FILE}" > "${STEPPATH}/password" + cat < "${DOCKER_STEPCA_INIT_PASSWORD_FILE}" > "${STEPPATH}/provisioner_password" + elif [ -n "${DOCKER_STEPCA_INIT_PASSWORD}" ]; then echo "${DOCKER_STEPCA_INIT_PASSWORD}" > "${STEPPATH}/password" echo "${DOCKER_STEPCA_INIT_PASSWORD}" > "${STEPPATH}/provisioner_password" else diff --git a/go.mod b/go.mod index c99b333b..0895bdce 100644 --- a/go.mod +++ b/go.mod @@ -1,90 +1,91 @@ module github.com/smallstep/certificates -go 1.18 +go 1.20 require ( - cloud.google.com/go/longrunning v0.4.1 - cloud.google.com/go/security v1.14.0 + cloud.google.com/go/longrunning v0.5.1 + cloud.google.com/go/security v1.15.1 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/fxamacker/cbor/v2 v2.4.0 - github.com/go-chi/chi v4.1.2+incompatible + github.com/dgraph-io/badger v1.6.2 + github.com/dgraph-io/badger/v2 v2.2007.4 + github.com/fxamacker/cbor/v2 v2.5.0 + github.com/go-chi/chi/v5 v5.0.10 github.com/golang/mock v1.6.0 - github.com/google/go-attestation v0.4.4-0.20220404204839-8820d49b18d9 github.com/google/go-cmp v0.5.9 - github.com/google/go-tpm v0.3.3 - github.com/google/uuid v1.3.0 - github.com/googleapis/gax-go/v2 v2.8.0 - github.com/hashicorp/vault/api v1.9.0 - github.com/hashicorp/vault/api/auth/approle v0.4.0 - github.com/hashicorp/vault/api/auth/kubernetes v0.4.0 + github.com/google/go-tpm v0.9.0 + github.com/google/uuid v1.3.1 + github.com/googleapis/gax-go/v2 v2.12.0 + github.com/hashicorp/vault/api v1.10.0 + github.com/hashicorp/vault/api/auth/approle v0.5.0 + github.com/hashicorp/vault/api/auth/kubernetes v0.5.0 github.com/micromdm/scep/v2 v2.1.0 - github.com/newrelic/go-agent/v3 v3.21.0 + github.com/newrelic/go-agent/v3 v3.25.1 github.com/pkg/errors v0.9.1 github.com/rs/xid v1.5.0 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/slackhq/nebula v1.6.1 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 + github.com/smallstep/go-attestation v0.4.4-0.20230627102604-cf579e53cbd2 github.com/smallstep/nosql v0.6.0 - github.com/stretchr/testify v1.8.2 - github.com/urfave/cli v1.22.12 + github.com/stretchr/testify v1.8.4 + github.com/urfave/cli v1.22.14 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 - go.step.sm/cli-utils v0.7.6 - go.step.sm/crypto v0.29.3 - go.step.sm/linkedca v0.19.0 - golang.org/x/crypto v0.8.0 + go.step.sm/cli-utils v0.8.0 + go.step.sm/crypto v0.35.1 + go.step.sm/linkedca v0.20.1 + golang.org/x/crypto v0.13.0 golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 - golang.org/x/net v0.9.0 - google.golang.org/api v0.118.0 - google.golang.org/grpc v1.54.0 - google.golang.org/protobuf v1.30.0 + golang.org/x/net v0.15.0 + google.golang.org/api v0.142.0 + google.golang.org/grpc v1.58.2 + google.golang.org/protobuf v1.31.0 gopkg.in/square/go-jose.v2 v2.6.0 - ) require ( - cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go v0.110.7 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.13.0 // indirect - cloud.google.com/go/kms v1.10.0 // indirect + cloud.google.com/go/iam v1.1.1 // indirect + cloud.google.com/go/kms v1.15.2 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/ThalesIgnite/crypto11 v1.2.5 // indirect - github.com/aws/aws-sdk-go v1.44.240 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/aws/aws-sdk-go v1.45.12 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgraph-io/badger v1.6.2 // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-kit/kit v0.10.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-piv/piv-go v1.11.0 // indirect - github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/certificate-transparency-go v1.1.4 // indirect - github.com/google/go-tpm-tools v0.3.11 // indirect + github.com/google/certificate-transparency-go v1.1.6 // indirect + github.com/google/go-tpm-tools v0.4.1 // indirect github.com/google/go-tspi v0.3.0 // indirect - github.com/google/s2a-go v0.1.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // 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 @@ -105,7 +106,7 @@ require ( github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgx/v4 v4.18.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.15.11 // indirect + github.com/klauspost/compress v1.16.3 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.8 // indirect @@ -126,26 +127,22 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/thales-e-security/pool v0.0.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.49.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.1.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd // indirect + google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) -// replace github.com/smallstep/nosql => ../nosql -// replace go.step.sm/crypto => ../crypto - -// replace go.step.sm/cli-utils => ../cli-utils -// replace go.step.sm/linkedca => ../linkedca - // use github.com/smallstep/pkcs7 fork with patches applied -replace go.mozilla.org/pkcs7 => github.com/smallstep/pkcs7 v0.0.0-20230302202335-4c094085c948 - -// use github.com/smallstep/go-attestation fork with patches for Windows AK support applied -replace github.com/google/go-attestation v0.4.4-0.20220404204839-8820d49b18d9 => github.com/smallstep/go-attestation v0.4.4-0.20230224121042-1bcb20a75add +replace go.mozilla.org/pkcs7 => github.com/smallstep/pkcs7 v0.0.0-20230615175518-7ce6486b74eb diff --git a/go.sum b/go.sum index daefea9b..403f6eaf 100644 --- a/go.sum +++ b/go.sum @@ -1,121 +1,43 @@ -bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= 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.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= -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.44.3/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.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -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.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -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/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -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/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/kms v1.10.0 h1:Imrtp8792uqNP9bdfPrjtUkjjqOMBcAJ2bdFaAnLhnk= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE= -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/security v1.14.0 h1:ujoEatlM890TPMVv3EBcoVfVh0DibTTTwy+lkUDE+kE= -cloud.google.com/go/security v1.14.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs= -cloud.google.com/go/spanner v1.18.0/go.mod h1:LvAjUXPeJRGNuGpikMULjhLj/t9cRvdc+fxRoLiugXA= -cloud.google.com/go/spanner v1.25.0/go.mod h1:kQUft3x355hzzaeFbObjsvkzZDgpDkesp3v75WBnI8w= -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= -cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g= -code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= -contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= -contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= -contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= -contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ= -contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= -contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE= +cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= +cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= +cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= +cloud.google.com/go/security v1.15.1 h1:jR3itwycg/TgGA0uIgTItcVhA55hKWiNJxaNNpQJaZE= +cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 h1:xGLAFFd9D3iLGxYiUGPdITSzsFmU1K8VtfuUHWAoN7M= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 h1:uqM+VoHjVH6zdlkLF2b6O0ZANcHoj3rO0PoQ3jglUJA= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2/go.mod h1:twTKAa1E6hLmSDjLhaCkbTMQKc7p/rNLU40rLxGEOCI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2 h1:t5+QXLCK9SVi0PPdaY0PrFvYUo24KwA0QwxnaHRSVd4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0 h1:TOFrNxfjslms5nLLIMjW7N0+zSALX4KiGsptmpb16AA= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0/go.mod h1:EAyXOW1F6BTJPiK2pDvmnvxOHPxoTYWoqBeIlql+QhI= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= -github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= -github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= -github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 h1:UE9n9rkJF62ArLb1F3DEjRt8O3jLwMWdSoypKV4f3MU= -github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= @@ -126,63 +48,34 @@ github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= 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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= -github.com/apache/beam v2.32.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= -github.com/apex/logs v0.0.4/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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.44.240 h1:38f1qBTuzotDC6bgSNLw1vrrYaoWL8MNNzwTsGjP6TY= -github.com/aws/aws-sdk-go v1.44.240/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.45.12 h1:+bKbbesGNPp+TeGrcqfrWuZoqcIEhjwKyBMHQPp80Jo= +github.com/aws/aws-sdk-go v1.45.12/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= 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/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -200,46 +93,25 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= 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/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -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/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 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-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 v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -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 v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 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.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/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/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= @@ -252,56 +124,32 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= 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/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o= -github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw= -github.com/fullstorydev/grpcurl v1.8.2/go.mod h1:YvWNT3xRp2KIRuvCphFodG0fKkMXwaxA9CJgKCcyzUQ= -github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= -github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= +github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= -github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-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-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 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= @@ -315,69 +163,44 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-piv/piv-go v1.11.0 h1:5vAaCdRTFSIW4PeqMbnsDlUZ7odMYWnHBDGdmtU/Zhg= github.com/go-piv/piv-go v1.11.0/go.mod h1:NZ2zmjVkfFaL/CF8cVQ/pXdXtuj110zEKGdJM6fJZZM= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -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/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -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-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= 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/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/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 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 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/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -386,120 +209,55 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/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/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ= -github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6/go.mod h1:aF2dp7Dh81mY8Y/zpzyXps4fQW5zQbDu2CxfpJB6NkI= -github.com/google/certificate-transparency-go v1.1.2/go.mod h1:3OL+HKDqHPUfdKrHVQxO6T8nDLO0HF7LRTlkIWXaWvQ= -github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY= -github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ= +github.com/google/certificate-transparency-go v1.1.6 h1:SW5K3sr7ptST/pIvNkSVWMiJqemRmkjJPPT0jzXdOOY= +github.com/google/certificate-transparency-go v1.1.6/go.mod h1:0OJjOsOk+wj6aYQgP7FU0ioQ0AJUmnWPFMqTjQeazPQ= 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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= -github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= -github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= -github.com/google/go-sev-guest v0.5.2 h1:dlCehnxU9aJWEIcTb0j7oZ/yM4qeno7AO6zWokb4mu0= -github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI= -github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw= -github.com/google/go-tpm v0.3.3 h1:P/ZFNBZYXRxc+z7i5uyd8VP7MaDteuLZInzrH2idRGo= -github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51BeghL4= -github.com/google/go-tpm-tools v0.0.0-20190906225433-1614c142f845/go.mod h1:AVfHadzbdzHo54inR2x1v640jdi1YSi3NauM2DUsxk0= -github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= -github.com/google/go-tpm-tools v0.3.9/go.mod h1:22JvWmHcD5w55cs+nMeqDGDxgNS15/2pDq2cLqnc3rc= -github.com/google/go-tpm-tools v0.3.11 h1:imObhmECgDS+ua4aAVPkMfCzE9LTZjS/MmVMCrAG4VY= -github.com/google/go-tpm-tools v0.3.11/go.mod h1:5UcOsOyG5B2hWhKsqNI3TtOjTcZs5sh+3913uMN29Y8= -github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= +github.com/google/go-sev-guest v0.7.0 h1:DBCABhTo7WicP27ZH/hwcCdjcmxFkxxMOQXm5hFcfp4= +github.com/google/go-tdx-guest v0.2.1-0.20230907045450-944015509c84 h1:XqVJa7fVU8b+Hlhcvw49qfg0+LYcRI+V+jYUrSek848= +github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= +github.com/google/go-tpm-tools v0.4.1 h1:gYU6iwRo0tY3V6NDnS6m+XYog+b3g6YFhHQl3sYaUL4= +github.com/google/go-tpm-tools v0.4.1/go.mod h1:w03m0jynhTo7puXTYoyfpNOMqyQ9SB7sixnKWsS/1L0= github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+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-20201218002935-b9804c9f04c2/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/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= -github.com/google/s2a-go v0.1.0 h1:3Qm0liEiCErViKERO2Su5wp+9PfMRiuS6XB5FvpKnYQ= -github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= -github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ= -github.com/google/trillian v1.3.14-0.20210511103300-67b5f349eefa/go.mod h1:s4jO3Ai4NSvxucdvqUHON0bCqJyoya32eNw6XJwsmNc= -github.com/google/trillian v1.4.0/go.mod h1:1Bja2nEgMDlEJWWRXBUemSPG9qYw84ZYX2gHRVHlR+g= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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.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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -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.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ= -github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 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/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c= -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-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.2/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.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= -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/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -515,7 +273,6 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP 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.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -542,23 +299,16 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO 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/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= -github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= -github.com/hashicorp/vault/api/auth/approle v0.4.0 h1:tjJHoUkPx8zRoFlFy86uvgg/1gpTnDPp0t0BYWTKjjw= -github.com/hashicorp/vault/api/auth/approle v0.4.0/go.mod h1:D2gEpR0aS/F/MEcSjmhUlOsuK1RMVZojsnIQAEf0EV0= -github.com/hashicorp/vault/api/auth/kubernetes v0.4.0 h1:f6OIOF9012JIdqYvOeeewxhtQdJosnog2CHzh33j41s= -github.com/hashicorp/vault/api/auth/kubernetes v0.4.0/go.mod h1:tMewM2hPyFNKP1EXdWbc0dUHHoS5V/0qS04BEaxuy78= +github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= +github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/hashicorp/vault/api/auth/approle v0.5.0 h1:a1TK6VGwYqSAfkmX4y4dJ4WBxMU5dStIZqScW4EPXR8= +github.com/hashicorp/vault/api/auth/approle v0.5.0/go.mod h1:CHOQIA1AZACfjTzHggmyfiOZ+xCSKNRFqe48FTCzH0k= +github.com/hashicorp/vault/api/auth/kubernetes v0.5.0 h1:CXO0fD7M3iCGovP/UApeHhPcH4paDFKcu7AjEXi94rI= +github.com/hashicorp/vault/api/auth/kubernetes v0.5.0/go.mod h1:afrElBIO9Q4sHFVuVWgNevG4uAs1bT2AZFA9aEiI608= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -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.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -612,106 +362,68 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= -github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= -github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 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/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 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.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/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/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= -github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 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/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/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= 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-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= 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.7/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.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -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-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/micromdm/scep/v2 v2.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU= github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -731,18 +443,13 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= @@ -750,22 +457,14 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/newrelic/go-agent/v3 v3.21.0 h1:KpkoW6PnSVzEDEO0W/C9LZEZZGwAb+a9g5DN8ifvt4Y= -github.com/newrelic/go-agent/v3 v3.21.0/go.mod h1:rT6ZUxJc5rQbWLyCtjqQCOcfb01lKRFbc1yMQkcboWM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= +github.com/newrelic/go-agent/v3 v3.25.1 h1:Fa+4apO08bcGJk9aOB0TlnacAOrXS4FzMYJzoG0ihA8= +github.com/newrelic/go-agent/v3 v3.25.1/go.mod h1:MANAXqchXM8ko+EXPZ+6mzX243/lehYwJWq8HOV2ytc= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -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/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -775,16 +474,10 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU= @@ -798,53 +491,29 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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 v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -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.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/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.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -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.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 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/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= -github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= -github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 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/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -859,14 +528,10 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo 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/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/schollz/jsonstore v1.1.0 h1:WZBDjgezFS34CHI+myb4s8GGpir3UMpy7vWoCeO0n6E= github.com/schollz/jsonstore v1.1.0/go.mod h1:15c6+9guw8vDRyozGjN3FoILt0wpruJk9Pi66vjaZfg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -875,28 +540,21 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.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.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slackhq/nebula v1.6.1 h1:/OCTR3abj0Sbf2nGoLUrdDXImrCv0ZVFpVPP5qa0DsM= github.com/slackhq/nebula v1.6.1/go.mod h1:UmkqnXe4O53QwToSl/gG7sM4BroQwAB7dd4hUaT6MlI= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smallstep/go-attestation v0.4.4-0.20230224121042-1bcb20a75add h1:nKji/LnfyxNGP6JM5EM2jVTnGus9Fblz9IGxQHRUI6M= -github.com/smallstep/go-attestation v0.4.4-0.20230224121042-1bcb20a75add/go.mod h1:hYP3lyq8hO11DmeEBjZ28norJ2uCFhm/Jj5m8V+hmNE= +github.com/smallstep/go-attestation v0.4.4-0.20230627102604-cf579e53cbd2 h1:UIAS8DTWkeclraEGH2aiJPyNPu16VbT41w4JoBlyFfU= +github.com/smallstep/go-attestation v0.4.4-0.20230627102604-cf579e53cbd2/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4= github.com/smallstep/nosql v0.6.0 h1:ur7ysI8s9st0cMXnTvB8tA3+x5Eifmkb6hl4uqNV5jc= github.com/smallstep/nosql v0.6.0/go.mod h1:jOXwLtockXORUPPZ2MCUcIkGR6w0cN1QGZniY9DITQA= -github.com/smallstep/pkcs7 v0.0.0-20230302202335-4c094085c948 h1:/80FqDt6pzL9clNW8G2IsRAzKGNAuzsEs7g1Y5oaM/Y= -github.com/smallstep/pkcs7 v0.0.0-20230302202335-4c094085c948/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +github.com/smallstep/pkcs7 v0.0.0-20230615175518-7ce6486b74eb h1:wWc8z37baPz2oyusY9BVuM+uPtq6XAOb7qSegevnRs0= +github.com/smallstep/pkcs7 v0.0.0-20230615175518-7ce6486b74eb/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= 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 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/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -908,17 +566,10 @@ github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -927,7 +578,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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 v0.0.0-20170130113145-4d4bfba8f1d1/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= @@ -937,183 +587,82 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= -github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= -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/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 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.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= -github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= +github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= +github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -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/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw= -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-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo= -go.etcd.io/etcd/etcdctl/v3 v3.5.0/go.mod h1:vGTfKdsh87RI7kA2JHFBEGxjQEYx+pi299wqEOdi34M= -go.etcd.io/etcd/etcdutl/v3 v3.5.0/go.mod h1:o98rKMCibbFAG8QS9KmvlYDGDShmmIbmRE8vSofzYNg= -go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= -go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30= -go.etcd.io/etcd/tests/v3 v3.5.0/go.mod h1:f+mtZ1bE1YPvgKdOJV2BKy4JQW0nAFnQehgOE7+WyJE= -go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To= -go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4= -go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -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.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= 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 v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.step.sm/cli-utils v0.7.6 h1:YkpLVrepmy2c5+eaz/wduiGxlgrRx3YdAStE37if25g= -go.step.sm/cli-utils v0.7.6/go.mod h1:j+FxFZ2gbWkAJl0eded/rksuxmNqWpmyxbkXcukGJaY= -go.step.sm/crypto v0.29.3 h1:lFCsFQQGic1VZIa0B/87iMCDy67+LW8eEl119GTyeWI= -go.step.sm/crypto v0.29.3/go.mod h1:0lYeIyQMJbFJ27L4BOGaq2gnuTgOShf+Ju/cTsMULq4= -go.step.sm/linkedca v0.19.0 h1:xuagkR35wrJI2gnu6FAM+q3VmjwsHScvGcJsfZ0GdsI= -go.step.sm/linkedca v0.19.0/go.mod h1:b7vWPrHfYLEOTSUZitFEcztVCpTc+ileIN85CwEAluM= +go.step.sm/cli-utils v0.8.0 h1:b/Tc1/m3YuQq+u3ghTFP7Dz5zUekZj6GUmd5pCvkEXQ= +go.step.sm/cli-utils v0.8.0/go.mod h1:S77aISrC0pKuflqiDfxxJlUbiXcAanyJ4POOnzFSxD4= +go.step.sm/crypto v0.35.1 h1:QAZZ7Q8xaM4TdungGSAYw/zxpyH4fMYTkfaXVV9H7pY= +go.step.sm/crypto v0.35.1/go.mod h1:vn8Vkx/Mbqgoe7AG8btC0qZ995Udm3e+JySuDS1LCJA= +go.step.sm/linkedca v0.20.1 h1:bHDn1+UG1NgRrERkWbbCiAIvv4lD5NOFaswPDTyO5vU= +go.step.sm/linkedca v0.20.1/go.mod h1:Vaq4+Umtjh7DLFI1KuIxeo598vfBzgSYZUjgVJ7Syxw= 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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= -golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -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-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-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 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/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw= golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20170726083632-f5079bd7f6f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1121,7 +670,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r 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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/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= @@ -1130,88 +678,34 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r 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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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-20200421231249-e086a090c8fd/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-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-20201202161906-c7110b5ffcbb/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-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-20190402181905-9f3314589c9a/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-20210126194326-f9ce19ea3013/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-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/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.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= 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-20190412183630-56d357773e84/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/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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20170728174421-0f826bdd13b5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -1223,77 +717,26 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190221075227-b4e8571b14e0/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-20190403152447-81d4e9dc473e/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-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/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-20200122134326-e047566fdf82/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-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-20200420163511-1957bb5e6d1f/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-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/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-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-20210309074719-68d13333faf2/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-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-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/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-20210603081109-ebe580a85c40/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-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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210629170331-7dc0b73dc9fb/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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1301,114 +744,48 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= 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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/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-20180828015842-6cd1fcedba52/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-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/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-20190621195816-6e04913cbbac/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-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/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-20191010075000-0337d82405ff/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/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-20191118222007-07fc4c7f2b98/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-20200103221440-774c71fcf114/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-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -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-20200522201501-cb1345f3a375/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-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -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-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -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.0.0-20210108195828-e2f9c7f1fc8e/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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1417,152 +794,39 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T 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= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= -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.10.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.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -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.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= -google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= -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.118.0 h1:FNfHq9Z2GKULxu7cEhCaB0wWQHg43UpomrrN+24ZRdE= -google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= +google.golang.org/api v0.142.0 h1:mf+7EJ94fi5ZcnpPy+m0Yv2dkz8bKm+UL0snTCuwXlY= +google.golang.org/api v0.142.0/go.mod h1:zJAN5o6HRqR7O+9qJUFOWrZkYE66RH+efPBdTLA4xBA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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.2/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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/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-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/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-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-20200423170343-7949de9c1215/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-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-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/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-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -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-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= +google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 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.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 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.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.32.0/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.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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= @@ -1571,65 +835,39 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.25.1-0.20200805231151-a709e31e5d12/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= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/cheggaaa/pb.v1 v1.0.28/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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.51.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.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 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 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.0-20210107192922-496545a6307b/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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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= -pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= -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/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/logging/handler_test.go b/logging/handler_test.go index 6cafc10c..8ab2a3c0 100644 --- a/logging/handler_test.go +++ b/logging/handler_test.go @@ -58,7 +58,7 @@ func TestHealthOKHandling(t *testing.T) { next: tt.handler, } - r := httptest.NewRequest("GET", tt.path, nil) + r := httptest.NewRequest("GET", tt.path, http.NoBody) w := httptest.NewRecorder() l.ServeHTTP(w, r) @@ -132,7 +132,7 @@ func TestHandlingRegardlessOfOptions(t *testing.T) { next: tt.handler, } - r := httptest.NewRequest("GET", tt.path, nil) + r := httptest.NewRequest("GET", tt.path, http.NoBody) w := httptest.NewRecorder() l.ServeHTTP(w, r) diff --git a/logging/logger.go b/logging/logger.go index 7ea25077..1716a7f4 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -3,6 +3,7 @@ package logging import ( "encoding/json" "net/http" + "os" "strings" "github.com/pkg/errors" @@ -38,6 +39,13 @@ func New(name string, raw json.RawMessage) (*Logger, error) { var formatter logrus.Formatter switch strings.ToLower(config.Format) { case "", "text": + _, noColor := os.LookupEnv("NO_COLOR") + // With EnvironmentOverrideColors set, logrus looks at CLICOLOR and + // CLICOLOR_FORCE + formatter = &logrus.TextFormatter{ + DisableColors: noColor, + EnvironmentOverrideColors: true, + } case "json": formatter = new(logrus.JSONFormatter) case "common": diff --git a/pki/helm.go b/pki/helm.go index d2ecdf37..3de2c2ec 100644 --- a/pki/helm.go +++ b/pki/helm.go @@ -117,10 +117,10 @@ inject: federateRoots: [] crt: {{ .Intermediate }} key: {{ .IntermediateKey }} - {{- if .Kms }} - kms: - type: {{ lower (.Kms.Type | toString) }} - {{- end }} + {{- if .Kms }} + kms: + type: {{ lower (.Kms.Type | toString) }} + {{- end }} {{- if .EnableSSH }} ssh: hostKey: {{ .Ssh.HostKey }} diff --git a/pki/helm_test.go b/pki/helm_test.go index 11c1d439..3aa0d224 100644 --- a/pki/helm_test.go +++ b/pki/helm_test.go @@ -210,7 +210,7 @@ func setKeyPair(t *testing.T, p *PKI) { } // setCertificates sets some static, gibberish intermediate and root CA certificate and key bytes. -func setCertificates(t *testing.T, p *PKI) { +func setCertificates(_ *testing.T, p *PKI) { raw := []byte("these are just some fake root CA cert bytes") p.Files[p.Root[0]] = encodeCertificate(&x509.Certificate{Raw: raw}) p.Files[p.RootKey[0]] = pem.EncodeToMemory(&pem.Block{ @@ -227,8 +227,7 @@ func setCertificates(t *testing.T, p *PKI) { } // setSSHSigningKeys sets some static, gibberish ssh user and host CA certificate and key bytes. -func setSSHSigningKeys(t *testing.T, p *PKI) { - +func setSSHSigningKeys(_ *testing.T, p *PKI) { if !p.options.enableSSH { return } diff --git a/pki/testdata/helm/with-ssh-and-acme.yml b/pki/testdata/helm/with-ssh-and-acme.yml index 639aca6a..7398c7e5 100644 --- a/pki/testdata/helm/with-ssh-and-acme.yml +++ b/pki/testdata/helm/with-ssh-and-acme.yml @@ -23,7 +23,7 @@ inject: authority: enableAdmin: false provisioners: - - {"type":"JWK","name":"step-cli","key":{"use":"sig","kty":"EC","kid":"zsUmysmDVoGJ71YoPHyZ-68tNihDaDaO5Mu7xX3M-_I","crv":"P-256","alg":"ES256","x":"Pqnua4CzqKz6ua41J3yeWZ1sRkGt0UlCkbHv8H2DGuY","y":"UhoZ_2ItDen9KQTcjay-ph-SBXH0mwqhHyvrrqIFDOI"},"encryptedKey":"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZjVvdGVRS2hvOXl4MmQtSGlMZi05QSJ9.eYA6tt3fNuUpoxKWDT7P0Lbn2juxhEbTxEnwEMbjlYLLQ3sxL-dYTA.ven-FhmdjlC9itH0.a2jRTarN9vPd6F_mWnNBlOn6KbfMjCApmci2t65XbAsLzYFzhI_79Ykm5ueMYTupWLTjBJctl-g51ZHmsSB55pStbpoyyLNAsUX2E1fTmHe-Ni8bRrspwLv15FoN1Xo1g0mpR-ufWIFxOsW-QIfnMmMIIkygVuHFXmg2tFpzTNNG5aS29K3dN2nyk0WJrdIq79hZSTqVkkBU25Yu3A46sgjcM86XcIJJ2XUEih_KWEa6T1YrkixGu96pebjVqbO0R6dbDckfPF7FqNnwPHVtb1ACFpEYoOJVIbUCMaARBpWsxYhjJZlEM__XA46l8snFQDkNY3CdN0p1_gF3ckA.JLmq9nmu1h9oUi1S8ZxYjA","claims":{"enableSSHCA":true,"disableRenewal":false,"allowRenewalAfterExpiry":false},"options":{"x509":{},"ssh":{}}} + - {"type":"JWK","name":"step-cli","key":{"use":"sig","kty":"EC","kid":"zsUmysmDVoGJ71YoPHyZ-68tNihDaDaO5Mu7xX3M-_I","crv":"P-256","alg":"ES256","x":"Pqnua4CzqKz6ua41J3yeWZ1sRkGt0UlCkbHv8H2DGuY","y":"UhoZ_2ItDen9KQTcjay-ph-SBXH0mwqhHyvrrqIFDOI"},"encryptedKey":"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZjVvdGVRS2hvOXl4MmQtSGlMZi05QSJ9.eYA6tt3fNuUpoxKWDT7P0Lbn2juxhEbTxEnwEMbjlYLLQ3sxL-dYTA.ven-FhmdjlC9itH0.a2jRTarN9vPd6F_mWnNBlOn6KbfMjCApmci2t65XbAsLzYFzhI_79Ykm5ueMYTupWLTjBJctl-g51ZHmsSB55pStbpoyyLNAsUX2E1fTmHe-Ni8bRrspwLv15FoN1Xo1g0mpR-ufWIFxOsW-QIfnMmMIIkygVuHFXmg2tFpzTNNG5aS29K3dN2nyk0WJrdIq79hZSTqVkkBU25Yu3A46sgjcM86XcIJJ2XUEih_KWEa6T1YrkixGu96pebjVqbO0R6dbDckfPF7FqNnwPHVtb1ACFpEYoOJVIbUCMaARBpWsxYhjJZlEM__XA46l8snFQDkNY3CdN0p1_gF3ckA.JLmq9nmu1h9oUi1S8ZxYjA","claims":{"enableSSHCA":true,"disableRenewal":false,"allowRenewalAfterExpiry":false,"disableSmallstepExtensions":false},"options":{"x509":{},"ssh":{}}} - {"type":"ACME","name":"acme"} - {"type":"SSHPOP","name":"sshpop","claims":{"enableSSHCA":true}} tls: diff --git a/pki/testdata/helm/with-ssh.yml b/pki/testdata/helm/with-ssh.yml index 2e4845f0..d5b38de7 100644 --- a/pki/testdata/helm/with-ssh.yml +++ b/pki/testdata/helm/with-ssh.yml @@ -23,7 +23,7 @@ inject: authority: enableAdmin: false provisioners: - - {"type":"JWK","name":"step-cli","key":{"use":"sig","kty":"EC","kid":"zsUmysmDVoGJ71YoPHyZ-68tNihDaDaO5Mu7xX3M-_I","crv":"P-256","alg":"ES256","x":"Pqnua4CzqKz6ua41J3yeWZ1sRkGt0UlCkbHv8H2DGuY","y":"UhoZ_2ItDen9KQTcjay-ph-SBXH0mwqhHyvrrqIFDOI"},"encryptedKey":"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZjVvdGVRS2hvOXl4MmQtSGlMZi05QSJ9.eYA6tt3fNuUpoxKWDT7P0Lbn2juxhEbTxEnwEMbjlYLLQ3sxL-dYTA.ven-FhmdjlC9itH0.a2jRTarN9vPd6F_mWnNBlOn6KbfMjCApmci2t65XbAsLzYFzhI_79Ykm5ueMYTupWLTjBJctl-g51ZHmsSB55pStbpoyyLNAsUX2E1fTmHe-Ni8bRrspwLv15FoN1Xo1g0mpR-ufWIFxOsW-QIfnMmMIIkygVuHFXmg2tFpzTNNG5aS29K3dN2nyk0WJrdIq79hZSTqVkkBU25Yu3A46sgjcM86XcIJJ2XUEih_KWEa6T1YrkixGu96pebjVqbO0R6dbDckfPF7FqNnwPHVtb1ACFpEYoOJVIbUCMaARBpWsxYhjJZlEM__XA46l8snFQDkNY3CdN0p1_gF3ckA.JLmq9nmu1h9oUi1S8ZxYjA","claims":{"enableSSHCA":true,"disableRenewal":false,"allowRenewalAfterExpiry":false},"options":{"x509":{},"ssh":{}}} + - {"type":"JWK","name":"step-cli","key":{"use":"sig","kty":"EC","kid":"zsUmysmDVoGJ71YoPHyZ-68tNihDaDaO5Mu7xX3M-_I","crv":"P-256","alg":"ES256","x":"Pqnua4CzqKz6ua41J3yeWZ1sRkGt0UlCkbHv8H2DGuY","y":"UhoZ_2ItDen9KQTcjay-ph-SBXH0mwqhHyvrrqIFDOI"},"encryptedKey":"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZjVvdGVRS2hvOXl4MmQtSGlMZi05QSJ9.eYA6tt3fNuUpoxKWDT7P0Lbn2juxhEbTxEnwEMbjlYLLQ3sxL-dYTA.ven-FhmdjlC9itH0.a2jRTarN9vPd6F_mWnNBlOn6KbfMjCApmci2t65XbAsLzYFzhI_79Ykm5ueMYTupWLTjBJctl-g51ZHmsSB55pStbpoyyLNAsUX2E1fTmHe-Ni8bRrspwLv15FoN1Xo1g0mpR-ufWIFxOsW-QIfnMmMIIkygVuHFXmg2tFpzTNNG5aS29K3dN2nyk0WJrdIq79hZSTqVkkBU25Yu3A46sgjcM86XcIJJ2XUEih_KWEa6T1YrkixGu96pebjVqbO0R6dbDckfPF7FqNnwPHVtb1ACFpEYoOJVIbUCMaARBpWsxYhjJZlEM__XA46l8snFQDkNY3CdN0p1_gF3ckA.JLmq9nmu1h9oUi1S8ZxYjA","claims":{"enableSSHCA":true,"disableRenewal":false,"allowRenewalAfterExpiry":false,"disableSmallstepExtensions":false},"options":{"x509":{},"ssh":{}}} - {"type":"SSHPOP","name":"sshpop","claims":{"enableSSHCA":true}} tls: cipherSuites: diff --git a/policy/engine.go b/policy/engine.go index c02fd7a9..56457325 100755 --- a/policy/engine.go +++ b/policy/engine.go @@ -244,30 +244,21 @@ func (e *NamePolicyEngine) IsX509CertificateRequestAllowed(csr *x509.Certificate return nil } -// AreSANSAllowed verifies that all names in the slice of SANs are allowed. +// AreSANsAllowed verifies that all names in the slice of SANs are allowed. // The SANs are first split into DNS names, IPs, email addresses and URIs. func (e *NamePolicyEngine) AreSANsAllowed(sans []string) error { dnsNames, ips, emails, uris := x509util.SplitSANs(sans) - if err := e.validateNames(dnsNames, ips, emails, uris, []string{}); err != nil { - return err - } - return nil + return e.validateNames(dnsNames, ips, emails, uris, []string{}) } // IsDNSAllowed verifies a single DNS domain is allowed. func (e *NamePolicyEngine) IsDNSAllowed(dns string) error { - if err := e.validateNames([]string{dns}, []net.IP{}, []string{}, []*url.URL{}, []string{}); err != nil { - return err - } - return nil + return e.validateNames([]string{dns}, []net.IP{}, []string{}, []*url.URL{}, []string{}) } // IsIPAllowed verifies a single IP domain is allowed. func (e *NamePolicyEngine) IsIPAllowed(ip net.IP) error { - if err := e.validateNames([]string{}, []net.IP{ip}, []string{}, []*url.URL{}, []string{}); err != nil { - return err - } - return nil + return e.validateNames([]string{}, []net.IP{ip}, []string{}, []*url.URL{}, []string{}) } // IsSSHCertificateAllowed verifies that all principals in an SSH certificate are allowed. @@ -276,10 +267,7 @@ func (e *NamePolicyEngine) IsSSHCertificateAllowed(cert *ssh.Certificate) error if err != nil { return err } - if err := e.validateNames(dnsNames, ips, emails, []*url.URL{}, principals); err != nil { - return err - } - return nil + return e.validateNames(dnsNames, ips, emails, []*url.URL{}, principals) } // splitPrincipals splits SSH certificate principals into DNS names, emails and usernames. diff --git a/scep/api/api.go b/scep/api/api.go index 346b9c75..614b5184 100644 --- a/scep/api/api.go +++ b/scep/api/api.go @@ -12,12 +12,13 @@ import ( "net/url" "strings" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" microscep "github.com/micromdm/scep/v2/scep" "go.mozilla.org/pkcs7" "github.com/smallstep/certificates/api" "github.com/smallstep/certificates/api/log" + "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/scep" ) @@ -208,7 +209,7 @@ func lookupProvisioner(next http.HandlerFunc) http.HandlerFunc { } ctx := r.Context() - auth := scep.MustFromContext(ctx) + auth := authority.MustFromContext(ctx) p, err := auth.LoadProvisionerByName(provisionerName) if err != nil { fail(w, err) @@ -221,7 +222,7 @@ func lookupProvisioner(next http.HandlerFunc) http.HandlerFunc { return } - ctx = context.WithValue(ctx, scep.ProvisionerContextKey, scep.Provisioner(prov)) + ctx = scep.NewProvisionerContext(ctx, scep.Provisioner(prov)) next(w, r.WithContext(ctx)) } } @@ -305,6 +306,8 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { // NOTE: at this point we have sufficient information for returning nicely signed CertReps csr := msg.CSRReqMessage.CSR + transactionID := string(msg.TransactionID) + challengePassword := msg.CSRReqMessage.ChallengePassword // NOTE: we're blocking the RenewalReq if the challenge does not match, because otherwise we don't have any authentication. // The macOS SCEP client performs renewals using PKCSreq. The CertNanny SCEP client will use PKCSreq with challenge too, it seems, @@ -312,13 +315,11 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { // a certificate exists; then it will use RenewalReq. Adding the challenge check here may be a small breaking change for clients. // We'll have to see how it works out. if msg.MessageType == microscep.PKCSReq || msg.MessageType == microscep.RenewalReq { - challengeMatches, err := auth.MatchChallengePassword(ctx, msg.CSRReqMessage.ChallengePassword) - if err != nil { - return createFailureResponse(ctx, csr, msg, microscep.BadRequest, errors.New("error when checking password")) - } - if !challengeMatches { - // TODO: can this be returned safely to the client? In the end, if the password was correct, that gains a bit of info too. - return createFailureResponse(ctx, csr, msg, microscep.BadRequest, errors.New("wrong password provided")) + if err := auth.ValidateChallenge(ctx, csr, challengePassword, transactionID); err != nil { + if errors.Is(err, provisioner.ErrSCEPChallengeInvalid) { + return createFailureResponse(ctx, csr, msg, microscep.BadRequest, err) + } + return createFailureResponse(ctx, csr, msg, microscep.BadRequest, errors.New("failed validating challenge password")) } } @@ -332,9 +333,18 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { certRep, err := auth.SignCSR(ctx, csr, msg) if err != nil { + if notifyErr := auth.NotifyFailure(ctx, csr, transactionID, 0, err.Error()); notifyErr != nil { + // TODO(hs): ignore this error case? It's not critical if the notification fails; but logging it might be good + _ = notifyErr + } return createFailureResponse(ctx, csr, msg, microscep.BadRequest, fmt.Errorf("error when signing new certificate: %w", err)) } + if notifyErr := auth.NotifySuccess(ctx, csr, certRep.Certificate, transactionID); notifyErr != nil { + // TODO(hs): ignore this error case? It's not critical if the notification fails; but logging it might be good + _ = notifyErr + } + res := Response{ Operation: opnPKIOperation, Data: certRep.Raw, diff --git a/scep/api/api_test.go b/scep/api/api_test.go index bdb51594..ef3e57ab 100644 --- a/scep/api/api_test.go +++ b/scep/api/api_test.go @@ -24,7 +24,7 @@ func Test_decodeRequest(t *testing.T) { { name: "fail/unsupported-method", args: args{ - r: httptest.NewRequest(http.MethodPatch, "http://scep:8080/?operation=AnUnsupportOperation", nil), + r: httptest.NewRequest(http.MethodPatch, "http://scep:8080/?operation=AnUnsupportOperation", http.NoBody), }, want: request{}, wantErr: true, @@ -32,7 +32,7 @@ func Test_decodeRequest(t *testing.T) { { name: "fail/get-unsupported-operation", args: args{ - r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=AnUnsupportOperation", nil), + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=AnUnsupportOperation", http.NoBody), }, want: request{}, wantErr: true, @@ -40,7 +40,7 @@ func Test_decodeRequest(t *testing.T) { { name: "fail/get-PKIOperation", args: args{ - r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=PKIOperation&message='somewronginput'", nil), + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=PKIOperation&message='somewronginput'", http.NoBody), }, want: request{}, wantErr: true, @@ -56,7 +56,7 @@ func Test_decodeRequest(t *testing.T) { { name: "ok/get-GetCACert", args: args{ - r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=GetCACert", nil), + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=GetCACert", http.NoBody), }, want: request{ Operation: "GetCACert", @@ -67,7 +67,7 @@ func Test_decodeRequest(t *testing.T) { { name: "ok/get-GetCACaps", args: args{ - r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=GetCACaps", nil), + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=GetCACaps", http.NoBody), }, want: request{ Operation: "GetCACaps", @@ -78,7 +78,7 @@ func Test_decodeRequest(t *testing.T) { { name: "ok/get-PKIOperation", args: args{ - r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=PKIOperation&message=MTIzNA==", nil), + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=PKIOperation&message=MTIzNA==", http.NoBody), }, want: request{ Operation: "PKIOperation", diff --git a/scep/authority.go b/scep/authority.go index 585b937e..292c7004 100644 --- a/scep/authority.go +++ b/scep/authority.go @@ -2,11 +2,11 @@ package scep import ( "context" - "crypto/subtle" + "crypto" "crypto/x509" "errors" "fmt" - "net/url" + "sync" microx509util "github.com/micromdm/scep/v2/cryptoutil/x509util" microscep "github.com/micromdm/scep/v2/scep" @@ -19,12 +19,17 @@ import ( // Authority is the layer that handles all SCEP interactions. type Authority struct { - prefix string - dns string - intermediateCertificate *x509.Certificate - caCerts []*x509.Certificate // TODO(hs): change to use these instead of root and intermediate - service *Service - signAuth SignAuthority + signAuth SignAuthority + roots []*x509.Certificate + intermediates []*x509.Certificate + defaultSigner crypto.Signer + signerCertificate *x509.Certificate + defaultDecrypter crypto.Decrypter + decrypterCertificate *x509.Certificate + scepProvisionerNames []string + + provisionersMutex sync.RWMutex + encryptionAlgorithmMutex sync.Mutex } type authorityKey struct{} @@ -50,19 +55,6 @@ func MustFromContext(ctx context.Context) *Authority { } } -// AuthorityOptions required to create a new SCEP Authority. -type AuthorityOptions struct { - // Service provides the certificate chain, the signer and the decrypter to the Authority - Service *Service - // DNS is the host used to generate accurate SCEP links. By default the authority - // will use the Host from the request, so this value will only be used if - // request.Host is empty. - DNS string - // Prefix is a URL path prefix under which the SCEP api is served. This - // prefix is required to generate accurate SCEP links. - Prefix string -} - // SignAuthority is the interface for a signing authority type SignAuthority interface { Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) @@ -70,24 +62,67 @@ type SignAuthority interface { } // New returns a new Authority that implements the SCEP interface. -func New(signAuth SignAuthority, ops AuthorityOptions) (*Authority, error) { - authority := &Authority{ - prefix: ops.Prefix, - dns: ops.DNS, - signAuth: signAuth, +func New(signAuth SignAuthority, opts Options) (*Authority, error) { + if err := opts.Validate(); err != nil { + return nil, err } - // TODO: this is not really nice to do; the Service should be removed - // in its entirety to make this more interoperable with the rest of - // step-ca, I think. - if ops.Service != nil { - authority.caCerts = ops.Service.certificateChain - // TODO(hs): look into refactoring SCEP into using just caCerts everywhere, if it makes sense for more elaborate SCEP configuration. Keeping it like this for clarity (for now). - authority.intermediateCertificate = ops.Service.certificateChain[0] - authority.service = ops.Service + return &Authority{ + signAuth: signAuth, // TODO: provide signAuth through context instead? + roots: opts.Roots, + intermediates: opts.Intermediates, + defaultSigner: opts.Signer, + signerCertificate: opts.SignerCert, + defaultDecrypter: opts.Decrypter, + decrypterCertificate: opts.SignerCert, // the intermediate signer cert is also the decrypter cert (if RSA) + scepProvisionerNames: opts.SCEPProvisionerNames, + }, nil +} + +// Validate validates if the SCEP Authority has a valid configuration. +// The validation includes a check if a decrypter is available, either +// an authority wide decrypter, or a provisioner specific decrypter. +func (a *Authority) Validate() error { + if a == nil { + return nil } - return authority, nil + a.provisionersMutex.RLock() + defer a.provisionersMutex.RUnlock() + + noDefaultDecrypterAvailable := a.defaultDecrypter == nil + for _, name := range a.scepProvisionerNames { + p, err := a.LoadProvisionerByName(name) + if err != nil { + return fmt.Errorf("failed loading provisioner %q: %w", name, err) + } + if scepProv, ok := p.(*provisioner.SCEP); ok { + cert, decrypter := scepProv.GetDecrypter() + // TODO(hs): return sentinel/typed error, to be able to ignore/log these cases during init? + if cert == nil && noDefaultDecrypterAvailable { + return fmt.Errorf("SCEP provisioner %q does not have a decrypter certificate", name) + } + if decrypter == nil && noDefaultDecrypterAvailable { + return fmt.Errorf("SCEP provisioner %q does not have decrypter", name) + } + } + } + + return nil +} + +// UpdateProvisioners updates the SCEP Authority with the new, and hopefully +// current SCEP provisioners configured. This allows the Authority to be +// validated with the latest data. +func (a *Authority) UpdateProvisioners(scepProvisionerNames []string) { + if a == nil { + return + } + + a.provisionersMutex.Lock() + defer a.provisionersMutex.Unlock() + + a.scepProvisionerNames = scepProvisionerNames } var ( @@ -109,74 +144,40 @@ func (a *Authority) LoadProvisionerByName(name string) (provisioner.Interface, e return a.signAuth.LoadProvisionerByName(name) } -// GetLinkExplicit returns the requested link from the directory. -func (a *Authority) GetLinkExplicit(provName string, abs bool, baseURL *url.URL, inputs ...string) string { - return a.getLinkExplicit(provName, abs, baseURL, inputs...) -} - -// getLinkExplicit returns an absolute or partial path to the given resource and a base -// URL dynamically obtained from the request for which the link is being calculated. -func (a *Authority) getLinkExplicit(provisionerName string, abs bool, baseURL *url.URL, inputs ...string) string { - link := "/" + provisionerName - if abs { - // Copy the baseURL value from the pointer. https://github.com/golang/go/issues/38351 - u := url.URL{} - if baseURL != nil { - u = *baseURL - } - - // If no Scheme is set, then default to http (in case of SCEP) - if u.Scheme == "" { - u.Scheme = "http" - } - - // If no Host is set, then use the default (first DNS attr in the ca.json). - if u.Host == "" { - u.Host = a.dns - } - - u.Path = a.prefix + link - return u.String() - } - - return link -} - -// GetCACertificates returns the certificate (chain) for the CA -func (a *Authority) GetCACertificates(ctx context.Context) ([]*x509.Certificate, error) { - // TODO: this should return: the "SCEP Server (RA)" certificate, the issuing CA up to and excl. the root - // Some clients do need the root certificate however; also see: https://github.com/openxpki/openxpki/issues/73 - // - // This means we might need to think about if we should use the current intermediate CA - // certificate as the "SCEP Server (RA)" certificate. It might be better to have a distinct - // RA certificate, with a corresponding rsa.PrivateKey, just for SCEP usage, which is signed by - // the intermediate CA. Will need to look how we can provide this nicely within step-ca. - // - // This might also mean that we might want to use a distinct instance of KMS for doing the key operations, - // so that we can use RSA just for SCEP. - // - // Using an RA does not seem to exist in https://tools.ietf.org/html/rfc8894, but is mentioned in - // https://tools.ietf.org/id/draft-nourse-scep-21.html. Will continue using the CA directly for now. - // - // The certificate to use should probably depend on the (configured) provisioner and may - // use a distinct certificate, apart from the intermediate. - - p, err := provisionerFromContext(ctx) - if err != nil { - return nil, err - } - - if len(a.caCerts) == 0 { - return nil, errors.New("no intermediate certificate available in SCEP authority") - } - - certs := []*x509.Certificate{} - certs = append(certs, a.caCerts[0]) - - // NOTE: we're adding the CA roots here, but they are (highly likely) different than what the RFC means. - // Clients are responsible to select the right cert(s) to use, though. - if p.ShouldIncludeRootInChain() && len(a.caCerts) > 1 { - certs = append(certs, a.caCerts[1]) +// GetCACertificates returns the certificate (chain) for the CA. +// +// This methods returns the "SCEP Server (RA)" certificate, the issuing CA up to and excl. the root. +// Some clients do need the root certificate however; also see: https://github.com/openxpki/openxpki/issues/73 +// +// In case a provisioner specific decrypter is available, this is used as the "SCEP Server (RA)" certificate +// instead of the CA intermediate directly. This uses a distinct instance of a KMS for doing the SCEP key +// operations, so that RSA can be used for just SCEP. +// +// Using an RA does not seem to exist in https://tools.ietf.org/html/rfc8894, but is mentioned in +// https://tools.ietf.org/id/draft-nourse-scep-21.html. +func (a *Authority) GetCACertificates(ctx context.Context) (certs []*x509.Certificate, err error) { + p := provisionerFromContext(ctx) + + // if a provisioner specific RSA decrypter is available, it is returned as + // the first certificate. + if decrypterCertificate, _ := p.GetDecrypter(); decrypterCertificate != nil { + certs = append(certs, decrypterCertificate) + } + + // the CA intermediate is added to the chain by default. It's possible to + // exclude it from being added through configuration. This can be useful in + // environments where the SCEP client doesn't select the right RSA decrypter + // certificate, resulting in the wrong recipient in the PKCS7 message. + if p.ShouldIncludeIntermediateInChain() || len(certs) == 0 { + // TODO(hs): ensure logic is in place that checks the signer is the first + // intermediate and that there are no double certificates. + certs = append(certs, a.intermediates...) + } + + // the CA roots are added for completeness when configured to do so. Clients + // are responsible to select the right cert(s) to store and use. + if p.ShouldIncludeRootInChain() { + certs = append(certs, a.roots...) } return certs, nil @@ -189,7 +190,12 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err return fmt.Errorf("error parsing pkcs7 content: %w", err) } - envelope, err := p7c.Decrypt(a.intermediateCertificate, a.service.decrypter) + cert, decrypter, err := a.selectDecrypter(ctx) + if err != nil { + return fmt.Errorf("failed selecting decrypter: %w", err) + } + + envelope, err := p7c.Decrypt(cert, decrypter) if err != nil { return fmt.Errorf("error decrypting encrypted pkcs7 content: %w", err) } @@ -209,7 +215,10 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err if err != nil { return fmt.Errorf("parse CSR from pkiEnvelope: %w", err) } - // check for challengePassword + if err := csr.CheckSignature(); err != nil { + return fmt.Errorf("invalid CSR signature; %w", err) + } + // extract the challenge password cp, err := microx509util.ParseChallengePassword(msg.pkiEnvelope) if err != nil { return fmt.Errorf("parse challenge password in pkiEnvelope: %w", err) @@ -235,10 +244,7 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m // poll for the status. It seems to be similar as what can happen in ACME, so might want to model // the implementation after the one in the ACME authority. Requires storage, etc. - p, err := provisionerFromContext(ctx) - if err != nil { - return nil, err - } + p := provisionerFromContext(ctx) // check if CSRReqMessage has already been decrypted if msg.CSRReqMessage.CSR == nil { @@ -308,20 +314,13 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m // and create a degenerate cert structure deg, err := microscep.DegenerateCertificates([]*x509.Certificate{cert}) if err != nil { - return nil, err + return nil, fmt.Errorf("failed generating degenerate certificate: %w", err) } - // apparently the pkcs7 library uses a global default setting for the content encryption - // algorithm to use when en- or decrypting data. We need to restore the current setting after - // the cryptographic operation, so that other usages of the library are not influenced by - // this call to Encrypt(). We are not required to use the same algorithm the SCEP client uses. - encryptionAlgorithmToRestore := pkcs7.ContentEncryptionAlgorithm - pkcs7.ContentEncryptionAlgorithm = p.GetContentEncryptionAlgorithm() - e7, err := pkcs7.Encrypt(deg, msg.P7.Certificates) + e7, err := a.encrypt(deg, msg.P7.Certificates, p.GetContentEncryptionAlgorithm()) if err != nil { - return nil, err + return nil, fmt.Errorf("failed encrypting degenerate certificate: %w", err) } - pkcs7.ContentEncryptionAlgorithm = encryptionAlgorithmToRestore // PKIMessageAttributes to be signed config := pkcs7.SignerInfoConfig{ @@ -359,10 +358,13 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m // as the first certificate in the array signedData.AddCertificate(cert) - authCert := a.intermediateCertificate + signerCert, signer, err := a.selectSigner(ctx) + if err != nil { + return nil, fmt.Errorf("failed selecting signer: %w", err) + } // sign the attributes - if err := signedData.AddSigner(authCert, a.service.signer, config); err != nil { + if err := signedData.AddSigner(signerCert, signer, config); err != nil { return nil, err } @@ -389,8 +391,30 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m return crepMsg, nil } +func (a *Authority) encrypt(content []byte, recipients []*x509.Certificate, algorithm int) ([]byte, error) { + // apparently the pkcs7 library uses a global default setting for the content encryption + // algorithm to use when en- or decrypting data. We need to restore the current setting after + // the cryptographic operation, so that other usages of the library are not influenced by + // this call to Encrypt(). We are not required to use the same algorithm the SCEP client uses. + a.encryptionAlgorithmMutex.Lock() + defer a.encryptionAlgorithmMutex.Unlock() + + encryptionAlgorithmToRestore := pkcs7.ContentEncryptionAlgorithm + defer func() { + pkcs7.ContentEncryptionAlgorithm = encryptionAlgorithmToRestore + }() + + pkcs7.ContentEncryptionAlgorithm = algorithm + e7, err := pkcs7.Encrypt(content, recipients) + if err != nil { + return nil, err + } + + return e7, nil +} + // CreateFailureResponse creates an appropriately signed reply for PKI operations -func (a *Authority) CreateFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage, info FailInfoName, infoText string) (*PKIMessage, error) { +func (a *Authority) CreateFailureResponse(ctx context.Context, _ *x509.CertificateRequest, msg *PKIMessage, info FailInfoName, infoText string) (*PKIMessage, error) { config := pkcs7.SignerInfoConfig{ ExtraSignedAttributes: []pkcs7.Attribute{ { @@ -429,8 +453,13 @@ func (a *Authority) CreateFailureResponse(ctx context.Context, csr *x509.Certifi return nil, err } + signerCert, signer, err := a.selectSigner(ctx) + if err != nil { + return nil, fmt.Errorf("failed selecting signer: %w", err) + } + // sign the attributes - if err := signedData.AddSigner(a.intermediateCertificate, a.service.signer, config); err != nil { + if err := signedData.AddSigner(signerCert, signer, config); err != nil { return nil, err } @@ -456,30 +485,9 @@ func (a *Authority) CreateFailureResponse(ctx context.Context, csr *x509.Certifi return crepMsg, nil } -// MatchChallengePassword verifies a SCEP challenge password -func (a *Authority) MatchChallengePassword(ctx context.Context, password string) (bool, error) { - p, err := provisionerFromContext(ctx) - if err != nil { - return false, err - } - - if subtle.ConstantTimeCompare([]byte(p.GetChallengePassword()), []byte(password)) == 1 { - return true, nil - } - - // TODO: support dynamic challenges, i.e. a list of challenges instead of one? - // That's probably a bit harder to configure, though; likely requires some data store - // that can be interacted with more easily, via some internal API, for example. - - return false, nil -} - // GetCACaps returns the CA capabilities func (a *Authority) GetCACaps(ctx context.Context) []string { - p, err := provisionerFromContext(ctx) - if err != nil { - return defaultCapabilities - } + p := provisionerFromContext(ctx) caps := p.GetCapabilities() if len(caps) == 0 { @@ -494,3 +502,64 @@ func (a *Authority) GetCACaps(ctx context.Context) []string { return caps } + +func (a *Authority) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error { + p := provisionerFromContext(ctx) + return p.ValidateChallenge(ctx, csr, challenge, transactionID) +} + +func (a *Authority) NotifySuccess(ctx context.Context, csr *x509.CertificateRequest, cert *x509.Certificate, transactionID string) error { + p := provisionerFromContext(ctx) + return p.NotifySuccess(ctx, csr, cert, transactionID) +} + +func (a *Authority) NotifyFailure(ctx context.Context, csr *x509.CertificateRequest, transactionID string, errorCode int, errorDescription string) error { + p := provisionerFromContext(ctx) + return p.NotifyFailure(ctx, csr, transactionID, errorCode, errorDescription) +} + +func (a *Authority) selectDecrypter(ctx context.Context) (cert *x509.Certificate, decrypter crypto.Decrypter, err error) { + p := provisionerFromContext(ctx) + cert, decrypter = p.GetDecrypter() + switch { + case cert != nil && decrypter != nil: + return + case cert == nil && decrypter != nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a decrypter certificate available", p.GetName()) + case cert != nil && decrypter == nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a decrypter available", p.GetName()) + } + + cert, decrypter = a.decrypterCertificate, a.defaultDecrypter + switch { + case cert == nil && decrypter != nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a default decrypter certificate available", p.GetName()) + case cert != nil && decrypter == nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a default decrypter available", p.GetName()) + } + + return +} + +func (a *Authority) selectSigner(ctx context.Context) (cert *x509.Certificate, signer crypto.Signer, err error) { + p := provisionerFromContext(ctx) + cert, signer = p.GetSigner() + switch { + case cert != nil && signer != nil: + return + case cert == nil && signer != nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a signer certificate available", p.GetName()) + case cert != nil && signer == nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a signer available", p.GetName()) + } + + cert, signer = a.signerCertificate, a.defaultSigner + switch { + case cert == nil && signer != nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a default signer certificate available", p.GetName()) + case cert != nil && signer == nil: + return nil, nil, fmt.Errorf("provisioner %q does not have a default signer available", p.GetName()) + } + + return +} diff --git a/scep/authority_test.go b/scep/authority_test.go new file mode 100644 index 00000000..0aa81b49 --- /dev/null +++ b/scep/authority_test.go @@ -0,0 +1,73 @@ +package scep + +import ( + "crypto/x509" + "crypto/x509/pkix" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.mozilla.org/pkcs7" + "go.step.sm/crypto/keyutil" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/randutil" +) + +func generateContent(t *testing.T, size int) []byte { + t.Helper() + b, err := randutil.Bytes(size) + require.NoError(t, err) + return b +} + +func generateRecipients(t *testing.T) []*x509.Certificate { + ca, err := minica.New() + require.NoError(t, err) + s, err := keyutil.GenerateSigner("RSA", "", 2048) + require.NoError(t, err) + tmpl := &x509.Certificate{ + PublicKey: s.Public(), + Subject: pkix.Name{CommonName: "Test PKCS#7 Encryption"}, + } + cert, err := ca.Sign(tmpl) + require.NoError(t, err) + return []*x509.Certificate{cert} +} + +func TestAuthority_encrypt(t *testing.T) { + t.Parallel() + a := &Authority{} + recipients := generateRecipients(t) + type args struct { + content []byte + recipients []*x509.Certificate + algorithm int + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"alg-0", args{generateContent(t, 32), recipients, pkcs7.EncryptionAlgorithmDESCBC}, false}, + {"alg-1", args{generateContent(t, 32), recipients, pkcs7.EncryptionAlgorithmAES128CBC}, false}, + {"alg-2", args{generateContent(t, 32), recipients, pkcs7.EncryptionAlgorithmAES256CBC}, false}, + {"alg-3", args{generateContent(t, 32), recipients, pkcs7.EncryptionAlgorithmAES128GCM}, false}, + {"alg-4", args{generateContent(t, 32), recipients, pkcs7.EncryptionAlgorithmAES256GCM}, false}, + {"alg-unknown", args{generateContent(t, 32), recipients, 42}, true}, + } + for _, tt := range tests { + tc := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := a.encrypt(tc.args.content, tc.args.recipients, tc.args.algorithm) + if tc.wantErr { + assert.Error(t, err) + assert.Nil(t, got) + return + } + + assert.NoError(t, err) + assert.NotEmpty(t, got) + }) + } +} diff --git a/scep/common.go b/scep/common.go deleted file mode 100644 index 73b16ed4..00000000 --- a/scep/common.go +++ /dev/null @@ -1,29 +0,0 @@ -package scep - -import ( - "context" - "errors" -) - -// ContextKey is the key type for storing and searching for SCEP request -// essentials in the context of a request. -type ContextKey string - -const ( - // ProvisionerContextKey provisioner key - ProvisionerContextKey = ContextKey("provisioner") -) - -// provisionerFromContext searches the context for a SCEP provisioner. -// Returns the provisioner or an error. -func provisionerFromContext(ctx context.Context) (Provisioner, error) { - val := ctx.Value(ProvisionerContextKey) - if val == nil { - return nil, errors.New("provisioner expected in request context") - } - p, ok := val.(Provisioner) - if !ok || p == nil { - return nil, errors.New("provisioner in context is not a SCEP provisioner") - } - return p, nil -} diff --git a/scep/database.go b/scep/database.go deleted file mode 100644 index f73573fd..00000000 --- a/scep/database.go +++ /dev/null @@ -1,7 +0,0 @@ -package scep - -import "crypto/x509" - -type DB interface { - StoreCertificate(crt *x509.Certificate) error -} diff --git a/scep/options.go b/scep/options.go index 201f1beb..8bc30a61 100644 --- a/scep/options.go +++ b/scep/options.go @@ -4,65 +4,78 @@ import ( "crypto" "crypto/rsa" "crypto/x509" - - "github.com/pkg/errors" + "errors" ) type Options struct { - // CertificateChain is the issuer certificate, along with any other bundled certificates - // to be returned in the chain for consumers. Configured in the ca.json crt property. - CertificateChain []*x509.Certificate + // Roots contains the (federated) CA roots certificate(s) + Roots []*x509.Certificate `json:"-"` + // Intermediates points issuer certificate, along with any other bundled certificates + // to be returned in the chain for consumers. + Intermediates []*x509.Certificate `json:"-"` + // SignerCert points to the certificate of the CA signer. It usually is the same as the + // first certificate in the CertificateChain. + SignerCert *x509.Certificate `json:"-"` // Signer signs CSRs in SCEP. Configured in the ca.json key property. Signer crypto.Signer `json:"-"` // Decrypter decrypts encrypted SCEP messages. Configured in the ca.json key property. Decrypter crypto.Decrypter `json:"-"` + // DecrypterCert points to the certificate of the CA decrypter. + DecrypterCert *x509.Certificate `json:"-"` + // SCEPProvisionerNames contains the currently configured SCEP provioner names. These + // are used to be able to load the provisioners when the SCEP authority is being + // validated. + SCEPProvisionerNames []string +} + +type comparablePublicKey interface { + Equal(crypto.PublicKey) bool } // Validate checks the fields in Options. func (o *Options) Validate() error { - if o.CertificateChain == nil { - return errors.New("certificate chain not configured correctly") + switch { + case len(o.Intermediates) == 0: + return errors.New("no intermediate certificate available for SCEP authority") + case o.Signer == nil: + return errors.New("no signer available for SCEP authority") + case o.SignerCert == nil: + return errors.New("no signer certificate available for SCEP authority") } - if len(o.CertificateChain) < 1 { - return errors.New("certificate chain should at least have one certificate") + // check if the signer (intermediate CA) certificate has the same public key as + // the signer. According to the RFC it seems valid to have different keys for + // the intermediate and the CA signing new certificates, so this might change + // in the future. + signerPublicKey := o.Signer.Public().(comparablePublicKey) + if !signerPublicKey.Equal(o.SignerCert.PublicKey) { + return errors.New("mismatch between signer certificate and public key") } - // According to the RFC: https://tools.ietf.org/html/rfc8894#section-3.1, SCEP - // can be used with something different than RSA, but requires the encryption - // to be performed using the challenge password. An older version of specification - // states that only RSA is supported: https://tools.ietf.org/html/draft-nourse-scep-23#section-2.1.1 - // Other algorithms than RSA do not seem to be supported in certnanny/sscep, but it might work - // in micromdm/scep. Currently only RSA is allowed, but it might be an option - // to try other algorithms in the future. - intermediate := o.CertificateChain[0] - if intermediate.PublicKeyAlgorithm != x509.RSA { - return errors.New("only the RSA algorithm is (currently) supported") - } - - // TODO: add checks for key usage? - - signerPublicKey, ok := o.Signer.Public().(*rsa.PublicKey) - if !ok { - return errors.New("only RSA public keys are (currently) supported as signers") - } - - // check if the intermediate ca certificate has the same public key as the signer. - // According to the RFC it seems valid to have different keys for the intermediate - // and the CA signing new certificates, so this might change in the future. - if !signerPublicKey.Equal(intermediate.PublicKey) { - return errors.New("mismatch between certificate chain and signer public keys") + // decrypter can be nil in case a signing only key is used; validation complete. + if o.Decrypter == nil { + return nil } + // If a decrypter is available, check that it's backed by an RSA key. According to the + // RFC: https://tools.ietf.org/html/rfc8894#section-3.1, SCEP can be used with something + // different than RSA, but requires the encryption to be performed using the challenge + // password in that case. An older version of specification states that only RSA is + // supported: https://tools.ietf.org/html/draft-nourse-scep-23#section-2.1.1. Other + // algorithms do not seem to be supported in certnanny/sscep, but it might work + // in micromdm/scep. Currently only RSA is allowed, but it might be an option + // to try other algorithms in the future. decrypterPublicKey, ok := o.Decrypter.Public().(*rsa.PublicKey) if !ok { - return errors.New("only RSA public keys are (currently) supported as decrypters") + return errors.New("only RSA keys are (currently) supported as decrypters") } // check if intermediate public key is the same as the decrypter public key. // In certnanny/sscep it's mentioned that the signing key can be different - // from the decrypting (and encrypting) key. Currently that's not supported. - if !decrypterPublicKey.Equal(intermediate.PublicKey) { + // from the decrypting (and encrypting) key. These options are only used and + // validated when the intermediate CA is also used as the decrypter, though, + // so they should match. + if !decrypterPublicKey.Equal(o.SignerCert.PublicKey) { return errors.New("mismatch between certificate chain and decrypter public keys") } diff --git a/scep/provisioner.go b/scep/provisioner.go index 679c6353..3df4b367 100644 --- a/scep/provisioner.go +++ b/scep/provisioner.go @@ -2,20 +2,43 @@ package scep import ( "context" - "time" + "crypto" + "crypto/x509" "github.com/smallstep/certificates/authority/provisioner" ) -// Provisioner is an interface that implements a subset of the provisioner.Interface -- -// only those methods required by the SCEP api/authority. +// Provisioner is an interface that embeds the +// provisioner.Interface and adds some SCEP specific +// functions. type Provisioner interface { - AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error) - GetName() string - DefaultTLSCertDuration() time.Duration + provisioner.Interface GetOptions() *provisioner.Options - GetChallengePassword() string GetCapabilities() []string ShouldIncludeRootInChain() bool + ShouldIncludeIntermediateInChain() bool + GetDecrypter() (*x509.Certificate, crypto.Decrypter) + GetSigner() (*x509.Certificate, crypto.Signer) GetContentEncryptionAlgorithm() int + ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error + NotifySuccess(ctx context.Context, csr *x509.CertificateRequest, cert *x509.Certificate, transactionID string) error + NotifyFailure(ctx context.Context, csr *x509.CertificateRequest, transactionID string, errorCode int, errorDescription string) error +} + +// provisionerKey is the key type for storing and searching a +// SCEP provisioner in the context. +type provisionerKey struct{} + +// provisionerFromContext searches the context for a SCEP provisioner. +// Returns the provisioner or panics if no SCEP provisioner is found. +func provisionerFromContext(ctx context.Context) Provisioner { + p, ok := ctx.Value(provisionerKey{}).(Provisioner) + if !ok { + panic("SCEP provisioner expected in request context") + } + return p +} + +func NewProvisionerContext(ctx context.Context, p Provisioner) context.Context { + return context.WithValue(ctx, provisionerKey{}, p) } diff --git a/scep/service.go b/scep/service.go deleted file mode 100644 index a4efe27e..00000000 --- a/scep/service.go +++ /dev/null @@ -1,27 +0,0 @@ -package scep - -import ( - "context" - "crypto" - "crypto/x509" -) - -// Service is a wrapper for crypto.Signer and crypto.Decrypter -type Service struct { - certificateChain []*x509.Certificate - signer crypto.Signer - decrypter crypto.Decrypter -} - -func NewService(ctx context.Context, opts Options) (*Service, error) { - if err := opts.Validate(); err != nil { - return nil, err - } - - // TODO: should this become similar to the New CertificateAuthorityService as in x509CAService? - return &Service{ - certificateChain: opts.CertificateChain, - signer: opts.Signer, - decrypter: opts.Decrypter, - }, nil -} diff --git a/scripts/README.md b/scripts/README.md index 80d3cdba..5571bf86 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -2,3 +2,7 @@ Please note that `install-step-ra.sh` is referenced on the `files.smallstep.com` S3 website bucket as a redirect to `raw.githubusercontent.com`. If you move it, please update the S3 redirect. +## badger-migration + +badger-migration is a tool that allows migrating data data from BadgerDB (v1 or +v2) to MySQL or PostgreSQL. diff --git a/scripts/badger-migration/main.go b/scripts/badger-migration/main.go new file mode 100644 index 00000000..3ae37abe --- /dev/null +++ b/scripts/badger-migration/main.go @@ -0,0 +1,354 @@ +package main + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "errors" + "flag" + "fmt" + "os" + "path/filepath" + + badgerv1 "github.com/dgraph-io/badger" + badgerv2 "github.com/dgraph-io/badger/v2" + + "github.com/smallstep/nosql" +) + +var ( + authorityTables = []string{ + "x509_certs", + "x509_certs_data", + "revoked_x509_certs", + "x509_crl", + "revoked_ssh_certs", + "used_ott", + "ssh_certs", + "ssh_hosts", + "ssh_users", + "ssh_host_principals", + } + acmeTables = []string{ + "acme_accounts", + "acme_keyID_accountID_index", + "acme_authzs", + "acme_challenges", + "nonces", + "acme_orders", + "acme_account_orders_index", + "acme_certs", + "acme_serial_certs_index", + "acme_external_account_keys", + "acme_external_account_keyID_reference_index", + "acme_external_account_keyID_provisionerID_index", + } + adminTables = []string{ + "admins", + "provisioners", + "authority_policies", + } +) + +type DB interface { + CreateTable([]byte) error + Set(bucket, key, value []byte) error +} + +type dryRunDB struct{} + +func (*dryRunDB) CreateTable([]byte) error { return nil } + +//nolint:revive // allow unused parameters to show function signature +func (*dryRunDB) Set(bucket, key, value []byte) error { return nil } + +func usage(fs *flag.FlagSet) { + name := filepath.Base(os.Args[0]) + fmt.Fprintf(os.Stderr, "%s is a tool to migrate data from BadgerDB to MySQL or PostgreSQL.\n", name) + fmt.Fprintln(os.Stderr, "\nUsage:") + fmt.Fprintf(os.Stderr, " %s [-v1|-v2] -dir= [-value-dir=] -type=type -database=\n", name) + fmt.Fprintln(os.Stderr, "\nExamples:") + fmt.Fprintf(os.Stderr, " %s -v1 -dir /var/lib/step-ca/db -type=mysql -database \"user@unix/step_ca\"\n", name) + fmt.Fprintf(os.Stderr, " %s -v1 -dir /var/lib/step-ca/db -type=mysql -database \"user:password@tcp(localhost:3306)/step_ca\"\n", name) + fmt.Fprintf(os.Stderr, " %s -v2 -dir /var/lib/step-ca/db -type=postgresql -database \"user=postgres dbname=step_ca\"\n", name) + fmt.Fprintf(os.Stderr, " %s -v2 -dir /var/lib/step-ca/db -dry-run\"\n", name) + fmt.Fprintln(os.Stderr, "\nOptions:") + fs.PrintDefaults() +} + +func main() { + var v1, v2, dryRun bool + var dir, valueDir string + var typ, database string + var key string + + fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + fs.BoolVar(&v1, "v1", false, "use badger v1 as the source database") + fs.BoolVar(&v2, "v2", false, "use badger v2 as the source database") + fs.StringVar(&dir, "dir", "", "badger database directory") + fs.StringVar(&valueDir, "value-dir", "", "badger database value directory") + fs.StringVar(&typ, "type", "", "the destination database type to use") + fs.StringVar(&database, "database", "", "the destination driver-specific data source name") + fs.StringVar(&key, "key", "", "the key used to resume the migration") + fs.BoolVar(&dryRun, "dry-run", false, "runs the migration scripts without writing anything") + fs.Usage = func() { usage(fs) } + fs.Parse(os.Args[1:]) + + switch { + case v1 == v2: + fatal("flag -v1 or -v2 are required") + case dir == "": + fatal("flag -dir is required") + case typ != "postgresql" && typ != "mysql" && !dryRun: + fatal(`flag -type must be "postgresql" or "mysql"`) + case database == "" && !dryRun: + fatal("flag --database required") + } + + var ( + err error + v1DB *badgerv1.DB + v2DB *badgerv2.DB + lastKey []byte + ) + + if key != "" { + if lastKey, err = base64.StdEncoding.DecodeString(key); err != nil { + fatal("error decoding key: %v", err) + } + } + + if v1 { + if v1DB, err = badgerV1Open(dir, valueDir); err != nil { + fatal("error opening badger v1 database: %v", err) + } + } else { + if v2DB, err = badgerV2Open(dir, valueDir); err != nil { + fatal("error opening badger v2 database: %v", err) + } + } + + var db DB + if dryRun { + db = &dryRunDB{} + } else { + db, err = nosql.New(typ, database) + if err != nil { + fatal("error opening %s database: %v", typ, err) + } + } + + allTables := append([]string{}, authorityTables...) + allTables = append(allTables, acmeTables...) + allTables = append(allTables, adminTables...) + + // Convert prefix names to badger key prefixes + badgerKeys := make([][]byte, len(allTables)) + for i, name := range allTables { + badgerKeys[i], err = badgerEncode([]byte(name)) + if err != nil { + fatal("error encoding table %s: %v", name, err) + } + } + + for i, prefix := range badgerKeys { + table := allTables[i] + + // With a key flag, resume from that table and prefix + if lastKey != nil { + bucket, _ := parseBadgerEncode(lastKey) + if table != string(bucket) { + fmt.Printf("skipping table %s\n", table) + continue + } + // Continue with a new prefix + prefix = lastKey + lastKey = nil + } + + var n int64 + fmt.Printf("migrating %s ...", table) + if err := db.CreateTable([]byte(table)); err != nil { + fatal("error creating table %s: %v", table, err) + } + + if v1 { + if badgerKey, err := badgerV1Iterate(v1DB, prefix, func(bucket, key, value []byte) error { + n++ + return db.Set(bucket, key, value) + }); err != nil { + fmt.Println() + fatal("error inserting into %s: %v\nLast key: %s", table, err, base64.StdEncoding.EncodeToString(badgerKey)) + } + } else { + if badgerKey, err := badgerV2Iterate(v2DB, prefix, func(bucket, key, value []byte) error { + n++ + return db.Set(bucket, key, value) + }); err != nil { + fmt.Println() + fatal("error inserting into %s: %v\nLast key: %s", table, err, base64.StdEncoding.EncodeToString(badgerKey)) + } + } + + fmt.Printf(" %d rows\n", n) + } +} + +func fatal(format string, args ...any) { + fmt.Fprintf(os.Stderr, format, args...) + fmt.Fprintln(os.Stderr) + os.Exit(1) +} + +func badgerV1Open(dir, valueDir string) (*badgerv1.DB, error) { + opts := badgerv1.DefaultOptions(dir) + if valueDir != "" { + opts.ValueDir = valueDir + } + return badgerv1.Open(opts) +} + +func badgerV2Open(dir, valueDir string) (*badgerv2.DB, error) { + opts := badgerv2.DefaultOptions(dir) + if valueDir != "" { + opts.ValueDir = valueDir + } + return badgerv2.Open(opts) +} + +type Iterator interface { + Seek([]byte) + ValidForPrefix([]byte) bool + Next() +} + +type Item interface { + KeyCopy([]byte) []byte + ValueCopy([]byte) ([]byte, error) +} + +func badgerV1Iterate(db *badgerv1.DB, prefix []byte, fn func(bucket, key, value []byte) error) (badgerKey []byte, err error) { + err = db.View(func(txn *badgerv1.Txn) error { + it := txn.NewIterator(badgerv1.DefaultIteratorOptions) + defer it.Close() + badgerKey, err = badgerIterate(it, prefix, fn) + return err + }) + return +} + +func badgerV2Iterate(db *badgerv2.DB, prefix []byte, fn func(bucket, key, value []byte) error) (badgerKey []byte, err error) { + err = db.View(func(txn *badgerv2.Txn) error { + it := txn.NewIterator(badgerv2.DefaultIteratorOptions) + defer it.Close() + badgerKey, err = badgerIterate(it, prefix, fn) + return err + }) + return +} + +func badgerIterate(it Iterator, prefix []byte, fn func(bucket, key, value []byte) error) ([]byte, error) { + var badgerKey []byte + for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() { + var item Item + switch itt := it.(type) { + case *badgerv1.Iterator: + item = itt.Item() + case *badgerv2.Iterator: + item = itt.Item() + default: + return badgerKey, fmt.Errorf("unexpected iterator type %T", it) + } + + badgerKey = item.KeyCopy(nil) + if isBadgerTable(badgerKey) { + continue + } + + bucket, key, err := fromBadgerKey(badgerKey) + if err != nil { + return badgerKey, fmt.Errorf("error converting from badger key %s", badgerKey) + } + value, err := item.ValueCopy(nil) + if err != nil { + return badgerKey, fmt.Errorf("error retrieving contents from database value: %w", err) + } + + if err := fn(bucket, key, value); err != nil { + return badgerKey, fmt.Errorf("error exporting %s[%s]=%x", bucket, key, value) + } + } + + return badgerKey, nil +} + +// badgerEncode encodes a byte slice into a section of a BadgerKey. See +// documentation for toBadgerKey. +func badgerEncode(val []byte) ([]byte, error) { + l := len(val) + switch { + case l == 0: + return nil, errors.New("input cannot be empty") + case l > 65535: + return nil, errors.New("length of input cannot be greater than 65535") + default: + lb := new(bytes.Buffer) + if err := binary.Write(lb, binary.LittleEndian, uint16(l)); err != nil { + return nil, fmt.Errorf("error doing binary Write: %w", err) + } + return append(lb.Bytes(), val...), nil + } +} + +// parseBadgerEncode decodes the badger key and returns the bucket and the rest. +func parseBadgerEncode(bk []byte) (value, rest []byte) { + var ( + keyLen uint16 + start = uint16(2) + length = uint16(len(bk)) + ) + if uint16(len(bk)) < start { + return nil, bk + } + // First 2 bytes stores the length of the value. + if err := binary.Read(bytes.NewReader(bk[:2]), binary.LittleEndian, &keyLen); err != nil { + return nil, bk + } + end := start + keyLen + switch { + case length < end: + return nil, bk + case length == end: + return bk[start:end], nil + default: + return bk[start:end], bk[end:] + } +} + +// isBadgerTable returns True if the slice is a badgerTable token, false +// otherwise. badgerTable means that the slice contains only the [size|value] of +// one section of a badgerKey and no remainder. A badgerKey is [bucket|key], +// while a badgerTable is only the bucket section. +func isBadgerTable(bk []byte) bool { + if k, rest := parseBadgerEncode(bk); len(k) > 0 && len(rest) == 0 { + return true + } + return false +} + +// fromBadgerKey returns the bucket and key encoded in a BadgerKey. See +// documentation for toBadgerKey. +func fromBadgerKey(bk []byte) ([]byte, []byte, error) { + bucket, rest := parseBadgerEncode(bk) + if len(bucket) == 0 || len(rest) == 0 { + return nil, nil, fmt.Errorf("invalid badger key: %v", bk) + } + + key, rest2 := parseBadgerEncode(rest) + if len(key) == 0 || len(rest2) != 0 { + return nil, nil, fmt.Errorf("invalid badger key: %v", bk) + } + + return bucket, key, nil +} diff --git a/webhook/options.go b/webhook/options.go index 88c44986..86923709 100644 --- a/webhook/options.go +++ b/webhook/options.go @@ -68,6 +68,13 @@ func WithAttestationData(data *AttestationData) RequestBodyOption { } } +func WithAuthorizationPrincipal(p string) RequestBodyOption { + return func(rb *RequestBody) error { + rb.AuthorizationPrincipal = p + return nil + } +} + func WithSSHCertificateRequest(cr sshutil.CertificateRequest) RequestBodyOption { return func(rb *RequestBody) error { rb.SSHCertificateRequest = &SSHCertificateRequest{ @@ -95,3 +102,23 @@ func WithSSHCertificate(cert *sshutil.Certificate, certTpl *ssh.Certificate) Req return nil } } + +func WithX5CCertificate(leaf *x509.Certificate) RequestBodyOption { + return func(rb *RequestBody) error { + rb.X5CCertificate = &X5CCertificate{ + Raw: leaf.Raw, + PublicKeyAlgorithm: leaf.PublicKeyAlgorithm.String(), + NotBefore: leaf.NotBefore, + NotAfter: leaf.NotAfter, + } + if leaf.PublicKey != nil { + key, err := x509.MarshalPKIXPublicKey(leaf.PublicKey) + if err != nil { + return err + } + rb.X5CCertificate.PublicKey = key + } + + return nil + } +} diff --git a/webhook/options_test.go b/webhook/options_test.go index e813bb44..9bcc59bc 100644 --- a/webhook/options_test.go +++ b/webhook/options_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/smallstep/assert" + "go.step.sm/crypto/keyutil" "go.step.sm/crypto/sshutil" "go.step.sm/crypto/x509util" "golang.org/x/crypto/ssh" @@ -16,6 +17,15 @@ func TestNewRequestBody(t *testing.T) { t1 := time.Now() t2 := t1.Add(time.Hour) + key, err := keyutil.GenerateDefaultSigner() + if err != nil { + t.Fatal(err) + } + keyBytes, err := x509.MarshalPKIXPublicKey(key.Public()) + if err != nil { + t.Fatal(err) + } + type test struct { options []RequestBodyOption want *RequestBody @@ -103,6 +113,40 @@ func TestNewRequestBody(t *testing.T) { }, wantErr: false, }, + "X5C Certificate": { + options: []RequestBodyOption{ + WithX5CCertificate(&x509.Certificate{ + Raw: []byte("some raw data"), + NotBefore: t1, + NotAfter: t2, + PublicKeyAlgorithm: x509.ECDSA, + PublicKey: key.Public(), + }), + }, + want: &RequestBody{ + X5CCertificate: &X5CCertificate{ + Raw: []byte("some raw data"), + PublicKeyAlgorithm: "ECDSA", + NotBefore: t1, + NotAfter: t2, + PublicKey: keyBytes, + }, + }, + wantErr: false, + }, + "fail/X5C Certificate": { + options: []RequestBodyOption{ + WithX5CCertificate(&x509.Certificate{ + Raw: []byte("some raw data"), + NotBefore: t1, + NotAfter: t2, + PublicKeyAlgorithm: x509.ECDSA, + PublicKey: []byte("fail"), + }), + }, + want: nil, + wantErr: true, + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { diff --git a/webhook/types.go b/webhook/types.go index 19624f5c..2d7832b8 100644 --- a/webhook/types.go +++ b/webhook/types.go @@ -30,6 +30,7 @@ type X509Certificate struct { PublicKeyAlgorithm string `json:"publicKeyAlgorithm"` NotBefore time.Time `json:"notBefore"` NotAfter time.Time `json:"notAfter"` + Raw []byte `json:"raw"` } // SSHCertificateRequest is the certificate request sent to webhook servers for @@ -56,6 +57,17 @@ type AttestationData struct { PermanentIdentifier string `json:"permanentIdentifier"` } +// X5CCertificate is the authorization certificate sent to webhook servers for +// enriching or authorizing webhooks when signing X509 or SSH certificates using +// the X5C provisioner. +type X5CCertificate struct { + Raw []byte `json:"raw"` + PublicKey []byte `json:"publicKey"` + PublicKeyAlgorithm string `json:"publicKeyAlgorithm"` + NotBefore time.Time `json:"notBefore"` + NotAfter time.Time `json:"notAfter"` +} + // RequestBody is the body sent to webhook servers. type RequestBody struct { Timestamp time.Time `json:"timestamp"` @@ -68,4 +80,13 @@ type RequestBody struct { X509Certificate *X509Certificate `json:"x509Certificate,omitempty"` SSHCertificateRequest *SSHCertificateRequest `json:"sshCertificateRequest,omitempty"` SSHCertificate *SSHCertificate `json:"sshCertificate,omitempty"` + // Only set for SCEP webhook requests + SCEPChallenge string `json:"scepChallenge,omitempty"` + SCEPTransactionID string `json:"scepTransactionID,omitempty"` + SCEPErrorCode int `json:"scepErrorCode,omitempty"` + SCEPErrorDescription string `json:"scepErrorDescription,omitempty"` + // Only set for X5C provisioners + X5CCertificate *X5CCertificate `json:"x5cCertificate,omitempty"` + // Set for X5C, AWS, GCP, and Azure provisioners + AuthorizationPrincipal string `json:"authorizationPrincipal,omitempty"` }