diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e0871f93..a9618d0b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,7 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" 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/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 471eedab..8ca265e0 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v1.1.1 + uses: dependabot/fetch-metadata@v1.6.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for Dependabot PRs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37fe2c2e..ab821066 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,19 +30,19 @@ jobs: echo ${{ github.ref }} | grep "\-rc.*" OUT=$? if [ $OUT -eq 0 ]; then IS_PRERELEASE=true; else IS_PRERELEASE=false; fi - echo "IS_PRERELEASE=${IS_PRERELEASE}" >> ${GITHUB_OUTPUT} + echo "IS_PRERELEASE=${IS_PRERELEASE}" >> "${GITHUB_OUTPUT}" - name: Extract Tag Names id: extract-tag run: | VERSION=${GITHUB_REF#refs/tags/v} - echo "VERSION=${VERSION}" >> ${GITHUB_OUTPUT} - echo "DOCKER_TAGS=${{ env.DOCKER_IMAGE }}:${VERSION}" >> ${GITHUB_ENV} - echo "DOCKER_TAGS_HSM=${{ env.DOCKER_IMAGE }}:${VERSION}-hsm" >> ${GITHUB_ENV} + echo "VERSION=${VERSION}" >> "${GITHUB_OUTPUT}" + echo "DOCKER_TAGS=${{ env.DOCKER_IMAGE }}:${VERSION}" >> "${GITHUB_ENV}" + echo "DOCKER_TAGS_HSM=${{ env.DOCKER_IMAGE }}:${VERSION}-hsm" >> "${GITHUB_ENV}" - name: Add Latest Tag if: steps.is_prerelease.outputs.IS_PRERELEASE == 'false' run: | - echo "DOCKER_TAGS=${{ env.DOCKER_TAGS }},${{ env.DOCKER_IMAGE }}:latest" >> ${GITHUB_ENV} - echo "DOCKER_TAGS_HSM=${{ env.DOCKER_TAGS_HSM }},${{ env.DOCKER_IMAGE }}:hsm" >> ${GITHUB_ENV} + echo "DOCKER_TAGS=${{ env.DOCKER_TAGS }},${{ env.DOCKER_IMAGE }}:latest" >> "${GITHUB_ENV}" + echo "DOCKER_TAGS_HSM=${{ env.DOCKER_TAGS_HSM }},${{ env.DOCKER_IMAGE }}:hsm" >> "${GITHUB_ENV}" - name: Create Release id: create_release uses: actions/create-release@v1 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 5e98cf92..c00b26e8 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -39,7 +39,6 @@ archives: format_overrides: - goos: windows format: zip - wrap_in_directory: "{{ .ProjectName }}_{{ .Version }}" files: - README.md - LICENSE @@ -48,6 +47,7 @@ archives: << : *ARCHIVE id: unversioned name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" + wrap_in_directory: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}" nfpms: @@ -164,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. @@ -298,7 +298,7 @@ winget: pull_request: # Whether to enable it or not. enabled: true - #check_boxes: true + check_boxes: true # Whether to open the PR as a draft or not. # # Default: false @@ -327,6 +327,7 @@ scoops: repository: owner: smallstep name: scoop-bucket + branch: main # Git author used to commit to the repository. # Defaults are shown. diff --git a/CHANGELOG.md b/CHANGELOG.md index ecfced1d..1e9e2029 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,10 +25,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. --- -## [Unreleased] +## [0.25.1] - 2023-11-28 ### Added +- Provisioner name in SCEP webhook request body in (smallstep/certificates#1617) +- Support for ASN1 boolean encoding in (smallstep/certificates#1590) + +### Changed + +- Generation of first provisioner name on `step ca init` in (smallstep/certificates#1566) +- Processing of SCEP Get PKIOperation requests in (smallstep/certificates#1570) +- Support for signing identity certificate during SSH sign by skipping URI validation in (smallstep/certificates#1572) +- Dependency on `micromdm/scep` and `go.mozilla.org/pkcs7` to use Smallstep forks in (smallstep/certificates#1600) +- Make the Common Name validator for JWK provisioners accept values from SANs too in (smallstep/certificates#1609) + +### Fixed + +- Registration Authority token creation relied on values from CSR. Fixed to rely on template in (smallstep/certificates#1608) +- Use same glibc version for running the CA when built using CGo in (smallstep/certificates#1616) + +## [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) @@ -36,12 +57,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. (smallstep/certificates#1477) - Added AWS public certificates for me-central-1 and ap-southeast-3 (smallstep/certificates#1404) -- Add namespace field to VaultCAS JSON config (smallstep/certificates#1424) +- 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 @@ -53,6 +96,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. (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 diff --git a/README.md b/README.md index 9b454f51..4505a7ef 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ To get up and running quickly, or as an alternative to running your own `step-ca [Documentation](https://smallstep.com/docs) | [Installation](https://smallstep.com/docs/step-ca/installation) | [Getting Started](https://smallstep.com/docs/step-ca/getting-started) | -[Contributor's Guide](./docs/CONTRIBUTING.md) +[Contributor's Guide](./CONTRIBUTING.md) [![GitHub release](https://img.shields.io/github/release/smallstep/certificates.svg)](https://github.com/smallstep/certificates/releases/latest) [![Go Report Card](https://goreportcard.com/badge/github.com/smallstep/certificates)](https://goreportcard.com/report/github.com/smallstep/certificates) diff --git a/acme/account_test.go b/acme/account_test.go index d4122500..8780d3c0 100644 --- a/acme/account_test.go +++ b/acme/account_test.go @@ -25,7 +25,7 @@ func TestKeyToID(t *testing.T) { jwk.Key = "foo" return test{ jwk: jwk, - err: NewErrorISE("error generating jwk thumbprint: square/go-jose: unknown key type 'string'"), + err: NewErrorISE("error generating jwk thumbprint: go-jose/go-jose: unknown key type 'string'"), } }, "ok": func(t *testing.T) test { diff --git a/acme/api/account.go b/acme/api/account.go index ce8b5799..25d923c7 100644 --- a/acme/api/account.go +++ b/acme/api/account.go @@ -6,7 +6,7 @@ import ( "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" diff --git a/acme/api/account_test.go b/acme/api/account_test.go index 1d74b78a..7d799c88 100644 --- a/acme/api/account_test.go +++ b/acme/api/account_test.go @@ -13,7 +13,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" "go.step.sm/crypto/jose" diff --git a/acme/api/handler.go b/acme/api/handler.go index 16713cf7..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" diff --git a/acme/api/handler_test.go b/acme/api/handler_test.go index 29cd133a..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" diff --git a/acme/api/middleware.go b/acme/api/middleware.go index ab2ab908..c3e1458e 100644 --- a/acme/api/middleware.go +++ b/acme/api/middleware.go @@ -422,11 +422,20 @@ func verifyAndExtractJWSPayload(next nextHTTP) nextHTTP { render.Error(w, acme.NewError(acme.ErrorMalformedType, "verifier and signature algorithm do not match")) return } + payload, err := jws.Verify(jwk) - if err != nil { + switch { + case errors.Is(err, jose.ErrCryptoFailure): + payload, err = retryVerificationWithPatchedSignatures(jws, jwk) + if err != nil { + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "error verifying jws with patched signature(s)")) + return + } + case err != nil: render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "error verifying jws")) return } + ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{ value: payload, isPostAsGet: len(payload) == 0, @@ -436,6 +445,105 @@ func verifyAndExtractJWSPayload(next nextHTTP) nextHTTP { } } +// retryVerificationWithPatchedSignatures retries verification of the JWS using +// the JWK by patching the JWS signatures if they're determined to be too short. +// +// Generally this shouldn't happen, but we've observed this to be the case with +// the macOS ACME client, which seems to omit (at least one) leading null +// byte(s). The error returned is `go-jose/go-jose: error in cryptographic +// primitive`, which is a sentinel error that hides the details of the actual +// underlying error, which is as follows: `go-jose/go-jose: invalid signature +// size, have 63 bytes, wanted 64`, for ES256. +func retryVerificationWithPatchedSignatures(jws *jose.JSONWebSignature, jwk *jose.JSONWebKey) (data []byte, err error) { + originalSignatureValues := make([][]byte, len(jws.Signatures)) + patched := false + defer func() { + if patched && err != nil { + for i, sig := range jws.Signatures { + sig.Signature = originalSignatureValues[i] + jws.Signatures[i] = sig + } + } + }() + for i, sig := range jws.Signatures { + var expectedSize int + alg := strings.ToUpper(sig.Header.Algorithm) + switch alg { + case jose.ES256: + expectedSize = 64 + case jose.ES384: + expectedSize = 96 + case jose.ES512: + expectedSize = 132 + default: + // other cases are (currently) ignored + continue + } + + switch diff := expectedSize - len(sig.Signature); diff { + case 0: + // expected length; nothing to do; will result in just doing the + // same verification (as done before calling this function) again, + // and thus an error will be returned. + continue + case 1: + patched = true + original := make([]byte, expectedSize-diff) + copy(original, sig.Signature) + originalSignatureValues[i] = original + + patchedR := make([]byte, expectedSize) + copy(patchedR[1:], original) // [0x00, R.0:31, S.0:32], for expectedSize 64 + sig.Signature = patchedR + jws.Signatures[i] = sig + + // verify it with a patched R; return early if successful; continue + // with patching S if not. + data, err = jws.Verify(jwk) + if err == nil { + return + } + + patchedS := make([]byte, expectedSize) + halfSize := expectedSize / 2 + copy(patchedS, original[:halfSize]) // [R.0:32], for expectedSize 64 + copy(patchedS[halfSize+1:], original[halfSize:]) // [R.0:32, 0x00, S.0:31] + sig.Signature = patchedS + jws.Signatures[i] = sig + case 2: + // assumption is currently the Apple case, in which only the + // first null byte of R and/or S are removed, and thus not a case in + // which two first bytes of either R or S are removed. + patched = true + original := make([]byte, expectedSize-diff) + copy(original, sig.Signature) + originalSignatureValues[i] = original + + patchedRS := make([]byte, expectedSize) + halfSize := expectedSize / 2 + copy(patchedRS[1:], original[:halfSize-1]) // [0x00, R.0:31], for expectedSize 64 + copy(patchedRS[halfSize+1:], original[halfSize-1:]) // [0x00, R.0:31, 0x00, S.0:31] + sig.Signature = patchedRS + jws.Signatures[i] = sig + default: + // Technically, there can be multiple null bytes in either R or S, + // so when the difference is larger than 2, there is more than one + // option to pick. Apple's ACME client seems to only cut off the + // first null byte of either R or S, so we don't do anything in this + // case. Will result in just doing the same verification (as done + // before calling this function) again, and thus an error will be + // returned. + // TODO(hs): log this specific case? It might mean some other ACME + // client is doing weird things. + continue + } + } + + data, err = jws.Verify(jwk) + + return +} + // isPostAsGet asserts that the request is a PostAsGet (empty JWS payload). func isPostAsGet(next nextHTTP) nextHTTP { return func(w http.ResponseWriter, r *http.Request) { diff --git a/acme/api/middleware_test.go b/acme/api/middleware_test.go index 90190bc7..14320ec2 100644 --- a/acme/api/middleware_test.go +++ b/acme/api/middleware_test.go @@ -6,6 +6,7 @@ import ( "crypto" "encoding/base64" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -14,9 +15,10 @@ import ( "strings" "testing" - "github.com/pkg/errors" "github.com/smallstep/assert" "github.com/smallstep/certificates/acme" + tassert "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" ) @@ -354,7 +356,7 @@ func TestHandler_parseJWS(t *testing.T) { return test{ body: strings.NewReader("foo"), statusCode: 400, - err: acme.NewError(acme.ErrorMalformedType, "failed to parse JWS from request body: square/go-jose: compact JWS format must have three parts"), + err: acme.NewError(acme.ErrorMalformedType, "failed to parse JWS from request body: go-jose/go-jose: compact JWS format must have three parts"), } }, "ok": func(t *testing.T) test { @@ -469,7 +471,7 @@ func TestHandler_verifyAndExtractJWSPayload(t *testing.T) { err: acme.NewErrorISE("jwk expected in request context"), } }, - "fail/verify-jws-failure": func(t *testing.T) test { + "fail/verify-jws-failure-wrong-jwk": func(t *testing.T) test { _jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) assert.FatalError(t, err) _pub := _jwk.Public() @@ -478,7 +480,34 @@ func TestHandler_verifyAndExtractJWSPayload(t *testing.T) { return test{ ctx: ctx, statusCode: 400, - err: acme.NewError(acme.ErrorMalformedType, "error verifying jws: square/go-jose: error in cryptographic primitive"), + err: acme.NewError(acme.ErrorMalformedType, "error verifying jws: go-jose/go-jose: error in cryptographic primitive"), + } + }, + "fail/verify-jws-failure-too-many-signatures": func(t *testing.T) test { + newParsedJWS, err := jose.ParseJWS(raw) + assert.FatalError(t, err) + newParsedJWS.Signatures = append(newParsedJWS.Signatures, newParsedJWS.Signatures...) + ctx := context.WithValue(context.Background(), jwsContextKey, newParsedJWS) + ctx = context.WithValue(ctx, jwkContextKey, pub) + return test{ + ctx: ctx, + statusCode: 400, + err: acme.NewError(acme.ErrorMalformedType, "error verifying jws: go-jose/go-jose: too many signatures in payload; expecting only one"), + } + }, + "fail/apple-acmeclient-omitting-leading-null-byte-in-signature-with-wrong-jwk": func(t *testing.T) test { + _jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) + assert.FatalError(t, err) + _pub := _jwk.Public() + appleNullByteCaseBody := `{"payload":"dGVzdC0xMTA1","protected":"eyJhbGciOiJFUzI1NiJ9","signature":"rQPYKYflfKnlgBKqDeWsJH2TJ6iHAnou7sFzXlmYD4ArXqLfYuqotWERKrna2wfzh0pu7USWO2gzlOqRK9qq"}` + appleNullByteCaseJWS, err := jose.ParseJWS(appleNullByteCaseBody) + require.NoError(t, err) + ctx := context.WithValue(context.Background(), jwsContextKey, appleNullByteCaseJWS) + ctx = context.WithValue(ctx, jwkContextKey, &_pub) + return test{ + ctx: ctx, + statusCode: 400, + err: acme.NewError(acme.ErrorMalformedType, "error verifying jws: go-jose/go-jose: error in cryptographic primitive"), } }, "fail/algorithm-mismatch": func(t *testing.T) test { @@ -577,6 +606,38 @@ func TestHandler_verifyAndExtractJWSPayload(t *testing.T) { }, } }, + "ok/apple-acmeclient-omitting-leading-null-byte-in-signature": func(t *testing.T) test { + appleNullByteCaseKey := []byte(`{ + "kid": "uioinbiTlJICL0MYsb6ar1totfRA2tiPqWgntF8xUdo", + "crv": "P-256", + "alg": "ES256", + "kty": "EC", + "x": "wlz-Kv9X0h32fzLq-cogls9HxoZQqV-GuWxdb2MCeUY", + "y": "xzP6zRrg_jynYljZTxfJuql_QWtdQR6lpJ52q_6Vavg" + }`) + appleNullByteCaseJWK := &jose.JSONWebKey{} + err = json.Unmarshal(appleNullByteCaseKey, appleNullByteCaseJWK) + require.NoError(t, err) + appleNullByteCaseBody := `{"payload":"dGVzdC0xMTA1","protected":"eyJhbGciOiJFUzI1NiJ9","signature":"rQPYKYflfKnlgBKqDeWsJH2TJ6iHAnou7sFzXlmYD4ArXqLfYuqotWERKrna2wfzh0pu7USWO2gzlOqRK9qq"}` + appleNullByteCaseJWS, err := jose.ParseJWS(appleNullByteCaseBody) + require.NoError(t, err) + ctx := context.WithValue(context.Background(), jwsContextKey, appleNullByteCaseJWS) + ctx = context.WithValue(ctx, jwkContextKey, appleNullByteCaseJWK) + return test{ + ctx: ctx, + statusCode: 200, + next: func(w http.ResponseWriter, r *http.Request) { + p, err := payloadFromContext(r.Context()) + tassert.NoError(t, err) + if tassert.NotNil(t, p) { + tassert.Equal(t, []byte(`test-1105`), p.value) + tassert.False(t, p.isPostAsGet) + tassert.False(t, p.isEmptyJSON) + } + w.Write(testBody) + }, + } + }, } for name, run := range tests { tc := run(t) @@ -1695,3 +1756,86 @@ func TestHandler_checkPrerequisites(t *testing.T) { }) } } + +func Test_retryVerificationWithPatchedSignatures(t *testing.T) { + patchedRKey := []byte(`{ + "kid": "uioinbiTlJICL0MYsb6ar1totfRA2tiPqWgntF8xUdo", + "crv": "P-256", + "alg": "ES256", + "kty": "EC", + "x": "wlz-Kv9X0h32fzLq-cogls9HxoZQqV-GuWxdb2MCeUY", + "y": "xzP6zRrg_jynYljZTxfJuql_QWtdQR6lpJ52q_6Vavg" + }`) + patchedRJWK := &jose.JSONWebKey{} + err := json.Unmarshal(patchedRKey, patchedRJWK) + require.NoError(t, err) + patchedRBody := `{"payload":"dGVzdC0xMTA1","protected":"eyJhbGciOiJFUzI1NiJ9","signature":"rQPYKYflfKnlgBKqDeWsJH2TJ6iHAnou7sFzXlmYD4ArXqLfYuqotWERKrna2wfzh0pu7USWO2gzlOqRK9qq"}` + patchedR, err := jose.ParseJWS(patchedRBody) + require.NoError(t, err) + + patchedSKey := []byte(`{ + "kid": "PblXsnK59uTiF5k3mmAN2B6HDPPxqBL_4UGhEG8ZO6g", + "crv": "P-256", + "alg": "ES256", + "kty": "EC", + "x": "T5aM_TOSattXNeUkH1VHZXh8URzdjZTI2zLvVgI0cy0", + "y": "Lf8h8qZnURXIxm6OnQ69kxGC91YtTZRD2GAroEf1UA8" + }`) + patchedSJWK := &jose.JSONWebKey{} + err = json.Unmarshal(patchedSKey, patchedSJWK) + require.NoError(t, err) + patchedSBody := `{"payload":"dGVzdC02Ng","protected":"eyJhbGciOiJFUzI1NiJ9","signature":"krtSKSgVB04oqx6i9QLeal_wZSnjV1_PSIM3AubT0WRIxnhl_yYbVpa3i53p3dUW56TtP6_SUZboH6SvLHMz"}` + patchedS, err := jose.ParseJWS(patchedSBody) + require.NoError(t, err) + + patchedRSKey := []byte(`{ + "kid": "U8BmBVbZsNUawvhOomJQPa6uYj1rdxCPQWF_nOLVsc4", + "crv": "P-256", + "alg": "ES256", + "kty": "EC", + "x": "Ym0l3GMS6aHBLo-xe73Kub4kafnOBu_QAfOsx5y-bV0", + "y": "wKijX9Cu67HbK94StPcI18WulgRfIMbP2ZU7gQuf3-M" + }`) + patchedRSJWK := &jose.JSONWebKey{} + err = json.Unmarshal(patchedRSKey, patchedRSJWK) + require.NoError(t, err) + patchedRSBody := `{"payload":"dGVzdC05MDY3","protected":"eyJhbGciOiJFUzI1NiJ9","signature":"2r_My19oRg7mWf9I5JTkNYp8otfEMz-yXRA8ltZTAKZxyJLurpVEgicmNItu7lfcCrGrTgI3Obye_gSaIyc"}` + patchedRS, err := jose.ParseJWS(patchedRSBody) + require.NoError(t, err) + + patchedRWithWrongJWK, err := jose.ParseJWS(patchedRBody) + require.NoError(t, err) + + tests := []struct { + name string + jws *jose.JSONWebSignature + jwk *jose.JSONWebKey + expectedData []byte + expectedSignature string + expectedError error + }{ + {"ok/patched-r", patchedR, patchedRJWK, []byte(`test-1105`), `AK0D2CmH5Xyp5YASqg3lrCR9kyeohwJ6Lu7Bc15ZmA-AK16i32LqqLVhESq52tsH84dKbu1EljtoM5TqkSvaqg`, nil}, + {"ok/patched-s", patchedS, patchedSJWK, []byte(`test-66`), `krtSKSgVB04oqx6i9QLeal_wZSnjV1_PSIM3AubT0WQASMZ4Zf8mG1aWt4ud6d3VFuek7T-v0lGW6B-kryxzMw`, nil}, + {"ok/patched-rs", patchedRS, patchedRSJWK, []byte(`test-9067`), `ANq_zMtfaEYO5ln_SOSU5DWKfKLXxDM_sl0QPJbWUwAApnHIku6ulUSCJyY0i27uV9wKsatOAjc5vJ7-BJojJw`, nil}, + {"fail/patched-r-wrong-jwk", patchedRWithWrongJWK, patchedRSJWK, nil, `rQPYKYflfKnlgBKqDeWsJH2TJ6iHAnou7sFzXlmYD4ArXqLfYuqotWERKrna2wfzh0pu7USWO2gzlOqRK9qq`, errors.New("go-jose/go-jose: error in cryptographic primitive")}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expectedSignature, decodeErr := base64.RawURLEncoding.DecodeString(tt.expectedSignature) + require.NoError(t, decodeErr) + + data, err := retryVerificationWithPatchedSignatures(tt.jws, tt.jwk) + if tt.expectedError != nil { + tassert.EqualError(t, err, tt.expectedError.Error()) + tassert.Equal(t, expectedSignature, tt.jws.Signatures[0].Signature) + tassert.Empty(t, data) + return + } + + tassert.NoError(t, err) + tassert.Len(t, tt.jws.Signatures[0].Signature, 64) + tassert.Equal(t, expectedSignature, tt.jws.Signatures[0].Signature) + tassert.Equal(t, tt.expectedData, data) + }) + } +} 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 5b9ad60a..36de975a 100644 --- a/acme/api/order_test.go +++ b/acme/api/order_test.go @@ -15,7 +15,7 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" "go.step.sm/crypto/pemutil" diff --git a/acme/api/revoke_test.go b/acme/api/revoke_test.go index e8edcc41..5d274faf 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" @@ -1283,7 +1283,7 @@ func Test_wrapUnauthorizedError(t *testing.T) { } }, "wrap-subject": func(t *testing.T) test { - acmeErr := acme.NewError(acme.ErrorUnauthorizedType, "verification of jws using certificate public key failed: square/go-jose: error in cryptographic primitive") + acmeErr := acme.NewError(acme.ErrorUnauthorizedType, "verification of jws using certificate public key failed: go-jose/go-jose: error in cryptographic primitive") acmeErr.Status = http.StatusForbidden acmeErr.Detail = "No authorization provided for name test.example.com" cert := &x509.Certificate{ @@ -1292,7 +1292,7 @@ func Test_wrapUnauthorizedError(t *testing.T) { }, } return test{ - err: errors.New("square/go-jose: error in cryptographic primitive"), + err: errors.New("go-jose/go-jose: error in cryptographic primitive"), cert: cert, unauthorizedIdentifiers: []acme.Identifier{}, msg: "verification of jws using certificate public key failed", diff --git a/acme/challenge.go b/acme/challenge.go index 687cc680..995981ab 100644 --- a/acme/challenge.go +++ b/acme/challenge.go @@ -26,7 +26,7 @@ import ( "time" "github.com/fxamacker/cbor/v2" - "github.com/google/go-tpm/tpm2" + "github.com/google/go-tpm/legacy/tpm2" "golang.org/x/exp/slices" "github.com/smallstep/go-attestation/attest" @@ -528,6 +528,7 @@ type coseAlgorithmIdentifier int32 const ( coseAlgES256 coseAlgorithmIdentifier = -7 coseAlgRS256 coseAlgorithmIdentifier = -257 + coseAlgRS1 coseAlgorithmIdentifier = -65535 // deprecated, but (still) often used in TPMs ) func doTPMAttestationFormat(_ context.Context, prov Provisioner, ch *Challenge, jwk *jose.JSONWebKey, att *attestationObject) (*tpmAttestationData, error) { @@ -652,15 +653,16 @@ func doTPMAttestationFormat(_ context.Context, prov Provisioner, ch *Challenge, return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid alg in attestation statement") } - // only RS256 and ES256 are allowed - coseAlg := coseAlgorithmIdentifier(alg) - if coseAlg != coseAlgRS256 && coseAlg != coseAlgES256 { + var hash crypto.Hash + switch coseAlgorithmIdentifier(alg) { + case coseAlgRS256, coseAlgES256: + hash = crypto.SHA256 + case coseAlgRS1: + hash = crypto.SHA1 + default: return nil, NewDetailedError(ErrorBadAttestationStatementType, "invalid alg %d in attestation statement", alg) } - // set the hash algorithm to use to SHA256 - hash := crypto.SHA256 - // recreate the generated key certification parameter values and verify // the attested key using the public key of the AK. certificationParameters := &attest.CertificationParameters{ diff --git a/acme/challenge_test.go b/acme/challenge_test.go index c20cf6aa..5cede1c5 100644 --- a/acme/challenge_test.go +++ b/acme/challenge_test.go @@ -354,7 +354,7 @@ func TestKeyAuthorization(t *testing.T) { return test{ token: "1234", jwk: jwk, - err: NewErrorISE("error generating JWK thumbprint: square/go-jose: unknown key type 'string'"), + err: NewErrorISE("error generating JWK thumbprint: go-jose/go-jose: unknown key type 'string'"), } }, "ok": func(t *testing.T) test { @@ -1089,7 +1089,7 @@ func TestHTTP01Validate(t *testing.T) { }, }, jwk: jwk, - err: NewErrorISE("error generating JWK thumbprint: square/go-jose: unknown key type 'string'"), + err: NewErrorISE("error generating JWK thumbprint: go-jose/go-jose: unknown key type 'string'"), } }, "ok/key-auth-mismatch": func(t *testing.T) test { @@ -1389,7 +1389,7 @@ func TestDNS01Validate(t *testing.T) { }, }, jwk: jwk, - err: NewErrorISE("error generating JWK thumbprint: square/go-jose: unknown key type 'string'"), + err: NewErrorISE("error generating JWK thumbprint: go-jose/go-jose: unknown key type 'string'"), } }, "fail/key-auth-mismatch-store-error": func(t *testing.T) test { @@ -2141,7 +2141,7 @@ func TestTLSALPN01Validate(t *testing.T) { }, srv: srv, jwk: jwk, - err: NewErrorISE("error generating JWK thumbprint: square/go-jose: unknown key type 'string'"), + err: NewErrorISE("error generating JWK thumbprint: go-jose/go-jose: unknown key type 'string'"), } }, "ok/error-no-extension": func(t *testing.T) test { diff --git a/acme/challenge_tpmsimulator_test.go b/acme/challenge_tpmsimulator_test.go index 87db8631..6f719541 100644 --- a/acme/challenge_tpmsimulator_test.go +++ b/acme/challenge_tpmsimulator_test.go @@ -817,7 +817,7 @@ func Test_doTPMAttestationFormat(t *testing.T) { "certInfo": params.CreateAttestation, "pubArea": params.Public, }, - }}, nil, newInternalServerError("failed creating key auth digest: error generating JWK thumbprint: square/go-jose: unknown key type '[]uint8'")}, + }}, nil, newInternalServerError("failed creating key auth digest: error generating JWK thumbprint: go-jose/go-jose: unknown key type '[]uint8'")}, {"fail different keyAuthorization", args{ctx, mustAttestationProvisioner(t, acaRoot), &Challenge{Token: "aDifferentToken"}, jwk, &attestationObject{ Format: "tpm", AttStatement: map[string]interface{}{ diff --git a/acme/client.go b/acme/client.go index 51560cb8..8f506ef9 100644 --- a/acme/client.go +++ b/acme/client.go @@ -55,6 +55,7 @@ func NewClient() Client { http: &http.Client{ Timeout: 30 * time.Second, Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{ //nolint:gosec // used on tls-alpn-01 challenge InsecureSkipVerify: true, // lgtm[go/disabled-certificate-check] diff --git a/acme/common.go b/acme/common.go index afab13b2..46e86ae6 100644 --- a/acme/common.go +++ b/acme/common.go @@ -94,14 +94,17 @@ func ProvisionerFromContext(ctx context.Context) (v Provisioner, ok bool) { return } -// MustLinkerFromContext returns the current provisioner from the given context. +// MustProvisionerFromContext returns the current provisioner from the given context. // It will panic if it's not in the context. func MustProvisionerFromContext(ctx context.Context) Provisioner { - if v, ok := ProvisionerFromContext(ctx); !ok { + var ( + v Provisioner + ok bool + ) + if v, ok = ProvisionerFromContext(ctx); !ok { panic("acme provisioner is not the context") - } else { - return v } + return v } // MockProvisioner for testing diff --git a/acme/db.go b/acme/db.go index fa9aa0de..4cbb3089 100644 --- a/acme/db.go +++ b/acme/db.go @@ -71,11 +71,14 @@ func DatabaseFromContext(ctx context.Context) (db DB, ok bool) { // MustDatabaseFromContext returns the current database from the given context. // It will panic if it's not in the context. func MustDatabaseFromContext(ctx context.Context) DB { - if db, ok := DatabaseFromContext(ctx); !ok { + var ( + db DB + ok bool + ) + if db, ok = DatabaseFromContext(ctx); !ok { panic("acme database is not in the context") - } else { - return db } + return db } // MockDB is an implementation of the DB interface that should only be used as diff --git a/acme/linker.go b/acme/linker.go index bddc21f1..d142bf10 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" @@ -142,11 +142,14 @@ func LinkerFromContext(ctx context.Context) (v Linker, ok bool) { // MustLinkerFromContext returns the current linker from the given context. It // will panic if it's not in the context. func MustLinkerFromContext(ctx context.Context) Linker { - if v, ok := LinkerFromContext(ctx); !ok { + var ( + v Linker + ok bool + ) + if v, ok = LinkerFromContext(ctx); !ok { panic("acme linker is not the context") - } else { - return v } + return v } type baseURLKey struct{} diff --git a/api/api.go b/api/api.go index 2d6c0bf7..1d367f7d 100644 --- a/api/api.go +++ b/api/api.go @@ -19,12 +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" @@ -54,7 +55,7 @@ type Authority interface { GetRoots() ([]*x509.Certificate, error) GetFederation() ([]*x509.Certificate, error) Version() authority.Version - GetCertificateRevocationList() ([]byte, error) + GetCertificateRevocationList() (*authority.CertificateRevocationListInfo, error) } // mustAuthority will be replaced on unit tests. @@ -232,6 +233,29 @@ type ProvisionersResponse struct { 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. // @@ -239,24 +263,22 @@ type ProvisionersResponse struct { // 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 } - old := scepProv.ChallengePassword - scepProv.ChallengePassword = "*** REDACTED ***" - defer func(p string) { //nolint:gocritic // defer in loop required to restore initial state of provisioners - scepProv.ChallengePassword = p - }(old) + responseProvisioners = append(responseProvisioners, scepFromProvisioner(scepProv)) } var list = struct { Provisioners []provisioner.Interface `json:"provisioners"` NextCursor string `json:"nextCursor"` }{ - Provisioners: []provisioner.Interface(p.Provisioners), + Provisioners: []provisioner.Interface(responseProvisioners), NextCursor: p.NextCursor, } diff --git a/api/api_test.go b/api/api_test.go index 90acf759..4266dff3 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -26,16 +26,13 @@ import ( "testing" "time" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "github.com/pkg/errors" - sassert "github.com/stretchr/testify/assert" + "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" @@ -204,7 +201,7 @@ type mockAuthority struct { getEncryptedKey func(kid string) (string, error) getRoots func() ([]*x509.Certificate, error) getFederation func() ([]*x509.Certificate, error) - getCRL func() ([]byte, error) + getCRL func() (*authority.CertificateRevocationListInfo, error) signSSH func(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) signSSHAddUser func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) renewSSH func(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error) @@ -218,12 +215,12 @@ type mockAuthority struct { version func() authority.Version } -func (m *mockAuthority) GetCertificateRevocationList() ([]byte, error) { +func (m *mockAuthority) GetCertificateRevocationList() (*authority.CertificateRevocationListInfo, error) { if m.getCRL != nil { return m.getCRL() } - return m.ret1.([]byte), m.err + return m.ret1.(*authority.CertificateRevocationListInfo), m.err } // TODO: remove once Authorize is deprecated. @@ -666,7 +663,7 @@ func TestSignRequest_Validate(t *testing.T) { } if err := s.Validate(); err != nil { if assert.NotNil(t, tt.err) { - assert.HasPrefix(t, err.Error(), tt.err.Error()) + assert.True(t, strings.HasPrefix(err.Error(), tt.err.Error())) } } else { assert.Nil(t, tt.err) @@ -800,45 +797,6 @@ func (m *mockProvisioner) AuthorizeSSHRekey(ctx context.Context, token string) ( return m.ret1.(*ssh.Certificate), m.ret2.([]provisioner.SignOption), m.err } -func Test_CRLGeneration(t *testing.T) { - tests := []struct { - name string - err error - statusCode int - expected []byte - }{ - {"empty", nil, http.StatusOK, nil}, - } - - chiCtx := chi.NewRouteContext() - req := httptest.NewRequest("GET", "http://example.com/crl", http.NoBody) - req = req.WithContext(context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)) - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockMustAuthority(t, &mockAuthority{ret1: tt.expected, err: tt.err}) - w := httptest.NewRecorder() - CRL(w, req) - res := w.Result() - - if res.StatusCode != tt.statusCode { - t.Errorf("caHandler.CRL StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) - } - - body, err := io.ReadAll(res.Body) - res.Body.Close() - if err != nil { - t.Errorf("caHandler.Root unexpected error = %v", err) - } - if tt.statusCode == 200 { - if !bytes.Equal(bytes.TrimSpace(body), tt.expected) { - t.Errorf("caHandler.Root CRL = %s, wants %s", body, tt.expected) - } - } - }) - } -} - func Test_caHandler_Route(t *testing.T) { type fields struct { Authority Authority @@ -1267,10 +1225,10 @@ func Test_Provisioners(t *testing.T) { expectedError400 := errs.BadRequest("limit 'abc' is not an integer") expectedError400Bytes, err := json.Marshal(expectedError400) - assert.FatalError(t, err) + require.NoError(t, err) expectedError500 := errs.InternalServer("force") expectedError500Bytes, err := json.Marshal(expectedError500) - assert.FatalError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockMustAuthority(t, tt.fields.Authority) @@ -1337,7 +1295,7 @@ func Test_ProvisionerKey(t *testing.T) { expected := []byte(`{"key":"` + privKey + `"}`) expectedError404 := errs.NotFound("force") expectedError404Bytes, err := json.Marshal(expectedError404) - assert.FatalError(t, err) + require.NoError(t, err) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1577,7 +1535,6 @@ func mustCertificate(t *testing.T, pub, priv interface{}) *x509.Certificate { } func TestProvisionersResponse_MarshalJSON(t *testing.T) { - k := map[string]any{ "use": "sig", "kty": "EC", @@ -1587,11 +1544,11 @@ func TestProvisionersResponse_MarshalJSON(t *testing.T) { "x": "7ZdAAMZCFU4XwgblI5RfZouBi8lYmF6DlZusNNnsbm8", "y": "sQr2JdzwD2fgyrymBEXWsxDxFNjjqN64qLLSbLdLZ9Y", } - key := squarejose.JSONWebKey{} + key := jose.JSONWebKey{} b, err := json.Marshal(k) - assert.FatalError(t, err) + require.NoError(t, err) err = json.Unmarshal(b, &key) - assert.FatalError(t, err) + require.NoError(t, err) r := ProvisionersResponse{ Provisioners: provisioner.List{ @@ -1601,6 +1558,12 @@ func TestProvisionersResponse_MarshalJSON(t *testing.T) { 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", @@ -1617,7 +1580,14 @@ func TestProvisionersResponse_MarshalJSON(t *testing.T) { { "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, }, @@ -1640,11 +1610,11 @@ func TestProvisionersResponse_MarshalJSON(t *testing.T) { } expBytes, err := json.Marshal(expected) - sassert.NoError(t, err) + assert.NoError(t, err) br, err := r.MarshalJSON() - sassert.NoError(t, err) - sassert.JSONEq(t, string(expBytes), string(br)) + assert.NoError(t, err) + assert.JSONEq(t, string(expBytes), string(br)) keyCopy := key expList := provisioner.List{ @@ -1654,6 +1624,12 @@ func TestProvisionersResponse_MarshalJSON(t *testing.T) { 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", @@ -1664,7 +1640,7 @@ func TestProvisionersResponse_MarshalJSON(t *testing.T) { } // MarshalJSON must not affect the struct properties itself - sassert.Equal(t, expList, r.Provisioners) + assert.Equal(t, expList, r.Provisioners) } const ( @@ -1683,14 +1659,14 @@ func TestLogSSHCertificate(t *testing.T) { rl := logging.NewResponseLogger(w) LogSSHCertificate(rl, cert) - sassert.Equal(t, 200, w.Result().StatusCode) + assert.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"]) + assert.Equal(t, uint64(14376510277651266987), fields["serial"]) + assert.Equal(t, []string{"herman"}, fields["principals"]) + assert.Equal(t, "ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate", fields["certificate-type"]) + assert.Equal(t, time.Unix(1674129191, 0).Format(time.RFC3339), fields["valid-from"]) + assert.Equal(t, time.Unix(1674186851, 0).Format(time.RFC3339), fields["valid-to"]) + assert.Equal(t, "AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgLnkvSk4odlo3b1R+RDw+LmorL3RkN354IilCIVFVen4AAAAIbmlzdHAyNTYAAABBBHjKHss8WM2ffMYlavisoLXR0I6UEIU+cidV1ogEH1U6+/SYaFPrlzQo0tGLM5CNkMbhInbyasQsrHzn8F1Rt7nHg5/tcSf9qwAAAAEAAAAGaGVybWFuAAAACgAAAAZoZXJtYW4AAAAAY8kvJwAAAABjyhBjAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAEEE/ayqpPrZZF5uA1UlDt4FreTf15agztQIzpxnWq/XoxAHzagRSkFGkdgFpjgsfiRpP8URHH3BZScqc0ZDCTxhoQAAAGQAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAEkAAAAhAJuP1wCVwoyrKrEtHGfFXrVbRHySDjvXtS1tVTdHyqymAAAAIBa/CSSzfZb4D2NLP+eEmOOMJwSjYOiNM8fiOoAaqglI", fields["certificate"]) + assert.Equal(t, "SHA256:RvkDPGwl/G9d7LUFm1kmWhvOD9I/moPq4yxcb0STwr0 (ECDSA-CERT)", fields["public-key"]) } diff --git a/api/crl.go b/api/crl.go index 6386f34a..c10d08ca 100644 --- a/api/crl.go +++ b/api/crl.go @@ -3,18 +3,32 @@ package api import ( "encoding/pem" "net/http" + "time" "github.com/smallstep/certificates/api/render" + "github.com/smallstep/certificates/errs" ) // CRL is an HTTP handler that returns the current CRL in DER or PEM format func CRL(w http.ResponseWriter, r *http.Request) { - crlBytes, err := mustAuthority(r.Context()).GetCertificateRevocationList() + crlInfo, err := mustAuthority(r.Context()).GetCertificateRevocationList() if err != nil { render.Error(w, err) return } + if crlInfo == nil { + render.Error(w, errs.New(http.StatusNotFound, "no CRL available")) + return + } + + expires := crlInfo.ExpiresAt + if expires.IsZero() { + expires = time.Now() + } + + w.Header().Add("Expires", expires.Format(time.RFC1123)) + _, formatAsPEM := r.URL.Query()["pem"] if formatAsPEM { w.Header().Add("Content-Type", "application/x-pem-file") @@ -22,11 +36,11 @@ func CRL(w http.ResponseWriter, r *http.Request) { _ = pem.Encode(w, &pem.Block{ Type: "X509 CRL", - Bytes: crlBytes, + Bytes: crlInfo.Data, }) } else { w.Header().Add("Content-Type", "application/pkix-crl") w.Header().Add("Content-Disposition", "attachment; filename=\"crl.der\"") - w.Write(crlBytes) + w.Write(crlInfo.Data) } } diff --git a/api/crl_test.go b/api/crl_test.go new file mode 100644 index 00000000..5b194721 --- /dev/null +++ b/api/crl_test.go @@ -0,0 +1,93 @@ +package api + +import ( + "bytes" + "context" + "encoding/pem" + "io" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/go-chi/chi/v5" + "github.com/pkg/errors" + "github.com/smallstep/certificates/authority" + "github.com/smallstep/certificates/errs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_CRL(t *testing.T) { + data := []byte{1, 2, 3, 4} + pemData := pem.EncodeToMemory(&pem.Block{ + Type: "X509 CRL", + Bytes: data, + }) + pemData = bytes.TrimSpace(pemData) + emptyPEMData := pem.EncodeToMemory(&pem.Block{ + Type: "X509 CRL", + Bytes: nil, + }) + emptyPEMData = bytes.TrimSpace(emptyPEMData) + tests := []struct { + name string + url string + err error + statusCode int + crlInfo *authority.CertificateRevocationListInfo + expectedBody []byte + expectedHeaders http.Header + expectedErrorJSON string + }{ + {"ok", "http://example.com/crl", nil, http.StatusOK, &authority.CertificateRevocationListInfo{Data: data}, data, http.Header{"Content-Type": []string{"application/pkix-crl"}, "Content-Disposition": []string{`attachment; filename="crl.der"`}}, ""}, + {"ok/pem", "http://example.com/crl?pem=true", nil, http.StatusOK, &authority.CertificateRevocationListInfo{Data: data}, pemData, http.Header{"Content-Type": []string{"application/x-pem-file"}, "Content-Disposition": []string{`attachment; filename="crl.pem"`}}, ""}, + {"ok/empty", "http://example.com/crl", nil, http.StatusOK, &authority.CertificateRevocationListInfo{Data: nil}, nil, http.Header{"Content-Type": []string{"application/pkix-crl"}, "Content-Disposition": []string{`attachment; filename="crl.der"`}}, ""}, + {"ok/empty-pem", "http://example.com/crl?pem=true", nil, http.StatusOK, &authority.CertificateRevocationListInfo{Data: nil}, emptyPEMData, http.Header{"Content-Type": []string{"application/x-pem-file"}, "Content-Disposition": []string{`attachment; filename="crl.pem"`}}, ""}, + {"fail/internal", "http://example.com/crl", errs.Wrap(http.StatusInternalServerError, errors.New("failure"), "authority.GetCertificateRevocationList"), http.StatusInternalServerError, nil, nil, http.Header{}, `{"status":500,"message":"The certificate authority encountered an Internal Server Error. Please see the certificate authority logs for more info."}`}, + {"fail/nil", "http://example.com/crl", nil, http.StatusNotFound, nil, nil, http.Header{}, `{"status":404,"message":"no CRL available"}`}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockMustAuthority(t, &mockAuthority{ret1: tt.crlInfo, err: tt.err}) + + chiCtx := chi.NewRouteContext() + req := httptest.NewRequest("GET", tt.url, http.NoBody) + req = req.WithContext(context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)) + w := httptest.NewRecorder() + CRL(w, req) + res := w.Result() + + assert.Equal(t, tt.statusCode, res.StatusCode) + + body, err := io.ReadAll(res.Body) + res.Body.Close() + require.NoError(t, err) + + if tt.statusCode >= 300 { + assert.JSONEq(t, tt.expectedErrorJSON, string(bytes.TrimSpace(body))) + return + } + + // check expected header values + for _, h := range []string{"content-type", "content-disposition"} { + v := tt.expectedHeaders.Get(h) + require.NotEmpty(t, v) + + actual := res.Header.Get(h) + assert.Equal(t, v, actual) + } + + // check expires header value + assert.NotEmpty(t, res.Header.Get("expires")) + t1, err := time.Parse(time.RFC1123, res.Header.Get("expires")) + if assert.NoError(t, err) { + assert.False(t, t1.IsZero()) + } + + // check body contents + assert.Equal(t, tt.expectedBody, bytes.TrimSpace(body)) + }) + } +} 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/ssh.go b/api/ssh.go index a07dab29..08294c71 100644 --- a/api/ssh.go +++ b/api/ssh.go @@ -317,7 +317,7 @@ func SSHSign(w http.ResponseWriter, r *http.Request) { var identityCertificate []Certificate if cr := body.IdentityCSR.CertificateRequest; cr != nil { ctx := authority.NewContextWithSkipTokenReuse(r.Context()) - ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod) + ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignIdentityMethod) signOpts, err := a.Authorize(ctx, body.OTT) if err != nil { render.Error(w, errs.UnauthorizedErr(err)) diff --git a/authority/admin/api/acme_test.go b/authority/admin/api/acme_test.go index 420413b7..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" 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 ae9ff83b..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" 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 0686d735..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" 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 1ae1b9de..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" diff --git a/authority/admin/api/webhook.go b/authority/admin/api/webhook.go index 3939d55e..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,9 +56,7 @@ func validateWebhook(webhook *linkedca.Webhook) error { } // kind - switch webhook.Kind { - case linkedca.Webhook_ENRICHING, linkedca.Webhook_AUTHORIZING, linkedca.Webhook_SCEPCHALLENGE: - default: + 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) } diff --git a/authority/admin/api/webhook_test.go b/authority/admin/api/webhook_test.go index ca6b3222..8f4ee1a2 100644 --- a/authority/admin/api/webhook_test.go +++ b/authority/admin/api/webhook_test.go @@ -11,7 +11,7 @@ import ( "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" diff --git a/authority/admin/db.go b/authority/admin/db.go index b331cc0a..b9894457 100644 --- a/authority/admin/db.go +++ b/authority/admin/db.go @@ -92,11 +92,14 @@ func FromContext(ctx context.Context) (db DB, ok bool) { // MustFromContext returns the current admin database from the given context. It // will panic if it's not in the context. func MustFromContext(ctx context.Context) DB { - if db, ok := FromContext(ctx); !ok { + var ( + db DB + ok bool + ) + if db, ok = FromContext(ctx); !ok { panic("admin database is not in the context") - } else { - return db } + return db } // MockDB is an implementation of the DB interface that should only be used as diff --git a/authority/authority.go b/authority/authority.go index ae85c018..c112bc25 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 @@ -101,6 +104,9 @@ type Authority struct { // If true, do not output initialization logs quietInit bool + + // Called whenever applicable, in order to instrument the authority. + meter Meter } // Info contains information about the authority. @@ -122,6 +128,8 @@ func New(cfg *config.Config, opts ...Option) (*Authority, error) { var a = &Authority{ config: cfg, certificates: new(sync.Map), + validateSCEP: true, + meter: noopMeter{}, } // Apply options. @@ -130,6 +138,9 @@ func New(cfg *config.Config, opts ...Option) (*Authority, error) { return nil, err } } + if a.keyManager != nil { + a.keyManager = &instrumentedKeyManager{a.keyManager, a.meter} + } if !a.skipInit { // Initialize authority from options or configuration. @@ -147,6 +158,7 @@ func NewEmbedded(opts ...Option) (*Authority, error) { a := &Authority{ config: &config.Config{}, certificates: new(sync.Map), + meter: noopMeter{}, } // Apply options. @@ -155,6 +167,9 @@ func NewEmbedded(opts ...Option) (*Authority, error) { return nil, err } } + if a.keyManager != nil { + a.keyManager = &instrumentedKeyManager{a.keyManager, a.meter} + } // Validate required options switch { @@ -197,11 +212,14 @@ func FromContext(ctx context.Context) (a *Authority, ok bool) { // MustFromContext returns the current authority from the given context. It will // panic if the authority is not in the context. func MustFromContext(ctx context.Context) *Authority { - if a, ok := FromContext(ctx); !ok { + var ( + a *Authority + ok bool + ) + if a, ok = FromContext(ctx); !ok { panic("authority is not in the context") - } else { - return a } + return a } // ReloadAdminResources reloads admins and provisioners from the DB. @@ -261,6 +279,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 } @@ -312,6 +348,8 @@ func (a *Authority) init() error { if err != nil { return err } + + a.keyManager = &instrumentedKeyManager{a.keyManager, a.meter} } // Initialize linkedca client if necessary. On a linked RA, the issuer @@ -640,48 +678,83 @@ func (a *Authority) init() error { return err } - // 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") + // 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 } - } - // 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 + // provide the current SCEP provisioner names, so that the provisioners + // can be validated when the CA is started. + a.scepOptions.SCEPProvisionerNames = a.getSCEPProvisionerNames() - // 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, - }) + // create a new SCEP authority + scepAuthority, err := scep.New(a, *a.scepOptions) 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 + if a.validateSCEP { + // validate the SCEP authority + if err := scepAuthority.Validate(); err != nil { + a.initLogf("failed validating SCEP authority: %v", err) } } - a.scepService, err = scep.NewService(ctx, options) - if err != nil { - return 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) } - - // TODO: mimick the x509CAService GetCertificateAuthority here too? } // Load X509 constraints engine. @@ -833,17 +906,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 +917,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 1e35afe0..02147687 100644 --- a/authority/authorize.go +++ b/authority/authorize.go @@ -214,7 +214,7 @@ func (a *Authority) Authorize(ctx context.Context, token string) ([]provisioner. var opts = []interface{}{errs.WithKeyVal("token", token)} switch m := provisioner.MethodFromContext(ctx); m { - case provisioner.SignMethod: + case provisioner.SignMethod, provisioner.SignIdentityMethod: signOpts, err := a.authorizeSign(ctx, token) return signOpts, errs.Wrap(http.StatusInternalServerError, err, "authority.Authorize", opts...) case provisioner.RevokeMethod: @@ -286,16 +286,16 @@ func (a *Authority) authorizeRevoke(ctx context.Context, token string) error { // extra extension cannot be found, authorize the renewal by default. // // TODO(mariano): should we authorize by default? -func (a *Authority) authorizeRenew(ctx context.Context, cert *x509.Certificate) error { +func (a *Authority) authorizeRenew(ctx context.Context, cert *x509.Certificate) (provisioner.Interface, error) { serial := cert.SerialNumber.String() var opts = []interface{}{errs.WithKeyVal("serialNumber", serial)} isRevoked, err := a.IsRevoked(serial) if err != nil { - return errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeRenew", opts...) + return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeRenew", opts...) } if isRevoked { - return errs.Unauthorized("authority.authorizeRenew: certificate has been revoked", opts...) + return nil, errs.Unauthorized("authority.authorizeRenew: certificate has been revoked", opts...) } p, err := a.LoadProvisionerByCertificate(cert) if err != nil { @@ -305,13 +305,13 @@ func (a *Authority) authorizeRenew(ctx context.Context, cert *x509.Certificate) // returns the noop provisioner if this happens, and it allows // certificate renewals. if p, ok = a.provisioners.LoadByCertificate(cert); !ok { - return errs.Unauthorized("authority.authorizeRenew: provisioner not found", opts...) + return nil, errs.Unauthorized("authority.authorizeRenew: provisioner not found", opts...) } } if err := p.AuthorizeRenew(ctx, cert); err != nil { - return errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeRenew", opts...) + return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeRenew", opts...) } - return nil + return p, nil } // authorizeSSHCertificate returns an error if the given certificate is revoked. diff --git a/authority/authorize_test.go b/authority/authorize_test.go index bec34fd6..3d748f69 100644 --- a/authority/authorize_test.go +++ b/authority/authorize_test.go @@ -876,7 +876,7 @@ func TestAuthority_authorizeRenew(t *testing.T) { t.Run(name, func(t *testing.T) { tc := genTestCase(t) - err := tc.auth.authorizeRenew(context.Background(), tc.cert) + _, err := tc.auth.authorizeRenew(context.Background(), tc.cert) if err != nil { if assert.NotNil(t, tc.err) { var sc render.StatusCodedError diff --git a/authority/config/config.go b/authority/config/config.go index ba581d8a..ea7ce35d 100644 --- a/authority/config/config.go +++ b/authority/config/config.go @@ -83,6 +83,7 @@ type Config struct { Templates *templates.Templates `json:"templates,omitempty"` CommonName string `json:"commonName,omitempty"` CRL *CRLConfig `json:"crl,omitempty"` + MetricsAddress string `json:"metricsAddress,omitempty"` SkipValidation bool `json:"-"` // Keeps record of the filename the Config is read from @@ -327,6 +328,12 @@ func (c *Config) Validate() error { return errors.Errorf("invalid address %s", c.Address) } + if addr := c.MetricsAddress; addr != "" { + if _, _, err := net.SplitHostPort(addr); err != nil { + return errors.Errorf("invalid metrics address %q", c.Address) + } + } + if c.TLS == nil { c.TLS = &DefaultTLSOptions } else { diff --git a/authority/meter.go b/authority/meter.go new file mode 100644 index 00000000..cccda22a --- /dev/null +++ b/authority/meter.go @@ -0,0 +1,87 @@ +package authority + +import ( + "crypto" + "io" + + "go.step.sm/crypto/kms" + kmsapi "go.step.sm/crypto/kms/apiv1" + + "github.com/smallstep/certificates/authority/provisioner" +) + +// Meter wraps the set of defined callbacks for metrics gatherers. +type Meter interface { + // X509Signed is called whenever an X509 certificate is signed. + X509Signed(provisioner.Interface, error) + + // X509Renewed is called whenever an X509 certificate is renewed. + X509Renewed(provisioner.Interface, error) + + // X509Rekeyed is called whenever an X509 certificate is rekeyed. + X509Rekeyed(provisioner.Interface, error) + + // X509WebhookAuthorized is called whenever an X509 authoring webhook is called. + X509WebhookAuthorized(provisioner.Interface, error) + + // X509WebhookEnriched is called whenever an X509 enriching webhook is called. + X509WebhookEnriched(provisioner.Interface, error) + + // SSHSigned is called whenever an SSH certificate is signed. + SSHSigned(provisioner.Interface, error) + + // SSHRenewed is called whenever an SSH certificate is renewed. + SSHRenewed(provisioner.Interface, error) + + // SSHRekeyed is called whenever an SSH certificate is rekeyed. + SSHRekeyed(provisioner.Interface, error) + + // SSHWebhookAuthorized is called whenever an SSH authoring webhook is called. + SSHWebhookAuthorized(provisioner.Interface, error) + + // SSHWebhookEnriched is called whenever an SSH enriching webhook is called. + SSHWebhookEnriched(provisioner.Interface, error) + + // KMSSigned is called per KMS signer signature. + KMSSigned(error) +} + +// noopMeter implements a noop [Meter]. +type noopMeter struct{} + +func (noopMeter) SSHRekeyed(provisioner.Interface, error) {} +func (noopMeter) SSHRenewed(provisioner.Interface, error) {} +func (noopMeter) SSHSigned(provisioner.Interface, error) {} +func (noopMeter) SSHWebhookAuthorized(provisioner.Interface, error) {} +func (noopMeter) SSHWebhookEnriched(provisioner.Interface, error) {} +func (noopMeter) X509Rekeyed(provisioner.Interface, error) {} +func (noopMeter) X509Renewed(provisioner.Interface, error) {} +func (noopMeter) X509Signed(provisioner.Interface, error) {} +func (noopMeter) X509WebhookAuthorized(provisioner.Interface, error) {} +func (noopMeter) X509WebhookEnriched(provisioner.Interface, error) {} +func (noopMeter) KMSSigned(error) {} + +type instrumentedKeyManager struct { + kms.KeyManager + meter Meter +} + +func (i *instrumentedKeyManager) CreateSigner(req *kmsapi.CreateSignerRequest) (s crypto.Signer, err error) { + if s, err = i.KeyManager.CreateSigner(req); err == nil { + s = &instrumentedKMSSigner{s, i.meter} + } + + return +} + +type instrumentedKMSSigner struct { + crypto.Signer + meter Meter +} + +func (i *instrumentedKMSSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { + signature, err = i.Signer.Sign(rand, digest, opts) + i.meter.KMSSigned(err) + + return +} diff --git a/authority/options.go b/authority/options.go index bf443ed6..55c27321 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. @@ -166,6 +167,15 @@ func WithKeyManager(k kms.KeyManager) Option { } } +// WithX509CAService allows the consumer to provide an externally implemented +// API implementation of apiv1.CertificateAuthorityService +func WithX509CAService(svc casapi.CertificateAuthorityService) Option { + return func(a *Authority) error { + a.x509CAService = svc + return nil + } +} + // WithX509Signer defines the signer used to sign X509 certificates. func WithX509Signer(crt *x509.Certificate, s crypto.Signer) Option { return WithX509SignerChain([]*x509.Certificate{crt}, s) @@ -205,6 +215,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 { @@ -369,3 +390,16 @@ func readCertificateBundle(pemCerts []byte) ([]*x509.Certificate, error) { } return certs, nil } + +// WithMeter is an option that sets the authority's [Meter] to the provided one. +func WithMeter(m Meter) Option { + if m == nil { + m = noopMeter{} + } + + return func(a *Authority) (_ error) { + a.meter = m + + return + } +} diff --git a/authority/policy_test.go b/authority/policy_test.go index 672ca489..bf7a1233 100644 --- a/authority/policy_test.go +++ b/authority/policy_test.go @@ -6,8 +6,8 @@ import ( "reflect" "testing" + "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/assert" - "gopkg.in/square/go-jose.v2" "go.step.sm/linkedca" diff --git a/authority/provisioner/aws.go b/authority/provisioner/aws.go index be641973..e95feedd 100644 --- a/authority/provisioner/aws.go +++ b/authority/provisioner/aws.go @@ -336,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(_ context.Context, token string) ([]SignOption, error) { +func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { payload, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "aws.AuthorizeSign") @@ -363,7 +363,7 @@ func (p *AWS) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro net.ParseIP(doc.PrivateIP), }), emailAddressesValidator(nil), - urisValidator(nil), + newURIsValidator(ctx, nil), ) // Template options diff --git a/authority/provisioner/aws_certificates.pem b/authority/provisioner/aws_certificates.pem index d9b5f639..994758b9 100644 --- a/authority/provisioner/aws_certificates.pem +++ b/authority/provisioner/aws_certificates.pem @@ -1,4 +1,5 @@ # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/verify-signature.html +# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/regions-certs.html use RSA format # default certificate for "other regions" -----BEGIN CERTIFICATE----- @@ -244,4 +245,20 @@ Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4GBACrKjWj460GUPZCGm3/z0dIz M2BPuH769wcOsqfFZcMKEysSFK91tVtUb1soFwH4/Lb/T0PqNrvtEwD1Nva5k0h2 xZhNNRmDuhOhW1K9wCcnHGRBwY5t4lYL6hNV6hcrqYwGMjTjcAjBG2yMgznSNFle Rwi/S3BFXISixNx9cILu +-----END CERTIFICATE----- + +# certificate for ca-west-1 +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAYPou9weMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMjEwMTgwMTM2 +MDlaGA8yMjAxMTAxODAxMzYwOVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK +1kIcG5Q6adBXQM75GldfTSiXl7tn54p10TnspI0ErDdb2B6q2Ji/v4XBVH13ZCMg +qlRHMqV8AWI5iO6gFn2A9sN3AZXTMqwtZeiDdebq3k6Wt7ieYvpXTg0qvgsjQIov +RZWaBDBJy9x8C2hW+w9lMQjFHkJ7Jy/PHCJ69EzebQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAGe9Snkz1A6rHBH6/5kDtYvtPYwhx2sXNxztbhkXErFk40Nw5l459NZx +EeudxJBLoCkkSgYjhRcOZ/gvDVtWG7qyb6fAqgoisyAbk8K9LzxSim2S1nmT9vD8 +4B/t/VvwQBylc+ej8kRxMH7fquZLp7IXfmtBzyUqu6Dpbne+chG2 -----END CERTIFICATE----- \ No newline at end of file diff --git a/authority/provisioner/aws_test.go b/authority/provisioner/aws_test.go index 05f51456..f2485e93 100644 --- a/authority/provisioner/aws_test.go +++ b/authority/provisioner/aws_test.go @@ -695,8 +695,9 @@ func TestAWS_AuthorizeSign(t *testing.T) { assert.Equals(t, []net.IP(v), []net.IP{net.ParseIP("127.0.0.1")}) case emailAddressesValidator: assert.Equals(t, v, nil) - case urisValidator: - assert.Equals(t, v, nil) + case *urisValidator: + assert.Equals(t, v.uris, nil) + assert.Equals(t, MethodFromContext(v.ctx), SignMethod) case dnsNamesValidator: assert.Equals(t, []string(v), []string{"ip-127-0-0-1.us-west-1.compute.internal"}) case *x509NamePolicyValidator: @@ -895,5 +896,5 @@ func TestAWS_HardcodedCertificates(t *testing.T) { assert.True(t, cert.NotAfter.After(time.Now())) certs = append(certs, cert) } - assert.Len(t, 14, certs, "expected 14 certificates in aws_certificates.pem") + assert.Len(t, 15, certs, "expected 15 certificates in aws_certificates.pem") } diff --git a/authority/provisioner/azure.go b/authority/provisioner/azure.go index 76bcebb6..a9d5d1fa 100644 --- a/authority/provisioner/azure.go +++ b/authority/provisioner/azure.go @@ -316,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(_ context.Context, token string) ([]SignOption, error) { +func (p *Azure) AuthorizeSign(ctx 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") @@ -382,7 +382,7 @@ func (p *Azure) AuthorizeSign(_ context.Context, token string) ([]SignOption, er dnsNamesValidator([]string{name}), ipAddressesValidator(nil), emailAddressesValidator(nil), - urisValidator(nil), + newURIsValidator(ctx, nil), ) // Enforce SANs in the template. diff --git a/authority/provisioner/azure_test.go b/authority/provisioner/azure_test.go index 51d46c5a..f262ffbc 100644 --- a/authority/provisioner/azure_test.go +++ b/authority/provisioner/azure_test.go @@ -560,8 +560,9 @@ func TestAzure_AuthorizeSign(t *testing.T) { assert.Equals(t, v, nil) case emailAddressesValidator: assert.Equals(t, v, nil) - case urisValidator: - assert.Equals(t, v, nil) + case *urisValidator: + assert.Equals(t, v.uris, nil) + assert.Equals(t, MethodFromContext(v.ctx), SignMethod) case dnsNamesValidator: assert.Equals(t, []string(v), []string{"virtualMachine"}) case *x509NamePolicyValidator: diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index b6274f8f..2296b1b0 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -223,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(_ context.Context, token string) ([]SignOption, error) { +func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { claims, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSign") @@ -254,7 +254,7 @@ func (p *GCP) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro }), ipAddressesValidator(nil), emailAddressesValidator(nil), - urisValidator(nil), + newURIsValidator(ctx, nil), ) // Template SANs diff --git a/authority/provisioner/gcp_test.go b/authority/provisioner/gcp_test.go index 7705b44a..ef791614 100644 --- a/authority/provisioner/gcp_test.go +++ b/authority/provisioner/gcp_test.go @@ -567,8 +567,9 @@ func TestGCP_AuthorizeSign(t *testing.T) { assert.Equals(t, v, nil) case emailAddressesValidator: assert.Equals(t, v, nil) - case urisValidator: - assert.Equals(t, v, nil) + case *urisValidator: + assert.Equals(t, v.uris, nil) + assert.Equals(t, MethodFromContext(v.ctx), SignMethod) case dnsNamesValidator: assert.Equals(t, []string(v), []string{"instance-name.c.project-id.internal", "instance-name.zone.c.project-id.internal"}) case *x509NamePolicyValidator: diff --git a/authority/provisioner/jwk.go b/authority/provisioner/jwk.go index 6c5ee657..3a7512b8 100644 --- a/authority/provisioner/jwk.go +++ b/authority/provisioner/jwk.go @@ -150,7 +150,7 @@ func (p *JWK) AuthorizeRevoke(_ context.Context, token string) error { } // AuthorizeSign validates the given token. -func (p *JWK) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { +func (p *JWK) AuthorizeSign(ctx 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") @@ -190,9 +190,9 @@ func (p *JWK) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID).WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators - commonNameValidator(claims.Subject), + commonNameSliceValidator(append([]string{claims.Subject}, claims.SANs...)), defaultPublicKeyValidator{}, - defaultSANsValidator(claims.SANs), + newDefaultSANsValidator(ctx, claims.SANs), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newX509NamePolicyValidator(p.ctl.getPolicy().getX509()), p.ctl.newWebhookController(data, linkedca.Webhook_X509), diff --git a/authority/provisioner/jwk_test.go b/authority/provisioner/jwk_test.go index 19cee4fb..794fe1ea 100644 --- a/authority/provisioner/jwk_test.go +++ b/authority/provisioner/jwk_test.go @@ -171,10 +171,10 @@ func TestJWK_authorizeToken(t *testing.T) { {"fail-token", p1, args{failTok}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; error parsing jwk token")}, {"fail-key", p1, args{failKey}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; error parsing jwk claims")}, {"fail-claims", p1, args{failClaims}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; error parsing jwk claims")}, - {"fail-signature", p1, args{failSig}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; error parsing jwk claims: square/go-jose: error in cryptographic primitive")}, - {"fail-issuer", p1, args{failIss}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk claims: square/go-jose/jwt: validation failed, invalid issuer claim (iss)")}, - {"fail-expired", p1, args{failExp}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk claims: square/go-jose/jwt: validation failed, token is expired (exp)")}, - {"fail-not-before", p1, args{failNbf}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk claims: square/go-jose/jwt: validation failed, token not valid yet (nbf)")}, + {"fail-signature", p1, args{failSig}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; error parsing jwk claims: go-jose/go-jose: error in cryptographic primitive")}, + {"fail-issuer", p1, args{failIss}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk claims: go-jose/go-jose/jwt: validation failed, invalid issuer claim (iss)")}, + {"fail-expired", p1, args{failExp}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk claims: go-jose/go-jose/jwt: validation failed, token is expired (exp)")}, + {"fail-not-before", p1, args{failNbf}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk claims: go-jose/go-jose/jwt: validation failed, token not valid yet (nbf)")}, {"fail-audience", p1, args{failAud}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; invalid jwk token audience claim (aud)")}, {"fail-subject", p1, args{failSub}, http.StatusUnauthorized, errors.New("jwk.authorizeToken; jwk token subject cannot be empty")}, {"ok", p1, args{t1}, http.StatusOK, nil}, @@ -218,7 +218,7 @@ func TestJWK_AuthorizeRevoke(t *testing.T) { code int err error }{ - {"fail-signature", p1, args{failSig}, http.StatusUnauthorized, errors.New("jwk.AuthorizeRevoke: jwk.authorizeToken; error parsing jwk claims: square/go-jose: error in cryptographic primitive")}, + {"fail-signature", p1, args{failSig}, http.StatusUnauthorized, errors.New("jwk.AuthorizeRevoke: jwk.authorizeToken; error parsing jwk claims: go-jose/go-jose: error in cryptographic primitive")}, {"ok", p1, args{t1}, http.StatusOK, nil}, } for _, tt := range tests { @@ -266,7 +266,7 @@ func TestJWK_AuthorizeSign(t *testing.T) { prov: p1, args: args{failSig}, code: http.StatusUnauthorized, - err: errors.New("jwk.AuthorizeSign: jwk.authorizeToken; error parsing jwk claims: square/go-jose: error in cryptographic primitive"), + err: errors.New("jwk.AuthorizeSign: jwk.authorizeToken; error parsing jwk claims: go-jose/go-jose: error in cryptographic primitive"), }, { name: "ok-sans", @@ -309,14 +309,15 @@ func TestJWK_AuthorizeSign(t *testing.T) { assert.Len(t, 0, v.KeyValuePairs) case profileDefaultDuration: assert.Equals(t, time.Duration(v), tt.prov.ctl.Claimer.DefaultTLSCertDuration()) - case commonNameValidator: - assert.Equals(t, string(v), "subject") + case commonNameSliceValidator: + assert.Equals(t, []string(v), append([]string{"subject"}, tt.sans...)) case defaultPublicKeyValidator: case *validityValidator: assert.Equals(t, v.min, tt.prov.ctl.Claimer.MinTLSCertDuration()) assert.Equals(t, v.max, tt.prov.ctl.Claimer.MaxTLSCertDuration()) - case defaultSANsValidator: - assert.Equals(t, []string(v), tt.sans) + case *defaultSANsValidator: + assert.Equals(t, v.sans, tt.sans) + assert.Equals(t, MethodFromContext(v.ctx), SignMethod) case *x509NamePolicyValidator: assert.Equals(t, nil, v.policyEngine) case *WebhookController: diff --git a/authority/provisioner/k8sSA_test.go b/authority/provisioner/k8sSA_test.go index 48581c2d..eaf837e0 100644 --- a/authority/provisioner/k8sSA_test.go +++ b/authority/provisioner/k8sSA_test.go @@ -97,7 +97,7 @@ func TestK8sSA_authorizeToken(t *testing.T) { p: p, token: tok, code: http.StatusUnauthorized, - err: errors.New("k8ssa.authorizeToken; invalid k8sSA token claims: square/go-jose/jwt: validation failed, invalid issuer claim (iss)"), + err: errors.New("k8ssa.authorizeToken; invalid k8sSA token claims: go-jose/go-jose/jwt: validation failed, invalid issuer claim (iss)"), } }, "ok": func(t *testing.T) test { diff --git a/authority/provisioner/method.go b/authority/provisioner/method.go index 01dda2ed..19aa6224 100644 --- a/authority/provisioner/method.go +++ b/authority/provisioner/method.go @@ -14,6 +14,8 @@ type methodKey struct{} const ( // SignMethod is the method used to sign X.509 certificates. SignMethod Method = iota + // SignIdentityMethod is the method used to sign X.509 identity certificates. + SignIdentityMethod // RevokeMethod is the method used to revoke X.509 certificates. RevokeMethod // RenewMethod is the method used to renew X.509 certificates. @@ -33,6 +35,8 @@ func (m Method) String() string { switch m { case SignMethod: return "sign-method" + case SignIdentityMethod: + return "sign-identity-method" case RevokeMethod: return "revoke-method" case RenewMethod: diff --git a/authority/provisioner/nebula.go b/authority/provisioner/nebula.go index 6c24bd00..66c523dc 100644 --- a/authority/provisioner/nebula.go +++ b/authority/provisioner/nebula.go @@ -389,7 +389,7 @@ func (v nebulaSANsValidator) Valid(req *x509.CertificateRequest) error { } } if len(req.URIs) > 0 { - if err := urisValidator(uris).Valid(req); err != nil { + if err := newURIsValidator(context.Background(), uris).Valid(req); err != nil { return err } } diff --git a/authority/provisioner/oidc_test.go b/authority/provisioner/oidc_test.go index 9972dc2c..b99f5bb7 100644 --- a/authority/provisioner/oidc_test.go +++ b/authority/provisioner/oidc_test.go @@ -233,11 +233,11 @@ func TestOIDC_authorizeToken(t *testing.T) { {"fail-key", p1, args{failKey}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken; cannot validate oidc token`)}, {"fail-token", p1, args{failTok}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken; error parsing oidc token: invalid character '~' looking for beginning of value`)}, {"fail-claims", p1, args{failClaims}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken; error parsing oidc token claims: invalid character '~' looking for beginning of value`)}, - {"fail-issuer", p1, args{failIss}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: square/go-jose/jwt: validation failed, invalid issuer claim (iss)`)}, - {"fail-audience", p1, args{failAud}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: square/go-jose/jwt: validation failed, invalid audience claim (aud)`)}, + {"fail-issuer", p1, args{failIss}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: go-jose/go-jose/jwt: validation failed, invalid issuer claim (iss)`)}, + {"fail-audience", p1, args{failAud}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: go-jose/go-jose/jwt: validation failed, invalid audience claim (aud)`)}, {"fail-signature", p1, args{failSig}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken; cannot validate oidc token`)}, - {"fail-expired", p1, args{failExp}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: square/go-jose/jwt: validation failed, token is expired (exp)`)}, - {"fail-not-before", p1, args{failNbf}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: square/go-jose/jwt: validation failed, token not valid yet (nbf)`)}, + {"fail-expired", p1, args{failExp}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: go-jose/go-jose/jwt: validation failed, token is expired (exp)`)}, + {"fail-not-before", p1, args{failNbf}, http.StatusUnauthorized, "", errors.New(`oidc.AuthorizeToken: validatePayload: failed to validate oidc token payload: go-jose/go-jose/jwt: validation failed, token not valid yet (nbf)`)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/authority/provisioner/scep.go b/authority/provisioner/scep.go index ff5b28d2..a48d11cc 100644 --- a/authority/provisioner/scep.go +++ b/authority/provisioner/scep.go @@ -2,13 +2,20 @@ 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" @@ -29,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 @@ -41,6 +58,12 @@ type SCEP struct { ctl *Controller 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. @@ -113,7 +136,8 @@ func newChallengeValidationController(client *http.Client, webhooks []*Webhook) } var ( - ErrSCEPChallengeInvalid = errors.New("webhook server did not allow request") + ErrSCEPChallengeInvalid = errors.New("webhook server did not allow request") + ErrSCEPNotificationFailed = errors.New("scep notification failed") ) // Validate executes zero or more configured webhooks to @@ -122,12 +146,15 @@ var ( // 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, challenge, transactionID string) error { +func (c *challengeValidationController) Validate(ctx context.Context, csr *x509.CertificateRequest, provisionerName, challenge, transactionID string) error { for _, wh := range c.webhooks { - req := &webhook.RequestBody{ - SCEPChallenge: challenge, - SCEPTransactionID: transactionID, + req, err := webhook.NewRequestBody(webhook.WithX509CertificateRequest(csr)) + if err != nil { + return fmt.Errorf("failed creating new webhook request: %w", err) } + req.ProvisionerName = provisionerName + 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) @@ -140,6 +167,63 @@ func (c *challengeValidationController) Validate(ctx context.Context, challenge, 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 { @@ -162,21 +246,139 @@ func (s *SCEP) Init(config Config) (err error) { 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) @@ -214,6 +416,15 @@ 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 { @@ -223,13 +434,13 @@ func (s *SCEP) GetContentEncryptionAlgorithm() int { // 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, challenge, transactionID string) error { +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, challenge, transactionID) + return s.challengeValidationController.Validate(ctx, csr, s.Name, challenge, transactionID) default: if subtle.ConstantTimeCompare([]byte(s.ChallengePassword), []byte(challenge)) == 0 { return errors.New("invalid challenge password provided") @@ -238,6 +449,20 @@ func (s *SCEP) ValidateChallenge(ctx context.Context, challenge, transactionID s } } +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 ( @@ -259,3 +484,20 @@ func (s *SCEP) selectValidationMethod() validationMethod { } 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 index acf047fb..2e9f3419 100644 --- a/authority/provisioner/scep_test.go +++ b/authority/provisioner/scep_test.go @@ -2,6 +2,7 @@ package provisioner import ( "context" + "crypto/x509" "encoding/json" "errors" "net/http" @@ -12,12 +13,19 @@ import ( "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 { - Challenge string `json:"scepChallenge"` - TransactionID string `json:"scepTransactionID"` + ProvisionerName string `json:"provisionerName,omitempty"` + Request *webhook.X509CertificateRequest `json:"x509CertificateRequest,omitempty"` + Challenge string `json:"scepChallenge"` + TransactionID string `json:"scepTransactionID"` } type response struct { Allow bool `json:"allow"` @@ -26,6 +34,7 @@ func Test_challengeValidationController_Validate(t *testing.T) { req := &request{} err := json.NewDecoder(r.Body).Decode(req) require.NoError(t, err) + assert.Equal(t, "my-scep-provisioner", req.ProvisionerName) assert.Equal(t, "not-allowed", req.Challenge) assert.Equal(t, "transaction-1", req.TransactionID) b, err := json.Marshal(response{Allow: false}) @@ -37,8 +46,12 @@ func Test_challengeValidationController_Validate(t *testing.T) { req := &request{} err := json.NewDecoder(r.Body).Decode(req) require.NoError(t, err) + assert.Equal(t, "my-scep-provisioner", req.ProvisionerName) 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) @@ -49,8 +62,9 @@ func Test_challengeValidationController_Validate(t *testing.T) { webhooks []*Webhook } type args struct { - challenge string - transactionID string + provisionerName string + challenge string + transactionID string } tests := []struct { name string @@ -62,7 +76,7 @@ func Test_challengeValidationController_Validate(t *testing.T) { { name: "fail/no-webhook", fields: fields{http.DefaultClient, nil}, - args: args{"no-webhook", "transaction-1"}, + args: args{"my-scep-provisioner", "no-webhook", "transaction-1"}, expErr: errors.New("webhook server did not allow request"), }, { @@ -73,7 +87,7 @@ func Test_challengeValidationController_Validate(t *testing.T) { CertType: linkedca.Webhook_SSH.String(), }, }}, - args: args{"wrong-cert-type", "transaction-1"}, + args: args{"my-scep-provisioner", "wrong-cert-type", "transaction-1"}, expErr: errors.New("webhook server did not allow request"), }, { @@ -89,8 +103,9 @@ func Test_challengeValidationController_Validate(t *testing.T) { }, }}, args: args{ - challenge: "wrong-secret-value", - transactionID: "transaction-1", + provisionerName: "my-scep-provisioner", + challenge: "wrong-secret-value", + transactionID: "transaction-1", }, expErr: errors.New("failed executing webhook request: illegal base64 data at input byte 0"), }, @@ -107,8 +122,9 @@ func Test_challengeValidationController_Validate(t *testing.T) { }, }}, args: args{ - challenge: "not-allowed", - transactionID: "transaction-1", + provisionerName: "my-scep-provisioner", + challenge: "not-allowed", + transactionID: "transaction-1", }, server: nokServer, expErr: errors.New("webhook server did not allow request"), @@ -126,8 +142,9 @@ func Test_challengeValidationController_Validate(t *testing.T) { }, }}, args: args{ - challenge: "challenge", - transactionID: "transaction-1", + provisionerName: "my-scep-provisioner", + challenge: "challenge", + transactionID: "transaction-1", }, server: okServer, }, @@ -141,7 +158,7 @@ func Test_challengeValidationController_Validate(t *testing.T) { } ctx := context.Background() - err := c.Validate(ctx, tt.args.challenge, tt.args.transactionID) + err := c.Validate(ctx, dummyCSR, tt.args.provisionerName, tt.args.challenge, tt.args.transactionID) if tt.expErr != nil { assert.EqualError(t, err, tt.expErr.Error()) @@ -221,9 +238,14 @@ func Test_selectValidationMethod(t *testing.T) { } func TestSCEP_ValidateChallenge(t *testing.T) { + dummyCSR := &x509.CertificateRequest{ + Raw: []byte{1}, + } type request struct { - Challenge string `json:"scepChallenge"` - TransactionID string `json:"scepTransactionID"` + ProvisionerName string `json:"provisionerName,omitempty"` + Request *webhook.X509CertificateRequest `json:"x509CertificateRequest,omitempty"` + Challenge string `json:"scepChallenge"` + TransactionID string `json:"scepTransactionID"` } type response struct { Allow bool `json:"allow"` @@ -232,8 +254,12 @@ func TestSCEP_ValidateChallenge(t *testing.T) { req := &request{} err := json.NewDecoder(r.Body).Decode(req) require.NoError(t, err) + assert.Equal(t, "SCEP", req.ProvisionerName) 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) @@ -330,7 +356,7 @@ func TestSCEP_ValidateChallenge(t *testing.T) { require.NoError(t, err) ctx := context.Background() - err = tt.p.ValidateChallenge(ctx, tt.args.challenge, tt.args.transactionID) + err = tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID) if tt.expErr != nil { assert.EqualError(t, err, tt.expErr.Error()) return diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index 782a3598..fec9b9f6 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -1,6 +1,7 @@ package provisioner import ( + "context" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" @@ -233,16 +234,28 @@ func (v emailAddressesValidator) Valid(req *x509.CertificateRequest) error { } // urisValidator validates the URI SANs of a certificate request. -type urisValidator []*url.URL +type urisValidator struct { + ctx context.Context + uris []*url.URL +} + +func newURIsValidator(ctx context.Context, uris []*url.URL) *urisValidator { + return &urisValidator{ctx, uris} +} // Valid checks that certificate request IP Addresses match those configured in // the bootstrap (token) flow. func (v urisValidator) Valid(req *x509.CertificateRequest) error { + // SignIdentityMethod does not need to validate URIs. + if MethodFromContext(v.ctx) == SignIdentityMethod { + return nil + } + if len(req.URIs) == 0 { return nil } want := make(map[string]bool) - for _, u := range v { + for _, u := range v.uris { want[u.String()] = true } got := make(map[string]bool) @@ -250,26 +263,33 @@ func (v urisValidator) Valid(req *x509.CertificateRequest) error { got[u.String()] = true } if !reflect.DeepEqual(want, got) { - return errs.Forbidden("certificate request does not contain the valid URIs - got %v, want %v", req.URIs, v) + return errs.Forbidden("certificate request does not contain the valid URIs - got %v, want %v", req.URIs, v.uris) } return nil } // defaultsSANsValidator stores a set of SANs to eventually validate 1:1 against // the SANs in an x509 certificate request. -type defaultSANsValidator []string +type defaultSANsValidator struct { + ctx context.Context + sans []string +} + +func newDefaultSANsValidator(ctx context.Context, sans []string) *defaultSANsValidator { + return &defaultSANsValidator{ctx, sans} +} // Valid verifies that the SANs stored in the validator match 1:1 with those // requested in the x509 certificate request. func (v defaultSANsValidator) Valid(req *x509.CertificateRequest) (err error) { - dnsNames, ips, emails, uris := x509util.SplitSANs(v) + dnsNames, ips, emails, uris := x509util.SplitSANs(v.sans) if err = dnsNamesValidator(dnsNames).Valid(req); err != nil { return } else if err = emailAddressesValidator(emails).Valid(req); err != nil { return } else if err = ipAddressesValidator(ips).Valid(req); err != nil { return - } else if err = urisValidator(uris).Valid(req); err != nil { + } else if err = newURIsValidator(v.ctx, uris).Valid(req); err != nil { return } return diff --git a/authority/provisioner/sign_options_test.go b/authority/provisioner/sign_options_test.go index e36d051f..5a55aa86 100644 --- a/authority/provisioner/sign_options_test.go +++ b/authority/provisioner/sign_options_test.go @@ -1,6 +1,7 @@ package provisioner import ( + "context" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" @@ -227,23 +228,26 @@ func Test_urisValidator_Valid(t *testing.T) { fu, err := url.Parse("https://unexpected.com") assert.FatalError(t, err) + signContext := NewContextWithMethod(context.Background(), SignMethod) + signIdentityContext := NewContextWithMethod(context.Background(), SignIdentityMethod) + type args struct { req *x509.CertificateRequest } tests := []struct { name string - v urisValidator + v *urisValidator args args wantErr bool }{ - {"ok0", []*url.URL{}, args{&x509.CertificateRequest{URIs: []*url.URL{}}}, false}, - {"ok1", []*url.URL{u1}, args{&x509.CertificateRequest{URIs: []*url.URL{u1}}}, false}, - {"ok2", []*url.URL{u1, u2}, args{&x509.CertificateRequest{URIs: []*url.URL{u2, u1}}}, false}, - {"ok3", []*url.URL{u2, u1, u3}, args{&x509.CertificateRequest{URIs: []*url.URL{u3, u2, u1}}}, false}, - {"ok3", []*url.URL{u2, u1, u3}, args{&x509.CertificateRequest{}}, false}, - {"fail1", []*url.URL{u1}, args{&x509.CertificateRequest{URIs: []*url.URL{u2}}}, true}, - {"fail2", []*url.URL{u1}, args{&x509.CertificateRequest{URIs: []*url.URL{u2, u1}}}, true}, - {"fail3", []*url.URL{u1, u2}, args{&x509.CertificateRequest{URIs: []*url.URL{u1, fu}}}, true}, + {"ok0", newURIsValidator(signContext, []*url.URL{}), args{&x509.CertificateRequest{URIs: []*url.URL{}}}, false}, + {"ok1", newURIsValidator(signContext, []*url.URL{u1}), args{&x509.CertificateRequest{URIs: []*url.URL{u1}}}, false}, + {"ok2", newURIsValidator(signContext, []*url.URL{u1, u2}), args{&x509.CertificateRequest{URIs: []*url.URL{u2, u1}}}, false}, + {"ok3", newURIsValidator(signContext, []*url.URL{u2, u1, u3}), args{&x509.CertificateRequest{URIs: []*url.URL{u3, u2, u1}}}, false}, + {"ok4", newURIsValidator(signIdentityContext, []*url.URL{u1, u2}), args{&x509.CertificateRequest{URIs: []*url.URL{u1, fu}}}, false}, + {"fail1", newURIsValidator(signContext, []*url.URL{u1}), args{&x509.CertificateRequest{URIs: []*url.URL{u2}}}, true}, + {"fail2", newURIsValidator(signContext, []*url.URL{u1}), args{&x509.CertificateRequest{URIs: []*url.URL{u2, u1}}}, true}, + {"fail3", newURIsValidator(signContext, []*url.URL{u1, u2}), args{&x509.CertificateRequest{URIs: []*url.URL{u1, fu}}}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -257,13 +261,19 @@ func Test_urisValidator_Valid(t *testing.T) { func Test_defaultSANsValidator_Valid(t *testing.T) { type test struct { csr *x509.CertificateRequest + ctx context.Context expectedSANs []string err error } + + signContext := NewContextWithMethod(context.Background(), SignMethod) + signIdentityContext := NewContextWithMethod(context.Background(), SignIdentityMethod) + tests := map[string]func() test{ "fail/dnsNamesValidator": func() test { return test{ csr: &x509.CertificateRequest{DNSNames: []string{"foo", "bar"}}, + ctx: signContext, expectedSANs: []string{"foo"}, err: errors.New("certificate request does not contain the valid DNS names"), } @@ -271,6 +281,7 @@ func Test_defaultSANsValidator_Valid(t *testing.T) { "fail/emailAddressesValidator": func() test { return test{ csr: &x509.CertificateRequest{EmailAddresses: []string{"max@fx.com", "mariano@fx.com"}}, + ctx: signContext, expectedSANs: []string{"dcow@fx.com"}, err: errors.New("certificate request does not contain the valid email addresses"), } @@ -278,6 +289,7 @@ func Test_defaultSANsValidator_Valid(t *testing.T) { "fail/ipAddressesValidator": func() test { return test{ csr: &x509.CertificateRequest{IPAddresses: []net.IP{net.ParseIP("1.1.1.1"), net.ParseIP("127.0.0.1")}}, + ctx: signContext, expectedSANs: []string{"127.0.0.1"}, err: errors.New("certificate request does not contain the valid IP addresses"), } @@ -289,16 +301,29 @@ func Test_defaultSANsValidator_Valid(t *testing.T) { assert.FatalError(t, err) return test{ csr: &x509.CertificateRequest{URIs: []*url.URL{u1, u2}}, + ctx: signContext, expectedSANs: []string{"urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959"}, err: errors.New("certificate request does not contain the valid URIs"), } }, + "ok/urisBadValidator-SignIdentity": func() test { + u1, err := url.Parse("https://google.com") + assert.FatalError(t, err) + u2, err := url.Parse("urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959") + assert.FatalError(t, err) + return test{ + csr: &x509.CertificateRequest{URIs: []*url.URL{u1, u2}}, + ctx: signIdentityContext, + expectedSANs: []string{"urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959"}, + } + }, "ok": func() test { u1, err := url.Parse("https://google.com") assert.FatalError(t, err) u2, err := url.Parse("urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959") assert.FatalError(t, err) return test{ + ctx: signContext, csr: &x509.CertificateRequest{ DNSNames: []string{"foo", "bar"}, EmailAddresses: []string{"max@fx.com", "mariano@fx.com"}, @@ -312,7 +337,7 @@ func Test_defaultSANsValidator_Valid(t *testing.T) { for name, run := range tests { t.Run(name, func(t *testing.T) { tt := run() - if err := defaultSANsValidator(tt.expectedSANs).Valid(tt.csr); err != nil { + if err := newDefaultSANsValidator(tt.ctx, tt.expectedSANs).Valid(tt.csr); err != nil { if assert.NotNil(t, tt.err, fmt.Sprintf("expected no error, but got err = %s", err.Error())) { assert.True(t, strings.Contains(err.Error(), tt.err.Error()), fmt.Sprintf("want err = %s, but got err = %s", tt.err.Error(), err.Error())) diff --git a/authority/provisioner/webhook.go b/authority/provisioner/webhook.go index 1cc2047c..c33dfa23 100644 --- a/authority/provisioner/webhook.go +++ b/authority/provisioner/webhook.go @@ -180,7 +180,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 cc79a09b..0ce3f36d 100644 --- a/authority/provisioner/webhook_test.go +++ b/authority/provisioner/webhook_test.go @@ -484,7 +484,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 b6e78697..9b1f2b08 100644 --- a/authority/provisioner/x5c.go +++ b/authority/provisioner/x5c.go @@ -194,7 +194,7 @@ func (p *X5C) AuthorizeRevoke(_ context.Context, token string) error { } // AuthorizeSign validates the given token. -func (p *X5C) AuthorizeSign(_ context.Context, token string) ([]SignOption, error) { +func (p *X5C) AuthorizeSign(ctx 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") @@ -244,7 +244,7 @@ func (p *X5C) AuthorizeSign(_ context.Context, token string) ([]SignOption, erro }, // validators commonNameValidator(claims.Subject), - defaultSANsValidator(claims.SANs), + newDefaultSANsValidator(ctx, claims.SANs), defaultPublicKeyValidator{}, newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newX509NamePolicyValidator(p.ctl.getPolicy().getX509()), diff --git a/authority/provisioner/x5c_test.go b/authority/provisioner/x5c_test.go index f9a2604b..22545446 100644 --- a/authority/provisioner/x5c_test.go +++ b/authority/provisioner/x5c_test.go @@ -460,7 +460,8 @@ func TestX5C_AuthorizeSign(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { tc := tt(t) - if opts, err := tc.p.AuthorizeSign(context.Background(), tc.token); err != nil { + ctx := NewContextWithMethod(context.Background(), SignIdentityMethod) + if opts, err := tc.p.AuthorizeSign(ctx, tc.token); err != nil { if assert.NotNil(t, tc.err) { var sc render.StatusCodedError if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") { @@ -489,8 +490,9 @@ func TestX5C_AuthorizeSign(t *testing.T) { case commonNameValidator: assert.Equals(t, string(v), "foo") case defaultPublicKeyValidator: - case defaultSANsValidator: - assert.Equals(t, []string(v), tc.sans) + case *defaultSANsValidator: + assert.Equals(t, v.sans, tc.sans) + assert.Equals(t, MethodFromContext(v.ctx), SignIdentityMethod) case *validityValidator: assert.Equals(t, v.min, tc.p.ctl.Claimer.MinTLSCertDuration()) assert.Equals(t, v.max, tc.p.ctl.Claimer.MaxTLSCertDuration()) diff --git a/authority/provisioners.go b/authority/provisioners.go index 0d38f667..551411de 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -10,7 +10,6 @@ import ( "os" "github.com/pkg/errors" - "gopkg.in/square/go-jose.v2/jwt" "go.step.sm/cli-utils/step" "go.step.sm/cli-utils/ui" @@ -146,7 +145,7 @@ func (a *Authority) unsafeLoadProvisionerFromDatabase(crt *x509.Certificate) (pr // LoadProvisionerByToken returns an interface to the provisioner that // provisioned the token. -func (a *Authority) LoadProvisionerByToken(token *jwt.JSONWebToken, claims *jwt.Claims) (provisioner.Interface, error) { +func (a *Authority) LoadProvisionerByToken(token *jose.JSONWebToken, claims *jose.Claims) (provisioner.Interface, error) { a.adminMutex.RLock() defer a.adminMutex.RUnlock() p, ok := a.provisioners.LoadByToken(token, claims) @@ -235,7 +234,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. @@ -974,7 +973,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, @@ -982,11 +981,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() { @@ -1241,7 +1248,14 @@ func ProvisionerToLinkedca(p provisioner.Interface) (*linkedca.Provisioner, erro 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/ssh.go b/authority/ssh.go index 688bfd76..26e8eebc 100644 --- a/authority/ssh.go +++ b/authority/ssh.go @@ -147,6 +147,12 @@ 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) { + cert, prov, err := a.signSSH(ctx, key, opts, signOpts...) + a.meter.SSHSigned(prov, err) + return cert, err +} + +func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, provisioner.Interface, error) { var ( certOptions []sshutil.Option mods []provisioner.SSHCertModifier @@ -155,7 +161,7 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi // Validate given options. if err := opts.Validate(); err != nil { - return nil, err + return nil, nil, err } // Set backdate with the configured value @@ -184,7 +190,7 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi // validate the given SSHOptions case provisioner.SSHCertOptionsValidator: if err := o.Valid(opts); err != nil { - return nil, errs.BadRequestErr(err, "error validating ssh certificate options") + return nil, prov, errs.BadRequestErr(err, "error validating ssh certificate options") } // call webhooks @@ -192,7 +198,7 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi webhookCtl = o default: - return nil, errs.InternalServer("authority.SignSSH: invalid extra option type %T", o) + return nil, prov, errs.InternalServer("authority.SignSSH: invalid extra option type %T", o) } } @@ -205,8 +211,8 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi } // Call enriching webhooks - if err := callEnrichingWebhooksSSH(ctx, webhookCtl, cr); err != nil { - return nil, errs.ApplyOptions( + if err := a.callEnrichingWebhooksSSH(ctx, prov, webhookCtl, cr); err != nil { + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, err.Error()), errs.WithKeyVal("signOptions", signOpts), ) @@ -216,20 +222,21 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi certificate, err := sshutil.NewCertificate(cr, certOptions...) if err != nil { var te *sshutil.TemplateError - if errors.As(err, &te) { - return nil, errs.ApplyOptions( + switch { + case errors.As(err, &te): + return nil, prov, errs.ApplyOptions( errs.BadRequestErr(err, err.Error()), errs.WithKeyVal("signOptions", signOpts), ) - } - // explicitly check for unmarshaling errors, which are most probably caused by JSON template syntax errors - if strings.HasPrefix(err.Error(), "error unmarshaling certificate") { - return nil, errs.InternalServerErr(templatingError(err), + case strings.HasPrefix(err.Error(), "error unmarshaling certificate"): + // explicitly check for unmarshaling errors, which are most probably caused by JSON template syntax errors + return nil, prov, errs.InternalServerErr(templatingError(err), errs.WithKeyVal("signOptions", signOpts), errs.WithMessage("error applying certificate template"), ) + default: + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH") } - return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH") } // Get actual *ssh.Certificate and continue with provisioner modifiers. @@ -238,13 +245,13 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi // Use SignSSHOptions to modify the certificate validity. It will be later // checked or set if not defined. if err := opts.ModifyValidity(certTpl); err != nil { - return nil, errs.BadRequestErr(err, err.Error()) + return nil, prov, errs.BadRequestErr(err, err.Error()) } // Use provisioner modifiers. for _, m := range mods { if err := m.Modify(certTpl, opts); err != nil { - return nil, errs.ForbiddenErr(err, "error creating ssh certificate") + return nil, prov, errs.ForbiddenErr(err, "error creating ssh certificate") } } @@ -253,32 +260,32 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi switch certTpl.CertType { case ssh.UserCert: if a.sshCAUserCertSignKey == nil { - return nil, errs.NotImplemented("authority.SignSSH: user certificate signing is not enabled") + return nil, prov, errs.NotImplemented("authority.SignSSH: user certificate signing is not enabled") } signer = a.sshCAUserCertSignKey case ssh.HostCert: if a.sshCAHostCertSignKey == nil { - return nil, errs.NotImplemented("authority.SignSSH: host certificate signing is not enabled") + return nil, prov, errs.NotImplemented("authority.SignSSH: host certificate signing is not enabled") } signer = a.sshCAHostCertSignKey default: - return nil, errs.InternalServer("authority.SignSSH: unexpected ssh certificate type: %d", certTpl.CertType) + return nil, prov, errs.InternalServer("authority.SignSSH: unexpected ssh certificate type: %d", certTpl.CertType) } // Check if authority is allowed to sign the certificate if err := a.isAllowedToSignSSHCertificate(certTpl); err != nil { var ee *errs.Error if errors.As(err, &ee) { - return nil, ee + return nil, prov, ee } - return nil, errs.InternalServerErr(err, + return nil, prov, errs.InternalServerErr(err, errs.WithMessage("authority.SignSSH: error creating ssh certificate"), ) } // Send certificate to webhooks for authorization - if err := callAuthorizingWebhooksSSH(ctx, webhookCtl, certificate, certTpl); err != nil { - return nil, errs.ApplyOptions( + if err := a.callAuthorizingWebhooksSSH(ctx, prov, webhookCtl, certificate, certTpl); err != nil { + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "authority.SignSSH: error signing certificate"), ) } @@ -286,21 +293,21 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi // Sign certificate. cert, err := sshutil.CreateCertificate(certTpl, signer) if err != nil { - return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH: error signing certificate") + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH: error signing certificate") } // User provisioners validators. for _, v := range validators { if err := v.Valid(cert, opts); err != nil { - return nil, errs.ForbiddenErr(err, "error validating ssh certificate") + return nil, prov, errs.ForbiddenErr(err, "error validating ssh certificate") } } - if err = a.storeSSHCertificate(prov, cert); err != nil && !errors.Is(err, db.ErrNotImplemented) { - return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH: error storing certificate in db") + if err := a.storeSSHCertificate(prov, cert); err != nil && !errors.Is(err, db.ErrNotImplemented) { + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH: error storing certificate in db") } - return cert, nil + return cert, prov, nil } // isAllowedToSignSSHCertificate checks if the Authority is allowed to sign the SSH certificate. @@ -310,12 +317,18 @@ func (a *Authority) isAllowedToSignSSHCertificate(cert *ssh.Certificate) error { // RenewSSH creates a signed SSH certificate using the old SSH certificate as a template. func (a *Authority) RenewSSH(ctx context.Context, oldCert *ssh.Certificate) (*ssh.Certificate, error) { + cert, prov, err := a.renewSSH(ctx, oldCert) + a.meter.SSHRenewed(prov, err) + return cert, err +} + +func (a *Authority) renewSSH(ctx context.Context, oldCert *ssh.Certificate) (*ssh.Certificate, provisioner.Interface, error) { if oldCert.ValidAfter == 0 || oldCert.ValidBefore == 0 { - return nil, errs.BadRequest("cannot renew a certificate without validity period") + return nil, nil, errs.BadRequest("cannot renew a certificate without validity period") } if err := a.authorizeSSHCertificate(ctx, oldCert); err != nil { - return nil, err + return nil, nil, err } // Attempt to extract the provisioner from the token. @@ -348,36 +361,41 @@ func (a *Authority) RenewSSH(ctx context.Context, oldCert *ssh.Certificate) (*ss switch certTpl.CertType { case ssh.UserCert: if a.sshCAUserCertSignKey == nil { - return nil, errs.NotImplemented("renewSSH: user certificate signing is not enabled") + return nil, prov, errs.NotImplemented("renewSSH: user certificate signing is not enabled") } signer = a.sshCAUserCertSignKey case ssh.HostCert: if a.sshCAHostCertSignKey == nil { - return nil, errs.NotImplemented("renewSSH: host certificate signing is not enabled") + return nil, prov, errs.NotImplemented("renewSSH: host certificate signing is not enabled") } signer = a.sshCAHostCertSignKey default: - return nil, errs.InternalServer("renewSSH: unexpected ssh certificate type: %d", certTpl.CertType) + return nil, prov, errs.InternalServer("renewSSH: unexpected ssh certificate type: %d", certTpl.CertType) } // Sign certificate. cert, err := sshutil.CreateCertificate(certTpl, signer) if err != nil { - return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate") + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate") } - if err = a.storeRenewedSSHCertificate(prov, oldCert, cert); err != nil && !errors.Is(err, db.ErrNotImplemented) { - return nil, errs.Wrap(http.StatusInternalServerError, err, "renewSSH: error storing certificate in db") + if err := a.storeRenewedSSHCertificate(prov, oldCert, cert); err != nil && !errors.Is(err, db.ErrNotImplemented) { + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "renewSSH: error storing certificate in db") } - return cert, nil + return cert, prov, nil } // RekeySSH creates a signed SSH certificate using the old SSH certificate as a template. func (a *Authority) RekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { - var validators []provisioner.SSHCertValidator + cert, prov, err := a.rekeySSH(ctx, oldCert, pub, signOpts...) + a.meter.SSHRekeyed(prov, err) + return cert, err +} +func (a *Authority) rekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub ssh.PublicKey, signOpts ...provisioner.SignOption) (*ssh.Certificate, provisioner.Interface, error) { var prov provisioner.Interface + var validators []provisioner.SSHCertValidator for _, op := range signOpts { switch o := op.(type) { // Capture current provisioner @@ -387,16 +405,16 @@ func (a *Authority) RekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub case provisioner.SSHCertValidator: validators = append(validators, o) default: - return nil, errs.InternalServer("rekeySSH; invalid extra option type %T", o) + return nil, prov, errs.InternalServer("rekeySSH; invalid extra option type %T", o) } } if oldCert.ValidAfter == 0 || oldCert.ValidBefore == 0 { - return nil, errs.BadRequest("cannot rekey a certificate without validity period") + return nil, prov, errs.BadRequest("cannot rekey a certificate without validity period") } if err := a.authorizeSSHCertificate(ctx, oldCert); err != nil { - return nil, err + return nil, prov, err } backdate := a.config.AuthorityConfig.Backdate.Duration @@ -423,37 +441,37 @@ func (a *Authority) RekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub switch cert.CertType { case ssh.UserCert: if a.sshCAUserCertSignKey == nil { - return nil, errs.NotImplemented("rekeySSH; user certificate signing is not enabled") + return nil, prov, errs.NotImplemented("rekeySSH; user certificate signing is not enabled") } signer = a.sshCAUserCertSignKey case ssh.HostCert: if a.sshCAHostCertSignKey == nil { - return nil, errs.NotImplemented("rekeySSH; host certificate signing is not enabled") + return nil, prov, errs.NotImplemented("rekeySSH; host certificate signing is not enabled") } signer = a.sshCAHostCertSignKey default: - return nil, errs.BadRequest("unexpected certificate type '%d'", cert.CertType) + return nil, prov, errs.BadRequest("unexpected certificate type '%d'", cert.CertType) } var err error // Sign certificate. cert, err = sshutil.CreateCertificate(cert, signer) if err != nil { - return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate") + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate") } // Apply validators from provisioner. for _, v := range validators { if err := v.Valid(cert, provisioner.SignSSHOptions{Backdate: backdate}); err != nil { - return nil, errs.ForbiddenErr(err, "error validating ssh certificate") + return nil, prov, errs.ForbiddenErr(err, "error validating ssh certificate") } } - if err = a.storeRenewedSSHCertificate(prov, oldCert, cert); err != nil && !errors.Is(err, db.ErrNotImplemented) { - return nil, errs.Wrap(http.StatusInternalServerError, err, "rekeySSH; error storing certificate in db") + if err := a.storeRenewedSSHCertificate(prov, oldCert, cert); err != nil && !errors.Is(err, db.ErrNotImplemented) { + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "rekeySSH; error storing certificate in db") } - return cert, nil + return cert, prov, nil } func (a *Authority) storeSSHCertificate(prov provisioner.Interface, cert *ssh.Certificate) error { @@ -653,28 +671,36 @@ func (a *Authority) getAddUserCommand(principal string) string { return strings.ReplaceAll(cmd, "", principal) } -func callEnrichingWebhooksSSH(ctx context.Context, webhookCtl webhookController, cr sshutil.CertificateRequest) error { +func (a *Authority) callEnrichingWebhooksSSH(ctx context.Context, prov provisioner.Interface, webhookCtl webhookController, cr sshutil.CertificateRequest) (err error) { if webhookCtl == nil { - return nil + return } - whEnrichReq, err := webhook.NewRequestBody( + + var whEnrichReq *webhook.RequestBody + if whEnrichReq, err = webhook.NewRequestBody( webhook.WithSSHCertificateRequest(cr), - ) - if err != nil { - return err + ); err == nil { + err = webhookCtl.Enrich(ctx, whEnrichReq) + + a.meter.SSHWebhookEnriched(prov, err) } - return webhookCtl.Enrich(ctx, whEnrichReq) + + return } -func callAuthorizingWebhooksSSH(ctx context.Context, webhookCtl webhookController, cert *sshutil.Certificate, certTpl *ssh.Certificate) error { +func (a *Authority) callAuthorizingWebhooksSSH(ctx context.Context, prov provisioner.Interface, webhookCtl webhookController, cert *sshutil.Certificate, certTpl *ssh.Certificate) (err error) { if webhookCtl == nil { - return nil + return } - whAuthBody, err := webhook.NewRequestBody( + + var whAuthBody *webhook.RequestBody + if whAuthBody, err = webhook.NewRequestBody( webhook.WithSSHCertificate(cert, certTpl), - ) - if err != nil { - return err + ); err == nil { + err = webhookCtl.Authorize(ctx, whAuthBody) + + a.meter.SSHWebhookAuthorized(prov, err) } - return webhookCtl.Authorize(ctx, whAuthBody) + + return } diff --git a/authority/tls.go b/authority/tls.go index 900b1ff8..082513c8 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -99,9 +99,15 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Sign return a.SignWithContext(context.Background(), csr, signOpts, extraOpts...) } -// SignWithContext creates a signed certificate from a certificate signing request, -// taking the provided context.Context. +// SignWithContext creates a signed certificate from a certificate signing +// request, taking the provided context.Context. func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRequest, signOpts provisioner.SignOptions, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { + chain, prov, err := a.signX509(ctx, csr, signOpts, extraOpts...) + a.meter.X509Signed(prov, err) + return chain, err +} + +func (a *Authority) signX509(ctx context.Context, csr *x509.CertificateRequest, signOpts provisioner.SignOptions, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, provisioner.Interface, error) { var ( certOptions []x509util.Option certValidators []provisioner.CertificateValidator @@ -109,9 +115,9 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe certEnforcers []provisioner.CertificateEnforcer ) - opts := []interface{}{errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts)} + opts := []any{errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts)} if err := csr.CheckSignature(); err != nil { - return nil, errs.ApplyOptions( + return nil, nil, errs.ApplyOptions( errs.BadRequestErr(err, "invalid certificate request"), opts..., ) @@ -120,10 +126,12 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe // Set backdate with the configured value signOpts.Backdate = a.config.AuthorityConfig.Backdate.Duration - var prov provisioner.Interface - var pInfo *casapi.ProvisionerInfo - var attData *provisioner.AttestationData - var webhookCtl webhookController + var ( + prov provisioner.Interface + pInfo *casapi.ProvisionerInfo + attData *provisioner.AttestationData + webhookCtl webhookController + ) for _, op := range extraOpts { switch k := op.(type) { // Capture current provisioner @@ -141,8 +149,8 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe // Validate the given certificate request. case provisioner.CertificateRequestValidator: if err := k.Valid(csr); err != nil { - return nil, errs.ApplyOptions( - errs.ForbiddenErr(err, "error validating certificate"), + return nil, prov, errs.ApplyOptions( + errs.ForbiddenErr(err, "error validating certificate request"), opts..., ) } @@ -168,45 +176,46 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe webhookCtl = k default: - return nil, errs.InternalServer("authority.Sign; invalid extra option type %T", append([]interface{}{k}, opts...)...) + return nil, prov, errs.InternalServer("authority.Sign; invalid extra option type %T", append([]any{k}, opts...)...) } } - if err := callEnrichingWebhooksX509(ctx, webhookCtl, attData, csr); err != nil { - return nil, errs.ApplyOptions( + if err := a.callEnrichingWebhooksX509(ctx, prov, webhookCtl, attData, csr); err != nil { + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, err.Error()), errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts), ) } - cert, err := x509util.NewCertificate(csr, certOptions...) + crt, err := x509util.NewCertificate(csr, certOptions...) if err != nil { var te *x509util.TemplateError - if errors.As(err, &te) { - return nil, errs.ApplyOptions( + switch { + case errors.As(err, &te): + return nil, prov, errs.ApplyOptions( errs.BadRequestErr(err, err.Error()), errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts), ) - } - // explicitly check for unmarshaling errors, which are most probably caused by JSON template (syntax) errors - if strings.HasPrefix(err.Error(), "error unmarshaling certificate") { - return nil, errs.InternalServerErr(templatingError(err), + case strings.HasPrefix(err.Error(), "error unmarshaling certificate"): + // explicitly check for unmarshaling errors, which are most probably caused by JSON template (syntax) errors + return nil, prov, errs.InternalServerErr(templatingError(err), errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts), errs.WithMessage("error applying certificate template"), ) + default: + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign", opts...) } - return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign", opts...) } // Certificate modifiers before validation - leaf := cert.GetCertificate() + leaf := crt.GetCertificate() // Set default subject if err := withDefaultASN1DN(a.config.AuthorityConfig.Template).Modify(leaf, signOpts); err != nil { - return nil, errs.ApplyOptions( + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "error creating certificate"), opts..., ) @@ -214,7 +223,7 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe for _, m := range certModifiers { if err := m.Modify(leaf, signOpts); err != nil { - return nil, errs.ApplyOptions( + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "error creating certificate"), opts..., ) @@ -224,7 +233,7 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe // Certificate validation. for _, v := range certValidators { if err := v.Valid(leaf, signOpts); err != nil { - return nil, errs.ApplyOptions( + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "error validating certificate"), opts..., ) @@ -233,8 +242,8 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe // Certificate modifiers after validation for _, m := range certEnforcers { - if err := m.Enforce(leaf); err != nil { - return nil, errs.ApplyOptions( + if err = m.Enforce(leaf); err != nil { + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "error creating certificate"), opts..., ) @@ -243,8 +252,8 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe // Process injected modifiers after validation for _, m := range a.x509Enforcers { - if err := m.Enforce(leaf); err != nil { - return nil, errs.ApplyOptions( + if err = m.Enforce(leaf); err != nil { + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "error creating certificate"), opts..., ) @@ -252,12 +261,12 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe } // Check if authority is allowed to sign the certificate - if err := a.isAllowedToSignX509Certificate(leaf); err != nil { + if err = a.isAllowedToSignX509Certificate(leaf); err != nil { var ee *errs.Error if errors.As(err, &ee) { - return nil, errs.ApplyOptions(ee, opts...) + return nil, prov, errs.ApplyOptions(ee, opts...) } - return nil, errs.InternalServerErr(err, + return nil, prov, errs.InternalServerErr(err, errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts), errs.WithMessage("error creating certificate"), @@ -265,8 +274,8 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe } // Send certificate to webhooks for authorization - if err := callAuthorizingWebhooksX509(ctx, webhookCtl, cert, leaf, attData); err != nil { - return nil, errs.ApplyOptions( + if err := a.callAuthorizingWebhooksX509(ctx, prov, webhookCtl, crt, leaf, attData); err != nil { + return nil, prov, errs.ApplyOptions( errs.ForbiddenErr(err, "error creating certificate"), opts..., ) @@ -274,6 +283,7 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe // Sign certificate lifetime := leaf.NotAfter.Sub(leaf.NotBefore.Add(signOpts.Backdate)) + resp, err := a.x509CAService.CreateCertificate(&casapi.CreateCertificateRequest{ Template: leaf, CSR: csr, @@ -282,23 +292,22 @@ func (a *Authority) SignWithContext(ctx context.Context, csr *x509.CertificateRe Provisioner: pInfo, }) if err != nil { - return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign; error creating certificate", opts...) + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign; error creating certificate", opts...) } - fullchain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...) + chain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...) - // Wrap provisioner with extra information. - prov = wrapProvisioner(prov, attData) + // Wrap provisioner with extra information, if not nil + if prov != nil { + prov = wrapProvisioner(prov, attData) + } // Store certificate in the db. - if err = a.storeCertificate(prov, fullchain); err != nil { - if !errors.Is(err, db.ErrNotImplemented) { - return nil, errs.Wrap(http.StatusInternalServerError, err, - "authority.Sign; error storing certificate in db", opts...) - } + if err := a.storeCertificate(prov, chain); err != nil && !errors.Is(err, db.ErrNotImplemented) { + return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign; error storing certificate in db", opts...) } - return fullchain, nil + return chain, prov, nil } // isAllowedToSignX509Certificate checks if the Authority is allowed @@ -346,14 +355,25 @@ func (a *Authority) Rekey(oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x5 // of rekey), and 'NotBefore/NotAfter' (the validity duration of the new // certificate should be equal to the old one, but starting 'now'). func (a *Authority) RenewContext(ctx context.Context, oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error) { + chain, prov, err := a.renewContext(ctx, oldCert, pk) + if pk == nil { + a.meter.X509Renewed(prov, err) + } else { + a.meter.X509Rekeyed(prov, err) + } + return chain, err +} + +func (a *Authority) renewContext(ctx context.Context, oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, provisioner.Interface, error) { isRekey := (pk != nil) opts := []errs.Option{ errs.WithKeyVal("serialNumber", oldCert.SerialNumber.String()), } // Check step provisioner extensions - if err := a.authorizeRenew(ctx, oldCert); err != nil { - return nil, errs.StatusCodeError(http.StatusInternalServerError, err, opts...) + prov, err := a.authorizeRenew(ctx, oldCert) + if err != nil { + return nil, prov, errs.StatusCodeError(http.StatusInternalServerError, err, opts...) } // Durations @@ -423,15 +443,17 @@ func (a *Authority) RenewContext(ctx context.Context, oldCert *x509.Certificate, // // TODO(hslatman,maraino): consider adding policies too and consider if // RenewSSH should check policies. - if err := a.constraintsEngine.ValidateCertificate(newCert); err != nil { + if err = a.constraintsEngine.ValidateCertificate(newCert); err != nil { var ee *errs.Error - if errors.As(err, &ee) { - return nil, errs.StatusCodeError(ee.StatusCode(), err, opts...) + switch { + case errors.As(err, &ee): + return nil, prov, errs.StatusCodeError(ee.StatusCode(), err, opts...) + default: + return nil, prov, errs.InternalServerErr(err, + errs.WithKeyVal("serialNumber", oldCert.SerialNumber.String()), + errs.WithMessage("error renewing certificate"), + ) } - return nil, errs.InternalServerErr(err, - errs.WithKeyVal("serialNumber", oldCert.SerialNumber.String()), - errs.WithMessage("error renewing certificate"), - ) } // The token can optionally be in the context. If the CA is running in RA @@ -445,17 +467,16 @@ func (a *Authority) RenewContext(ctx context.Context, oldCert *x509.Certificate, Token: token, }) if err != nil { - return nil, errs.StatusCodeError(http.StatusInternalServerError, err, opts...) + return nil, prov, errs.StatusCodeError(http.StatusInternalServerError, err, opts...) } - fullchain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...) - if err = a.storeRenewedCertificate(oldCert, fullchain); err != nil { - if !errors.Is(err, db.ErrNotImplemented) { - return nil, errs.StatusCodeError(http.StatusInternalServerError, err, opts...) - } + chain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...) + + if err = a.storeRenewedCertificate(oldCert, chain); err != nil && !errors.Is(err, db.ErrNotImplemented) { + return nil, prov, errs.StatusCodeError(http.StatusInternalServerError, err, opts...) } - return fullchain, nil + return chain, prov, nil } // storeCertificate allows to use an extension of the db.AuthDB interface that @@ -684,9 +705,17 @@ func (a *Authority) revokeSSH(crt *ssh.Certificate, rci *db.RevokedCertificateIn return a.db.RevokeSSH(rci) } +// CertificateRevocationListInfo contains a CRL in DER format and associated metadata. +type CertificateRevocationListInfo struct { + Number int64 + ExpiresAt time.Time + Duration time.Duration + Data []byte +} + // GetCertificateRevocationList will return the currently generated CRL from the DB, or a not implemented // error if the underlying AuthDB does not support CRLs -func (a *Authority) GetCertificateRevocationList() ([]byte, error) { +func (a *Authority) GetCertificateRevocationList() (*CertificateRevocationListInfo, error) { if !a.config.CRL.IsEnabled() { return nil, errs.Wrap(http.StatusNotFound, errors.Errorf("Certificate Revocation Lists are not enabled"), "authority.GetCertificateRevocationList") } @@ -701,7 +730,12 @@ func (a *Authority) GetCertificateRevocationList() ([]byte, error) { return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.GetCertificateRevocationList") } - return crlInfo.DER, nil + return &CertificateRevocationListInfo{ + Number: crlInfo.Number, + ExpiresAt: crlInfo.ExpiresAt, + Duration: crlInfo.Duration, + Data: crlInfo.DER, + }, nil } // GenerateCertificateRevocationList generates a DER representation of a signed CRL and stores it in the @@ -961,42 +995,52 @@ func templatingError(err error) error { return errors.Wrap(cause, "error applying certificate template") } -func callEnrichingWebhooksX509(ctx context.Context, webhookCtl webhookController, attData *provisioner.AttestationData, csr *x509.CertificateRequest) error { +func (a *Authority) callEnrichingWebhooksX509(ctx context.Context, prov provisioner.Interface, webhookCtl webhookController, attData *provisioner.AttestationData, csr *x509.CertificateRequest) (err error) { if webhookCtl == nil { - return nil + return } + var attested *webhook.AttestationData if attData != nil { attested = &webhook.AttestationData{ PermanentIdentifier: attData.PermanentIdentifier, } } - whEnrichReq, err := webhook.NewRequestBody( + + var whEnrichReq *webhook.RequestBody + if whEnrichReq, err = webhook.NewRequestBody( webhook.WithX509CertificateRequest(csr), webhook.WithAttestationData(attested), - ) - if err != nil { - return err + ); err == nil { + err = webhookCtl.Enrich(ctx, whEnrichReq) + + a.meter.X509WebhookEnriched(prov, err) } - return webhookCtl.Enrich(ctx, whEnrichReq) + + return } -func callAuthorizingWebhooksX509(ctx context.Context, webhookCtl webhookController, cert *x509util.Certificate, leaf *x509.Certificate, attData *provisioner.AttestationData) error { +func (a *Authority) callAuthorizingWebhooksX509(ctx context.Context, prov provisioner.Interface, webhookCtl webhookController, cert *x509util.Certificate, leaf *x509.Certificate, attData *provisioner.AttestationData) (err error) { if webhookCtl == nil { - return nil + return } + var attested *webhook.AttestationData if attData != nil { attested = &webhook.AttestationData{ PermanentIdentifier: attData.PermanentIdentifier, } } - whAuthBody, err := webhook.NewRequestBody( + + var whAuthBody *webhook.RequestBody + if whAuthBody, err = webhook.NewRequestBody( webhook.WithX509Certificate(cert, leaf), webhook.WithAttestationData(attested), - ) - if err != nil { - return err + ); err == nil { + err = webhookCtl.Authorize(ctx, whAuthBody) + + a.meter.X509WebhookAuthorized(prov, err) } - return webhookCtl.Authorize(ctx, whAuthBody) + + return } diff --git a/authority/tls_test.go b/authority/tls_test.go index efcb78f8..1fb8411a 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -24,7 +24,7 @@ import ( "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x509util" - "github.com/smallstep/assert" + sassert "github.com/smallstep/assert" "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/policy" @@ -33,6 +33,8 @@ import ( "github.com/smallstep/certificates/db" "github.com/smallstep/certificates/errs" "github.com/smallstep/nosql/database" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var ( @@ -80,25 +82,25 @@ func generateCertificate(t *testing.T, commonName string, sans []string, opts .. t.Helper() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - assert.FatalError(t, err) + require.NoError(t, err) cr, err := x509util.CreateCertificateRequest(commonName, sans, priv) - assert.FatalError(t, err) + require.NoError(t, err) template, err := x509util.NewCertificate(cr) - assert.FatalError(t, err) + require.NoError(t, err) cert := template.GetCertificate() for _, m := range opts { switch m := m.(type) { case provisioner.CertificateModifierFunc: err = m.Modify(cert, provisioner.SignOptions{}) - assert.FatalError(t, err) + require.NoError(t, err) case signerFunc: cert, err = m(cert, priv.Public()) - assert.FatalError(t, err) + require.NoError(t, err) default: - t.Fatalf("unknown type %T", m) + require.Fail(t, "", "unknown type %T", m) } } @@ -108,36 +110,36 @@ func generateCertificate(t *testing.T, commonName string, sans []string, opts .. func generateRootCertificate(t *testing.T) (*x509.Certificate, crypto.Signer) { t.Helper() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - assert.FatalError(t, err) + require.NoError(t, err) cr, err := x509util.CreateCertificateRequest("TestRootCA", nil, priv) - assert.FatalError(t, err) + require.NoError(t, err) data := x509util.CreateTemplateData("TestRootCA", nil) template, err := x509util.NewCertificate(cr, x509util.WithTemplate(x509util.DefaultRootTemplate, data)) - assert.FatalError(t, err) + require.NoError(t, err) cert := template.GetCertificate() cert, err = x509util.CreateCertificate(cert, cert, priv.Public(), priv) - assert.FatalError(t, err) + require.NoError(t, err) return cert, priv } func generateIntermidiateCertificate(t *testing.T, issuer *x509.Certificate, signer crypto.Signer) (*x509.Certificate, crypto.Signer) { t.Helper() priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - assert.FatalError(t, err) + require.NoError(t, err) cr, err := x509util.CreateCertificateRequest("TestIntermediateCA", nil, priv) - assert.FatalError(t, err) + require.NoError(t, err) data := x509util.CreateTemplateData("TestIntermediateCA", nil) template, err := x509util.NewCertificate(cr, x509util.WithTemplate(x509util.DefaultRootTemplate, data)) - assert.FatalError(t, err) + require.NoError(t, err) cert := template.GetCertificate() cert, err = x509util.CreateCertificate(cert, issuer, priv.Public(), signer) - assert.FatalError(t, err) + require.NoError(t, err) return cert, priv } @@ -192,9 +194,9 @@ func getCSR(t *testing.T, priv interface{}, opts ...func(*x509.CertificateReques opt(_csr) } csrBytes, err := x509.CreateCertificateRequest(rand.Reader, _csr, priv) - assert.FatalError(t, err) + require.NoError(t, err) csr, err := x509.ParseCertificateRequest(csrBytes) - assert.FatalError(t, err) + require.NoError(t, err) return csr } @@ -239,10 +241,10 @@ func (e *testEnforcer) Enforce(cert *x509.Certificate) error { func TestAuthority_Sign(t *testing.T) { pub, priv, err := keyutil.GenerateDefaultKeyPair() - assert.FatalError(t, err) + require.NoError(t, err) a := testAuthority(t) - assert.FatalError(t, err) + require.NoError(t, err) a.config.AuthorityConfig.Template = &ASN1DN{ Country: "Tazmania", Organization: "Acme Co", @@ -262,12 +264,12 @@ func TestAuthority_Sign(t *testing.T) { // Create a token to get test extra opts. p := a.config.AuthorityConfig.Provisioners[1].(*provisioner.JWK) 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) extraOpts, err := a.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) type signTest struct { auth *Authority @@ -372,9 +374,9 @@ W5kR63lNVHBHgQmv5mA8YFsfrJHstaz5k727v2LMHEYIf5/3i16d5zhuxUoaPTYr ZYtQ9Ot36qc= -----END CERTIFICATE REQUEST-----` block, _ := pem.Decode([]byte(shortRSAKeyPEM)) - assert.FatalError(t, err) + require.NoError(t, err) csr, err := x509.ParseCertificateRequest(block.Bytes) - assert.FatalError(t, err) + require.NoError(t, err) return &signTest{ auth: a, @@ -413,10 +415,10 @@ ZYtQ9Ot36qc= X509: &provisioner.X509Options{Template: `{{ fail "fail message" }}`}, } testExtraOpts, err := testAuthority.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) testAuthority.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -442,10 +444,10 @@ ZYtQ9Ot36qc= }, } testExtraOpts, err := testAuthority.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) testAuthority.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -471,10 +473,10 @@ ZYtQ9Ot36qc= }, } testExtraOpts, err := testAuthority.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) testAuthority.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -492,7 +494,7 @@ ZYtQ9Ot36qc= aa := testAuthority(t) aa.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -517,7 +519,7 @@ ZYtQ9Ot36qc= })) aa.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -537,7 +539,7 @@ ZYtQ9Ot36qc= aa.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { fmt.Println(crt.Subject) - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -549,7 +551,7 @@ ZYtQ9Ot36qc= }, } engine, err := policy.New(options) - assert.FatalError(t, err) + require.NoError(t, err) aa.policyEngine = engine return &signTest{ auth: aa, @@ -598,7 +600,7 @@ ZYtQ9Ot36qc= _a := testAuthority(t) _a.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -617,7 +619,7 @@ ZYtQ9Ot36qc= bcExt.Id = asn1.ObjectIdentifier{2, 5, 29, 19} bcExt.Critical = false bcExt.Value, err = asn1.Marshal(basicConstraints{IsCA: true, MaxPathLen: 4}) - assert.FatalError(t, err) + require.NoError(t, err) csr := getCSR(t, priv, setExtraExtsCSR([]pkix.Extension{ bcExt, @@ -632,7 +634,7 @@ ZYtQ9Ot36qc= _a := testAuthority(t) _a.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -663,10 +665,10 @@ ZYtQ9Ot36qc= }`}, } testExtraOpts, err := testAuthority.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) testAuthority.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -697,10 +699,10 @@ ZYtQ9Ot36qc= }`}, } testExtraOpts, err := testAuthority.Authorize(ctx, token) - assert.FatalError(t, err) + require.NoError(t, err) testAuthority.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -737,7 +739,7 @@ ZYtQ9Ot36qc= _a.config.AuthorityConfig.Template = &ASN1DN{} _a.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject, pkix.Name{}) + sassert.Equals(t, crt.Subject, pkix.Name{}) return nil }, } @@ -762,8 +764,8 @@ ZYtQ9Ot36qc= aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template aa.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") - assert.Equals(t, crt.CRLDistributionPoints, []string{"http://ca.example.org/leaf.crl"}) + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.CRLDistributionPoints, []string{"http://ca.example.org/leaf.crl"}) return nil }, } @@ -783,7 +785,7 @@ ZYtQ9Ot36qc= aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template aa.db = &db.MockAuthDB{ MStoreCertificate: func(crt *x509.Certificate) error { - assert.Equals(t, crt.Subject.CommonName, "smallstep test") + sassert.Equals(t, crt.Subject.CommonName, "smallstep test") return nil }, } @@ -796,7 +798,7 @@ ZYtQ9Ot36qc= }, } engine, err := policy.New(options) - assert.FatalError(t, err) + require.NoError(t, err) aa.policyEngine = engine return &signTest{ auth: aa, @@ -816,13 +818,13 @@ ZYtQ9Ot36qc= MStoreCertificateChain: func(prov provisioner.Interface, certs ...*x509.Certificate) error { p, ok := prov.(attProvisioner) if assert.True(t, ok) { - assert.Equals(t, &provisioner.AttestationData{ + sassert.Equals(t, &provisioner.AttestationData{ PermanentIdentifier: "1234567890", }, p.AttestationData()) } - if assert.Len(t, 2, certs) { - assert.Equals(t, certs[0].Subject.CommonName, "smallstep test") - assert.Equals(t, certs[1].Subject.CommonName, "smallstep Intermediate CA") + if assert.Len(t, certs, 2) { + sassert.Equals(t, certs[0].Subject.CommonName, "smallstep test") + sassert.Equals(t, certs[1].Subject.CommonName, "smallstep Intermediate CA") } return nil }, @@ -851,26 +853,26 @@ ZYtQ9Ot36qc= if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) { assert.Nil(t, certChain) var sc render.StatusCodedError - assert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") - assert.Equals(t, sc.StatusCode(), tc.code) - assert.HasPrefix(t, err.Error(), tc.err.Error()) + sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") + sassert.Equals(t, sc.StatusCode(), tc.code) + sassert.HasPrefix(t, err.Error(), tc.err.Error()) var ctxErr *errs.Error - assert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") - assert.Equals(t, ctxErr.Details["csr"], tc.csr) - assert.Equals(t, ctxErr.Details["signOptions"], tc.signOpts) + sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") + sassert.Equals(t, ctxErr.Details["csr"], tc.csr) + sassert.Equals(t, ctxErr.Details["signOptions"], tc.signOpts) } } else { leaf := certChain[0] intermediate := certChain[1] if assert.Nil(t, tc.err) { - assert.Equals(t, leaf.NotBefore, tc.notBefore) - assert.Equals(t, leaf.NotAfter, tc.notAfter) + sassert.Equals(t, leaf.NotBefore, tc.notBefore) + sassert.Equals(t, leaf.NotAfter, tc.notAfter) tmplt := a.config.AuthorityConfig.Template if tc.csr.Subject.CommonName == "" { - assert.Equals(t, leaf.Subject, pkix.Name{}) + sassert.Equals(t, leaf.Subject, pkix.Name{}) } else { - assert.Equals(t, leaf.Subject.String(), + sassert.Equals(t, leaf.Subject.String(), pkix.Name{ Country: []string{tmplt.Country}, Organization: []string{tmplt.Organization}, @@ -879,18 +881,18 @@ ZYtQ9Ot36qc= Province: []string{tmplt.Province}, CommonName: "smallstep test", }.String()) - assert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com"}) + sassert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com"}) } - assert.Equals(t, leaf.Issuer, intermediate.Subject) - assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) - assert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA) - assert.Equals(t, leaf.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) + sassert.Equals(t, leaf.Issuer, intermediate.Subject) + sassert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) + sassert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA) + sassert.Equals(t, leaf.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) issuer := getDefaultIssuer(a) subjectKeyID, err := generateSubjectKeyID(pub) - assert.FatalError(t, err) - assert.Equals(t, leaf.SubjectKeyId, subjectKeyID) - assert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId) + require.NoError(t, err) + sassert.Equals(t, leaf.SubjectKeyId, subjectKeyID) + sassert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId) // Verify Provisioner OID found := 0 @@ -900,18 +902,18 @@ ZYtQ9Ot36qc= found++ val := stepProvisionerASN1{} _, err := asn1.Unmarshal(ext.Value, &val) - assert.FatalError(t, err) - assert.Equals(t, val.Type, provisionerTypeJWK) - assert.Equals(t, val.Name, []byte(p.Name)) - assert.Equals(t, val.CredentialID, []byte(p.Key.KeyID)) + require.NoError(t, err) + sassert.Equals(t, val.Type, provisionerTypeJWK) + sassert.Equals(t, val.Name, []byte(p.Name)) + sassert.Equals(t, val.CredentialID, []byte(p.Key.KeyID)) // Basic Constraints case ext.Id.Equal(asn1.ObjectIdentifier([]int{2, 5, 29, 19})): val := basicConstraints{} _, err := asn1.Unmarshal(ext.Value, &val) - assert.FatalError(t, err) + require.NoError(t, err) assert.False(t, val.IsCA, false) - assert.Equals(t, val.MaxPathLen, 0) + sassert.Equals(t, val.MaxPathLen, 0) // SAN extension case ext.Id.Equal(asn1.ObjectIdentifier([]int{2, 5, 29, 17})): @@ -922,11 +924,11 @@ ZYtQ9Ot36qc= } } } - assert.Equals(t, found, 1) + sassert.Equals(t, found, 1) realIntermediate, err := x509.ParseCertificate(issuer.Raw) - assert.FatalError(t, err) - assert.Equals(t, intermediate, realIntermediate) - assert.Len(t, tc.extensionsCount, leaf.Extensions) + require.NoError(t, err) + sassert.Equals(t, intermediate, realIntermediate) + assert.Len(t, leaf.Extensions, tc.extensionsCount) } } }) @@ -1056,7 +1058,7 @@ func TestAuthority_Renew(t *testing.T) { for name, genTestCase := range tests { t.Run(name, func(t *testing.T) { tc, err := genTestCase() - assert.FatalError(t, err) + require.NoError(t, err) var certChain []*x509.Certificate if tc.auth != nil { @@ -1068,19 +1070,19 @@ func TestAuthority_Renew(t *testing.T) { if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) { assert.Nil(t, certChain) var sc render.StatusCodedError - assert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") - assert.Equals(t, sc.StatusCode(), tc.code) - assert.HasPrefix(t, err.Error(), tc.err.Error()) + sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") + sassert.Equals(t, sc.StatusCode(), tc.code) + sassert.HasPrefix(t, err.Error(), tc.err.Error()) var ctxErr *errs.Error - assert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") - assert.Equals(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String()) + sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") + sassert.Equals(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String()) } } else { leaf := certChain[0] intermediate := certChain[1] if assert.Nil(t, tc.err) { - assert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore)) + sassert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore)) assert.True(t, leaf.NotBefore.After(now.Add(-2*time.Minute))) assert.True(t, leaf.NotBefore.Before(now.Add(time.Minute))) @@ -1090,30 +1092,30 @@ func TestAuthority_Renew(t *testing.T) { assert.True(t, leaf.NotAfter.Before(expiry.Add(time.Hour))) tmplt := a.config.AuthorityConfig.Template - assert.Equals(t, leaf.RawSubject, tc.cert.RawSubject) - assert.Equals(t, leaf.Subject.Country, []string{tmplt.Country}) - assert.Equals(t, leaf.Subject.Organization, []string{tmplt.Organization}) - assert.Equals(t, leaf.Subject.Locality, []string{tmplt.Locality}) - assert.Equals(t, leaf.Subject.StreetAddress, []string{tmplt.StreetAddress}) - assert.Equals(t, leaf.Subject.Province, []string{tmplt.Province}) - assert.Equals(t, leaf.Subject.CommonName, tmplt.CommonName) - - assert.Equals(t, leaf.Issuer, intermediate.Subject) - - assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) - assert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA) - assert.Equals(t, leaf.ExtKeyUsage, + sassert.Equals(t, leaf.RawSubject, tc.cert.RawSubject) + sassert.Equals(t, leaf.Subject.Country, []string{tmplt.Country}) + sassert.Equals(t, leaf.Subject.Organization, []string{tmplt.Organization}) + sassert.Equals(t, leaf.Subject.Locality, []string{tmplt.Locality}) + sassert.Equals(t, leaf.Subject.StreetAddress, []string{tmplt.StreetAddress}) + sassert.Equals(t, leaf.Subject.Province, []string{tmplt.Province}) + sassert.Equals(t, leaf.Subject.CommonName, tmplt.CommonName) + + sassert.Equals(t, leaf.Issuer, intermediate.Subject) + + sassert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) + sassert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA) + sassert.Equals(t, leaf.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) - assert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com", "test"}) + sassert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com", "test"}) subjectKeyID, err := generateSubjectKeyID(leaf.PublicKey) - assert.FatalError(t, err) - assert.Equals(t, leaf.SubjectKeyId, subjectKeyID) + require.NoError(t, err) + sassert.Equals(t, leaf.SubjectKeyId, subjectKeyID) // We did not change the intermediate before renewing. authIssuer := getDefaultIssuer(tc.auth) if issuer.SerialNumber == authIssuer.SerialNumber { - assert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId) + sassert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId) // Compare extensions: they can be in a different order for _, ext1 := range tc.cert.Extensions { //skip SubjectKeyIdentifier @@ -1133,7 +1135,7 @@ func TestAuthority_Renew(t *testing.T) { } } else { // We did change the intermediate before renewing. - assert.Equals(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId) + sassert.Equals(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId) // Compare extensions: they can be in a different order for _, ext1 := range tc.cert.Extensions { //skip SubjectKeyIdentifier @@ -1161,8 +1163,8 @@ func TestAuthority_Renew(t *testing.T) { } realIntermediate, err := x509.ParseCertificate(authIssuer.Raw) - assert.FatalError(t, err) - assert.Equals(t, intermediate, realIntermediate) + require.NoError(t, err) + sassert.Equals(t, intermediate, realIntermediate) } } }) @@ -1171,7 +1173,7 @@ func TestAuthority_Renew(t *testing.T) { func TestAuthority_Rekey(t *testing.T) { pub, _, err := keyutil.GenerateDefaultKeyPair() - assert.FatalError(t, err) + require.NoError(t, err) a := testAuthority(t) a.config.AuthorityConfig.Template = &ASN1DN{ @@ -1261,7 +1263,7 @@ func TestAuthority_Rekey(t *testing.T) { for name, genTestCase := range tests { t.Run(name, func(t *testing.T) { tc, err := genTestCase() - assert.FatalError(t, err) + require.NoError(t, err) var certChain []*x509.Certificate if tc.auth != nil { @@ -1273,19 +1275,19 @@ func TestAuthority_Rekey(t *testing.T) { if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) { assert.Nil(t, certChain) var sc render.StatusCodedError - assert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") - assert.Equals(t, sc.StatusCode(), tc.code) - assert.HasPrefix(t, err.Error(), tc.err.Error()) + sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") + sassert.Equals(t, sc.StatusCode(), tc.code) + sassert.HasPrefix(t, err.Error(), tc.err.Error()) var ctxErr *errs.Error - assert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") - assert.Equals(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String()) + sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") + sassert.Equals(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String()) } } else { leaf := certChain[0] intermediate := certChain[1] if assert.Nil(t, tc.err) { - assert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore)) + sassert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore)) assert.True(t, leaf.NotBefore.After(now.Add(-2*time.Minute))) assert.True(t, leaf.NotBefore.Before(now.Add(time.Minute))) @@ -1295,7 +1297,7 @@ func TestAuthority_Rekey(t *testing.T) { assert.True(t, leaf.NotAfter.Before(expiry.Add(time.Hour))) tmplt := a.config.AuthorityConfig.Template - assert.Equals(t, leaf.Subject.String(), + sassert.Equals(t, leaf.Subject.String(), pkix.Name{ Country: []string{tmplt.Country}, Organization: []string{tmplt.Organization}, @@ -1304,32 +1306,32 @@ func TestAuthority_Rekey(t *testing.T) { Province: []string{tmplt.Province}, CommonName: tmplt.CommonName, }.String()) - assert.Equals(t, leaf.Issuer, intermediate.Subject) + sassert.Equals(t, leaf.Issuer, intermediate.Subject) - assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) - assert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA) - assert.Equals(t, leaf.ExtKeyUsage, + sassert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) + sassert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA) + sassert.Equals(t, leaf.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) - assert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com", "test"}) + sassert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com", "test"}) // Test Public Key and SubjectKeyId expectedPK := tc.pk if tc.pk == nil { expectedPK = cert.PublicKey } - assert.Equals(t, leaf.PublicKey, expectedPK) + sassert.Equals(t, leaf.PublicKey, expectedPK) subjectKeyID, err := generateSubjectKeyID(expectedPK) - assert.FatalError(t, err) - assert.Equals(t, leaf.SubjectKeyId, subjectKeyID) + require.NoError(t, err) + sassert.Equals(t, leaf.SubjectKeyId, subjectKeyID) if tc.pk == nil { - assert.Equals(t, leaf.SubjectKeyId, cert.SubjectKeyId) + sassert.Equals(t, leaf.SubjectKeyId, cert.SubjectKeyId) } // We did not change the intermediate before renewing. authIssuer := getDefaultIssuer(tc.auth) if issuer.SerialNumber == authIssuer.SerialNumber { - assert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId) + sassert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId) // Compare extensions: they can be in a different order for _, ext1 := range tc.cert.Extensions { //skip SubjectKeyIdentifier @@ -1349,7 +1351,7 @@ func TestAuthority_Rekey(t *testing.T) { } } else { // We did change the intermediate before renewing. - assert.Equals(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId) + sassert.Equals(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId) // Compare extensions: they can be in a different order for _, ext1 := range tc.cert.Extensions { //skip SubjectKeyIdentifier @@ -1377,8 +1379,8 @@ func TestAuthority_Rekey(t *testing.T) { } realIntermediate, err := x509.ParseCertificate(authIssuer.Raw) - assert.FatalError(t, err) - assert.Equals(t, intermediate, realIntermediate) + require.NoError(t, err) + sassert.Equals(t, intermediate, realIntermediate) } } }) @@ -1413,10 +1415,10 @@ func TestAuthority_GetTLSOptions(t *testing.T) { for name, genTestCase := range tests { t.Run(name, func(t *testing.T) { tc, err := genTestCase() - assert.FatalError(t, err) + require.NoError(t, err) opts := tc.auth.GetTLSOptions() - assert.Equals(t, opts, tc.opts) + sassert.Equals(t, opts, tc.opts) }) } } @@ -1429,11 +1431,11 @@ func TestAuthority_Revoke(t *testing.T) { now := time.Now().UTC() jwk, err := jose.ReadKey("testdata/secrets/step_cli_key_priv.jwk", jose.WithPassword([]byte("pass"))) - assert.FatalError(t, err) + require.NoError(t, err) sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, (&jose.SignerOptions{}).WithType("JWT").WithHeader("kid", jwk.KeyID)) - assert.FatalError(t, err) + require.NoError(t, err) a := testAuthority(t) @@ -1472,7 +1474,7 @@ func TestAuthority_Revoke(t *testing.T) { ID: "44", } raw, err := jose.Signed(sig).Claims(cl).CompactSerialize() - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: a, @@ -1486,9 +1488,9 @@ func TestAuthority_Revoke(t *testing.T) { err: errors.New("authority.Revoke; no persistence layer configured"), code: http.StatusNotImplemented, checkErrDetails: func(err *errs.Error) { - assert.Equals(t, err.Details["token"], raw) - assert.Equals(t, err.Details["tokenID"], "44") - assert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc") + sassert.Equals(t, err.Details["token"], raw) + sassert.Equals(t, err.Details["tokenID"], "44") + sassert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc") }, } }, @@ -1512,7 +1514,7 @@ func TestAuthority_Revoke(t *testing.T) { ID: "44", } raw, err := jose.Signed(sig).Claims(cl).CompactSerialize() - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: _a, @@ -1526,9 +1528,9 @@ func TestAuthority_Revoke(t *testing.T) { err: errors.New("authority.Revoke: force"), code: http.StatusInternalServerError, checkErrDetails: func(err *errs.Error) { - assert.Equals(t, err.Details["token"], raw) - assert.Equals(t, err.Details["tokenID"], "44") - assert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc") + sassert.Equals(t, err.Details["token"], raw) + sassert.Equals(t, err.Details["tokenID"], "44") + sassert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc") }, } }, @@ -1552,7 +1554,7 @@ func TestAuthority_Revoke(t *testing.T) { ID: "44", } raw, err := jose.Signed(sig).Claims(cl).CompactSerialize() - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: _a, @@ -1566,9 +1568,9 @@ func TestAuthority_Revoke(t *testing.T) { err: errors.New("certificate with serial number 'sn' is already revoked"), code: http.StatusBadRequest, checkErrDetails: func(err *errs.Error) { - assert.Equals(t, err.Details["token"], raw) - assert.Equals(t, err.Details["tokenID"], "44") - assert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc") + sassert.Equals(t, err.Details["token"], raw) + sassert.Equals(t, err.Details["tokenID"], "44") + sassert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc") }, } }, @@ -1591,7 +1593,7 @@ func TestAuthority_Revoke(t *testing.T) { ID: "44", } raw, err := jose.Signed(sig).Claims(cl).CompactSerialize() - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: _a, ctx: tlsRevokeCtx, @@ -1607,7 +1609,7 @@ func TestAuthority_Revoke(t *testing.T) { _a := testAuthority(t, WithDatabase(&db.MockAuthDB{})) crt, err := pemutil.ReadCertificate("./testdata/certs/foo.crt") - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: _a, @@ -1625,7 +1627,7 @@ func TestAuthority_Revoke(t *testing.T) { _a := testAuthority(t, WithDatabase(&db.MockAuthDB{})) crt, err := pemutil.ReadCertificate("./testdata/certs/foo.crt") - assert.FatalError(t, err) + require.NoError(t, err) // Filter out provisioner extension. for i, ext := range crt.Extensions { if ext.Id.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 37476, 9000, 64, 1}) { @@ -1650,7 +1652,7 @@ func TestAuthority_Revoke(t *testing.T) { _a := testAuthority(t, WithDatabase(&db.MockAuthDB{})) crt, err := pemutil.ReadCertificate("./testdata/certs/foo.crt") - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: _a, @@ -1683,7 +1685,7 @@ func TestAuthority_Revoke(t *testing.T) { ID: "44", } raw, err := jose.Signed(sig).Claims(cl).CompactSerialize() - assert.FatalError(t, err) + require.NoError(t, err) return test{ auth: a, ctx: provisioner.NewContextWithMethod(context.Background(), provisioner.SSHRevokeMethod), @@ -1702,17 +1704,17 @@ func TestAuthority_Revoke(t *testing.T) { if err := tc.auth.Revoke(tc.ctx, tc.opts); err != nil { if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) { var sc render.StatusCodedError - assert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") - assert.Equals(t, sc.StatusCode(), tc.code) - assert.HasPrefix(t, err.Error(), tc.err.Error()) + sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") + sassert.Equals(t, sc.StatusCode(), tc.code) + sassert.HasPrefix(t, err.Error(), tc.err.Error()) var ctxErr *errs.Error - assert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") - assert.Equals(t, ctxErr.Details["serialNumber"], tc.opts.Serial) - assert.Equals(t, ctxErr.Details["reasonCode"], tc.opts.ReasonCode) - assert.Equals(t, ctxErr.Details["reason"], tc.opts.Reason) - assert.Equals(t, ctxErr.Details["MTLS"], tc.opts.MTLS) - assert.Equals(t, ctxErr.Details["context"], provisioner.RevokeMethod.String()) + sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error") + sassert.Equals(t, ctxErr.Details["serialNumber"], tc.opts.Serial) + sassert.Equals(t, ctxErr.Details["reasonCode"], tc.opts.ReasonCode) + sassert.Equals(t, ctxErr.Details["reason"], tc.opts.Reason) + sassert.Equals(t, ctxErr.Details["MTLS"], tc.opts.MTLS) + sassert.Equals(t, ctxErr.Details["context"], provisioner.RevokeMethod.String()) if tc.checkErrDetails != nil { tc.checkErrDetails(ctxErr) @@ -1814,13 +1816,11 @@ func TestAuthority_CRL(t *testing.T) { validIssuer := "step-cli" validAudience := testAudiences.Revoke now := time.Now().UTC() - // jwk, err := jose.ReadKey("testdata/secrets/step_cli_key_priv.jwk", jose.WithPassword([]byte("pass"))) - assert.FatalError(t, err) - // + require.NoError(t, err) sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, (&jose.SignerOptions{}).WithType("JWT").WithHeader("kid", jwk.KeyID)) - assert.FatalError(t, err) + require.NoError(t, err) crlCtx := provisioner.NewContextWithMethod(context.Background(), provisioner.RevokeMethod) @@ -1865,7 +1865,7 @@ func TestAuthority_CRL(t *testing.T) { auth: a, ctx: crlCtx, expected: nil, - err: database.ErrNotFound, + err: errors.New("authority.GetCertificateRevocationList: not found"), } }, "ok/crl-full": func() test { @@ -1910,7 +1910,7 @@ func TestAuthority_CRL(t *testing.T) { ID: sn, } raw, err := jose.Signed(sig).Claims(cl).CompactSerialize() - assert.FatalError(t, err) + require.NoError(t, err) err = a.Revoke(crlCtx, &RevokeOptions{ Serial: sn, ReasonCode: reasonCode, @@ -1918,7 +1918,7 @@ func TestAuthority_CRL(t *testing.T) { OTT: raw, }) - assert.FatalError(t, err) + require.NoError(t, err) ex = append(ex, sn) } @@ -1933,22 +1933,22 @@ func TestAuthority_CRL(t *testing.T) { for name, f := range tests { tc := f() t.Run(name, func(t *testing.T) { - if crlBytes, err := tc.auth.GetCertificateRevocationList(); err == nil { - crl, parseErr := x509.ParseRevocationList(crlBytes) - if parseErr != nil { - t.Errorf("x509.ParseCertificateRequest() error = %v, wantErr %v", parseErr, nil) - return - } + crlInfo, err := tc.auth.GetCertificateRevocationList() + if tc.err != nil { + assert.EqualError(t, err, tc.err.Error()) + assert.Nil(t, crlInfo) + return + } - var cmpList []string - for _, c := range crl.RevokedCertificates { - cmpList = append(cmpList, c.SerialNumber.String()) - } + crl, parseErr := x509.ParseRevocationList(crlInfo.Data) + require.NoError(t, parseErr) - assert.Equals(t, cmpList, tc.expected) - } else { - assert.NotNil(t, tc.err, err.Error()) + var cmpList []string + for _, c := range crl.RevokedCertificateEntries { + cmpList = append(cmpList, c.SerialNumber.String()) } + + assert.Equal(t, tc.expected, cmpList) }) } } diff --git a/ca/acmeClient.go b/ca/acmeClient.go index 1c195efd..bb3b1d84 100644 --- a/ca/acmeClient.go +++ b/ca/acmeClient.go @@ -176,7 +176,7 @@ func (c *ACMEClient) post(payload []byte, url string, headerOps ...withHeaderOpt } signed, err := signer.Sign(payload) if err != nil { - return nil, errors.Errorf("error signing payload: %s", strings.TrimPrefix(err.Error(), "square/go-jose: ")) + return nil, errors.Errorf("error signing payload: %s", jose.TrimPrefix(err)) } raw, err := serialize(signed) if err != nil { diff --git a/ca/ca.go b/ca/ca.go index b8f65332..4146466d 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" @@ -26,7 +26,9 @@ import ( "github.com/smallstep/certificates/authority/admin" adminAPI "github.com/smallstep/certificates/authority/admin/api" "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/cas/apiv1" "github.com/smallstep/certificates/db" + "github.com/smallstep/certificates/internal/metrix" "github.com/smallstep/certificates/logging" "github.com/smallstep/certificates/monitoring" "github.com/smallstep/certificates/scep" @@ -46,6 +48,8 @@ type options struct { sshHostPassword []byte sshUserPassword []byte database db.AuthDB + x509CAService apiv1.CertificateAuthorityService + tlsConfig *tls.Config } func (o *options) apply(opts []Option) { @@ -65,6 +69,13 @@ func WithConfigFile(name string) Option { } } +// WithX509CAService provides the x509CAService to be used for signing x509 requests +func WithX509CAService(svc apiv1.CertificateAuthorityService) Option { + return func(o *options) { + o.x509CAService = svc + } +} + // WithPassword sets the given password as the configured password in the CA // options. func WithPassword(password []byte) Option { @@ -104,6 +115,14 @@ func WithDatabase(d db.AuthDB) Option { } } +// WithTLSConfig sets the TLS configuration to be used by the HTTP(s) server +// spun by step-ca. +func WithTLSConfig(t *tls.Config) Option { + return func(o *options) { + o.tlsConfig = t + } +} + // WithLinkedCAToken sets the token used to authenticate with the linkedca. func WithLinkedCAToken(token string) Option { return func(o *options) { @@ -125,6 +144,7 @@ type CA struct { config *config.Config srv *server.Server insecureSrv *server.Server + metricsSrv *server.Server opts *options renewer *TLSRenewer compactStop chan struct{} @@ -163,6 +183,16 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { opts = append(opts, authority.WithQuietInit()) } + if ca.opts.x509CAService != nil { + opts = append(opts, authority.WithX509CAService(ca.opts.x509CAService)) + } + + var meter *metrix.Meter + if ca.config.MetricsAddress != "" { + meter = metrix.New() + opts = append(opts, authority.WithMeter(meter)) + } + webhookTransport := http.DefaultTransport.(*http.Transport).Clone() opts = append(opts, authority.WithWebhookClient(&http.Client{Transport: webhookTransport})) @@ -172,9 +202,20 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { } ca.auth = auth - tlsConfig, clientTLSConfig, err := ca.getTLSConfig(auth) - if err != nil { - return nil, err + var tlsConfig *tls.Config + var clientTLSConfig *tls.Config + if ca.opts.tlsConfig != nil { + // try using the tls Configuration supplied by the caller + log.Print("Using tls configuration supplied by the application") + tlsConfig = ca.opts.tlsConfig + clientTLSConfig = ca.opts.tlsConfig + } else { + // default to using the step-ca x509 Signer Interface + log.Print("Building new tls configuration using step-ca x509 Signer Interface") + tlsConfig, clientTLSConfig, err = ca.getTLSConfig(auth) + if err != nil { + return nil, err + } } webhookTransport.TLSClientConfig = clientTLSConfig @@ -250,19 +291,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) }) @@ -323,6 +359,13 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { } } + if meter != nil { + ca.metricsSrv = server.New(ca.config.MetricsAddress, meter, nil) + ca.metricsSrv.BaseContext = func(net.Listener) context.Context { + return baseContext + } + } + return ca, nil } @@ -409,6 +452,14 @@ func (ca *CA) Run() error { }() } + if ca.metricsSrv != nil { + wg.Add(1) + go func() { + defer wg.Done() + errs <- ca.metricsSrv.ListenAndServe() + }() + } + wg.Add(1) go func() { defer wg.Done() @@ -426,7 +477,10 @@ func (ca *CA) Run() error { // Stop stops the CA calling to the server Shutdown method. func (ca *CA) Stop() error { close(ca.compactStop) - ca.renewer.Stop() + if ca.renewer != nil { + ca.renewer.Stop() + } + if err := ca.auth.Shutdown(); err != nil { log.Printf("error stopping ca.Authority: %+v\n", err) } @@ -485,6 +539,13 @@ func (ca *CA) Reload() error { } } + if ca.metricsSrv != nil { + if err = ca.metricsSrv.Reload(newCA.metricsSrv); err != nil { + logContinue("Reload failed because metrics server could not be replaced.") + return errors.Wrap(err, "error reloading metrics server") + } + } + if err = ca.srv.Reload(newCA.srv); err != nil { logContinue("Reload failed because server could not be replaced.") return errors.Wrap(err, "error reloading server") @@ -494,7 +555,10 @@ func (ca *CA) Reload() error { // 2. Safely shutdown any internal resources (e.g. key manager) // 3. Replace ca properties // Do not replace ca.srv - ca.renewer.Stop() + if ca.renewer != nil { + ca.renewer.Stop() + } + ca.auth.CloseForReload() ca.auth = newCA.auth ca.config = newCA.config @@ -584,10 +648,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.go b/ca/client.go index 7321f82f..ac13e1fe 100644 --- a/ca/client.go +++ b/ca/client.go @@ -37,7 +37,6 @@ import ( "golang.org/x/net/http2" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" - "gopkg.in/square/go-jose.v2/jwt" ) // DisableIdentity is a global variable to disable the identity. @@ -1374,7 +1373,7 @@ func (c *Client) RootFingerprintWithContext(ctx context.Context) (string, error) // CreateSignRequest is a helper function that given an x509 OTT returns a // simple but secure sign request as well as the private key used. func CreateSignRequest(ott string) (*api.SignRequest, crypto.PrivateKey, error) { - token, err := jwt.ParseSigned(ott) + token, err := jose.ParseSigned(ott) if err != nil { return nil, nil, errors.Wrap(err, "error parsing ott") } diff --git a/cas/apiv1/services.go b/cas/apiv1/services.go index bca24d96..fdd35f16 100644 --- a/cas/apiv1/services.go +++ b/cas/apiv1/services.go @@ -53,6 +53,8 @@ const ( StepCAS = "stepcas" // VaultCAS is a CertificateAuthorityService using Hasicorp Vault PKI. VaultCAS = "vaultcas" + // ExternalCAS is a CertificateAuthorityService using an external injected CA implementation + ExternalCAS = "externalcas" ) // String returns a string from the type. It will always return the lower case diff --git a/cas/apiv1/services_test.go b/cas/apiv1/services_test.go index 9289de76..b4f1def7 100644 --- a/cas/apiv1/services_test.go +++ b/cas/apiv1/services_test.go @@ -13,6 +13,7 @@ func TestType_String(t *testing.T) { {"default", "", "softcas"}, {"SoftCAS", SoftCAS, "softcas"}, {"CloudCAS", CloudCAS, "cloudcas"}, + {"ExternalCAS", ExternalCAS, "externalcas"}, {"UnknownCAS", "UnknownCAS", "unknowncas"}, } for _, tt := range tests { diff --git a/cas/stepcas/jwk_issuer_test.go b/cas/stepcas/jwk_issuer_test.go index 0924414b..3f9fa09f 100644 --- a/cas/stepcas/jwk_issuer_test.go +++ b/cas/stepcas/jwk_issuer_test.go @@ -33,10 +33,10 @@ func Test_jwkIssuer_SignToken(t *testing.T) { RA *raInfo `json:"ra"` } type claims struct { - Aud []string `json:"aud"` - Sub string `json:"sub"` - Sans []string `json:"sans"` - Step stepClaims `json:"step"` + Aud jose.Audience `json:"aud"` + Sub string `json:"sub"` + Sans []string `json:"sans"` + Step stepClaims `json:"step"` } tests := []struct { name string @@ -72,7 +72,7 @@ func Test_jwkIssuer_SignToken(t *testing.T) { } var c claims want := claims{ - Aud: []string{tt.fields.caURL.String() + "/1.0/sign"}, + Aud: jose.Audience{tt.fields.caURL.String() + "/1.0/sign"}, Sub: tt.args.subject, Sans: tt.args.sans, } @@ -80,6 +80,7 @@ func Test_jwkIssuer_SignToken(t *testing.T) { want.Step.RA = tt.args.info } if err := jwt.Claims(testX5CKey.Public(), &c); err != nil { + t.Log(got) t.Errorf("jwt.Claims() error = %v", err) } if !reflect.DeepEqual(c, want) { @@ -109,9 +110,9 @@ func Test_jwkIssuer_RevokeToken(t *testing.T) { subject string } type claims struct { - Aud []string `json:"aud"` - Sub string `json:"sub"` - Sans []string `json:"sans"` + Aud jose.Audience `json:"aud"` + Sub string `json:"sub"` + Sans []string `json:"sans"` } tests := []struct { name string diff --git a/cas/stepcas/stepcas.go b/cas/stepcas/stepcas.go index 9f94c6ae..51c5f687 100644 --- a/cas/stepcas/stepcas.go +++ b/cas/stepcas/stepcas.go @@ -71,6 +71,8 @@ func (s *StepCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1 switch { case req.CSR == nil: return nil, errors.New("createCertificateRequest `csr` cannot be nil") + case req.Template == nil: + return nil, errors.New("createCertificateRequest `template` cannot be nil") case req.Lifetime == 0: return nil, errors.New("createCertificateRequest `lifetime` cannot be 0") } @@ -87,7 +89,7 @@ func (s *StepCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1 info.ProvisionerName = p.Name } - cert, chain, err := s.createCertificate(req.CSR, req.Lifetime, info) + cert, chain, err := s.createCertificate(req.CSR, req.Template, req.Lifetime, info) if err != nil { return nil, err } @@ -167,18 +169,18 @@ func (s *StepCAS) GetCertificateAuthority(*apiv1.GetCertificateAuthorityRequest) }, nil } -func (s *StepCAS) createCertificate(cr *x509.CertificateRequest, lifetime time.Duration, raInfo *raInfo) (*x509.Certificate, []*x509.Certificate, error) { - sans := make([]string, 0, len(cr.DNSNames)+len(cr.EmailAddresses)+len(cr.IPAddresses)+len(cr.URIs)) - sans = append(sans, cr.DNSNames...) - sans = append(sans, cr.EmailAddresses...) - for _, ip := range cr.IPAddresses { +func (s *StepCAS) createCertificate(cr *x509.CertificateRequest, template *x509.Certificate, lifetime time.Duration, raInfo *raInfo) (*x509.Certificate, []*x509.Certificate, error) { + sans := make([]string, 0, len(template.DNSNames)+len(template.EmailAddresses)+len(template.IPAddresses)+len(template.URIs)) + sans = append(sans, template.DNSNames...) + sans = append(sans, template.EmailAddresses...) + for _, ip := range template.IPAddresses { sans = append(sans, ip.String()) } - for _, u := range cr.URIs { + for _, u := range template.URIs { sans = append(sans, u.String()) } - commonName := cr.Subject.CommonName + commonName := template.Subject.CommonName if commonName == "" && len(sans) > 0 { commonName = sans[0] } diff --git a/cas/stepcas/stepcas_test.go b/cas/stepcas/stepcas_test.go index b9dd9abd..f7746da0 100644 --- a/cas/stepcas/stepcas_test.go +++ b/cas/stepcas/stepcas_test.go @@ -23,6 +23,7 @@ import ( "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/ca" "github.com/smallstep/certificates/cas/apiv1" + "github.com/stretchr/testify/require" "go.step.sm/crypto/jose" "go.step.sm/crypto/pemutil" "go.step.sm/crypto/randutil" @@ -631,6 +632,17 @@ func TestStepCAS_CreateCertificate(t *testing.T) { jwkEnc := testJWKIssuer(t, caURL, testPassword) x5cBad := testX5CIssuer(t, caURL, "bad-password") + testTemplate := &x509.Certificate{ + Subject: testCR.Subject, + DNSNames: testCR.DNSNames, + EmailAddresses: testCR.EmailAddresses, + IPAddresses: testCR.IPAddresses, + URIs: testCR.URIs, + } + + testOtherCR, err := x509util.CreateCertificateRequest("Test Certificate", []string{"test.example.com"}, testKey) + require.NoError(t, err) + type fields struct { iss stepIssuer client *ca.Client @@ -648,6 +660,15 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }{ {"ok", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: testCR, + Template: testTemplate, + Lifetime: time.Hour, + }}, &apiv1.CreateCertificateResponse{ + Certificate: testCrt, + CertificateChain: []*x509.Certificate{testIssCrt}, + }, false}, + {"ok with different CSR", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ + CSR: testOtherCR, + Template: testTemplate, Lifetime: time.Hour, }}, &apiv1.CreateCertificateResponse{ Certificate: testCrt, @@ -655,6 +676,7 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }, false}, {"ok with password", fields{x5cEnc, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: testCR, + Template: testTemplate, Lifetime: time.Hour, }}, &apiv1.CreateCertificateResponse{ Certificate: testCrt, @@ -662,6 +684,7 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }, false}, {"ok jwk", fields{jwk, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: testCR, + Template: testTemplate, Lifetime: time.Hour, }}, &apiv1.CreateCertificateResponse{ Certificate: testCrt, @@ -669,6 +692,7 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }, false}, {"ok jwk with password", fields{jwkEnc, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: testCR, + Template: testTemplate, Lifetime: time.Hour, }}, &apiv1.CreateCertificateResponse{ Certificate: testCrt, @@ -676,6 +700,7 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }, false}, {"ok with provisioner", fields{jwk, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: testCR, + Template: testTemplate, Lifetime: time.Hour, Provisioner: &apiv1.ProvisionerInfo{ID: "provisioner-id", Type: "ACME"}, }}, &apiv1.CreateCertificateResponse{ @@ -684,6 +709,7 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }, false}, {"ok with server cert", fields{jwk, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: testCR, + Template: testTemplate, Lifetime: time.Hour, IsCAServerCert: true, }}, &apiv1.CreateCertificateResponse{ @@ -692,6 +718,12 @@ func TestStepCAS_CreateCertificate(t *testing.T) { }, false}, {"fail CSR", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ CSR: nil, + Template: testTemplate, + Lifetime: time.Hour, + }}, nil, true}, + {"fail Template", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ + CSR: testCR, + Template: nil, Lifetime: time.Hour, }}, nil, true}, {"fail lifetime", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{ diff --git a/cas/stepcas/x5c_issuer_test.go b/cas/stepcas/x5c_issuer_test.go index c32490ef..df8bc71c 100644 --- a/cas/stepcas/x5c_issuer_test.go +++ b/cas/stepcas/x5c_issuer_test.go @@ -58,10 +58,10 @@ func Test_x5cIssuer_SignToken(t *testing.T) { RA *raInfo `json:"ra"` } type claims struct { - Aud []string `json:"aud"` - Sub string `json:"sub"` - Sans []string `json:"sans"` - Step stepClaims `json:"step"` + Aud jose.Audience `json:"aud"` + Sub string `json:"sub"` + Sans []string `json:"sans"` + Step stepClaims `json:"step"` } tests := []struct { name string @@ -132,9 +132,9 @@ func Test_x5cIssuer_RevokeToken(t *testing.T) { subject string } type claims struct { - Aud []string `json:"aud"` - Sub string `json:"sub"` - Sans []string `json:"sans"` + Aud jose.Audience `json:"aud"` + Sub string `json:"sub"` + Sans []string `json:"sans"` } tests := []struct { name string diff --git a/commands/app.go b/commands/app.go index e5c6ea1e..c96b50ae 100644 --- a/commands/app.go +++ b/commands/app.go @@ -251,7 +251,8 @@ To get a linked authority token: ca.WithSSHUserPassword(sshUserPassword), ca.WithIssuerPassword(issuerPassword), ca.WithLinkedCAToken(token), - ca.WithQuiet(quiet)) + ca.WithQuiet(quiet), + ) if err != nil { fatal(err) } diff --git a/db/db.go b/db/db.go index 03295f22..39452672 100644 --- a/db/db.go +++ b/db/db.go @@ -78,11 +78,14 @@ func FromContext(ctx context.Context) (db AuthDB, ok bool) { // MustFromContext returns the current database from the given context. It // will panic if it's not in the context. func MustFromContext(ctx context.Context) AuthDB { - if db, ok := FromContext(ctx); !ok { + var ( + db AuthDB + ok bool + ) + if db, ok = FromContext(ctx); !ok { panic("authority database is not in the context") - } else { - return db } + return db } // CertificateStorer is an extension of AuthDB that allows to store diff --git a/docker/Dockerfile.hsm b/docker/Dockerfile.hsm index c5a54d8c..f6cec47a 100644 --- a/docker/Dockerfile.hsm +++ b/docker/Dockerfile.hsm @@ -1,4 +1,4 @@ -FROM golang AS builder +FROM golang:bookworm AS builder WORKDIR /src COPY . . @@ -9,9 +9,9 @@ RUN apt-get install -y --no-install-recommends \ 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 +FROM smallstep/step-kms-plugin:bookworm AS kms -FROM smallstep/step-cli:bullseye +FROM smallstep/step-cli:bookworm COPY --from=builder /src/bin/step-ca /usr/local/bin/step-ca COPY --from=kms /usr/local/bin/step-kms-plugin /usr/local/bin/step-kms-plugin diff --git a/examples/README.md b/examples/README.md index a2323302..a6908c6b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -21,7 +21,7 @@ the token does contain the root fingerprint then it is simpler to use: client, err := ca.Bootstrap(token) ``` -After the initialization there are examples of all the client methods. These +After the initialization, there are examples of all the client methods. These methods are a convenient way to use the CA API. The first method, `Health`, returns the status of the CA server. If the server is up it will return `{"status":"ok"}`. @@ -77,7 +77,7 @@ if err != nil { ... } ``` The following methods are for inpsecting Provisioners. -One method that returns a list of provisioners or a the encrypted key of one provisioner. +One method that returns a list of provisioners or an encrypted key of one provisioner. ```go // Without options it will return the first 20 provisioners. @@ -98,7 +98,7 @@ key, err := client.ProvisionerKey("DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk") ``` The following example shows how to create a -tls.Config object that can be injected into servers and clients. By default these +tls.Config object that can be injected into servers and clients. By default, these methods will spin off Go routines that auto-renew a certificate once (approximately) two thirds of the duration of the certificate has passed. @@ -184,7 +184,7 @@ resp, err := client.Get("https://localhost:8443") ``` We will demonstrate the mTLS configuration in a different example. In this -examplefor we will configure the server to only verify client certificates +example we will configure the server to only verify client certificates if they are provided. To being with let's start the Step CA: @@ -226,7 +226,7 @@ If you'd like to turn off curl's verification of the certificate, use HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure. ``` -Now lets use the root certificate generated for the Step PKI. It should work. +Now let's use the root certificate generated for the Step PKI. It should work. ```sh certificates $ curl --cacert examples/pki/secrets/root_ca.crt https://localhost:8443 @@ -236,7 +236,7 @@ Hello nobody at 2018-11-03 01:49:25.66912 +0000 UTC!!! Notice that in the response we see `nobody`. This is because the server did not detected a TLS client configuration. -But if we create a client with it's own certificate (generated by the Step CA), +But if we create a client with its own certificate (generated by the Step CA), we should see the Common Name of the client certificate: ```sh @@ -304,7 +304,7 @@ We can use the bootstrap-server to demonstrate certificate rotation. We've added a second provisioner, named `mike@smallstep.com`, to the CA configuration. This provisioner is has a default certificate duration of 2 minutes. Let's run the server, and inspect the certificate. We can should be able to -see the certificate rotate once approximately 2/3rds of it's lifespan has passed. +see the certificate rotate once approximately 2/3rds of its lifespan has passed. ```sh certificates $ export STEPPATH=examples/pki @@ -320,7 +320,7 @@ The exact formula is `-/3-rand(/20)` (`duration=12 in our example). We can use the following command to check the certificate expiration and to make -sure the certificate changes after 74-80 seconds. +sure the certificate changes after 74-80 seconds. ```sh certificates $ step certificate inspect --insecure https://localhost:8443 diff --git a/examples/docker/renewer/entrypoint.sh b/examples/docker/renewer/entrypoint.sh index dc84dcbf..545f7fda 100755 --- a/examples/docker/renewer/entrypoint.sh +++ b/examples/docker/renewer/entrypoint.sh @@ -7,12 +7,12 @@ sleep 5 rm -f /var/local/step/root_ca.crt rm -f /var/local/step/site.crt /var/local/step/site.key -# Donwload the root certificate +# Download the root certificate step ca root /var/local/step/root_ca.crt # Get token STEP_TOKEN=$(step ca token $COMMON_NAME) -# Donwload the root certificate +# Download the root certificate step ca certificate --token $STEP_TOKEN $COMMON_NAME /var/local/step/site.crt /var/local/step/site.key -exec "$@" \ No newline at end of file +exec "$@" diff --git a/go.mod b/go.mod index fe3aa6a4..11d9d775 100644 --- a/go.mod +++ b/go.mod @@ -3,63 +3,78 @@ module github.com/smallstep/certificates go 1.20 require ( - cloud.google.com/go/longrunning v0.5.1 - cloud.google.com/go/security v1.15.1 + cloud.google.com/go/longrunning v0.5.5 + cloud.google.com/go/security v1.15.5 github.com/Masterminds/sprig/v3 v3.2.3 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 v4.1.2+incompatible + github.com/go-chi/chi/v5 v5.0.11 + github.com/go-jose/go-jose/v3 v3.0.1 github.com/golang/mock v1.6.0 - github.com/google/go-cmp v0.5.9 - github.com/google/go-tpm v0.3.3 - github.com/google/uuid v1.3.1 + github.com/google/go-cmp v0.6.0 + github.com/google/go-tpm v0.9.0 + github.com/google/uuid v1.6.0 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.24.1 + github.com/hashicorp/vault/api v1.12.0 + github.com/hashicorp/vault/api/auth/approle v0.6.0 + github.com/hashicorp/vault/api/auth/kubernetes v0.6.0 + github.com/newrelic/go-agent/v3 v3.30.0 github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.18.0 github.com/rs/xid v1.5.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.20230509120429-e17291421738 + github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 github.com/smallstep/nosql v0.6.0 + github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81 + github.com/smallstep/scep v0.0.0-20231024192529-aee96d7ad34d 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.8.0 - go.step.sm/crypto v0.35.0 - go.step.sm/linkedca v0.20.0 - golang.org/x/crypto v0.13.0 + go.step.sm/crypto v0.43.1 + go.step.sm/linkedca v0.20.1 + golang.org/x/crypto v0.19.0 golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 - golang.org/x/net v0.15.0 - google.golang.org/api v0.141.0 - google.golang.org/grpc v1.58.1 - google.golang.org/protobuf v1.31.0 - gopkg.in/square/go-jose.v2 v2.6.0 + golang.org/x/net v0.21.0 + google.golang.org/api v0.165.0 + google.golang.org/grpc v1.61.0 + google.golang.org/protobuf v1.32.0 ) require ( - cloud.google.com/go v0.110.6 // indirect - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.1 // indirect - cloud.google.com/go/kms v1.15.1 // indirect - filippo.io/edwards25519 v1.0.0 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/kms v1.15.6 // indirect + filippo.io/edwards25519 v1.1.0 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // 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.0.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.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.318 // indirect + github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.27.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect + github.com/aws/smithy-go v1.19.0 // indirect + github.com/beorn7/perks v1.0.1 // 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 @@ -68,23 +83,26 @@ require ( github.com/davecgh/go-spew v1.1.1 // 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/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/dustin/go-humanize v1.0.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-kit/kit v0.13.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // 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.1.0 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect + github.com/golang/glog v1.1.2 // 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.12 // indirect + github.com/google/certificate-transparency-go v1.1.6 // indirect + github.com/google/go-tpm-tools v0.4.2 // indirect github.com/google/go-tspi v0.3.0 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -104,12 +122,12 @@ require ( github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 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 + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -117,8 +135,11 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/peterbourgon/diskv/v3 v3.0.1 // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/schollz/jsonstore v1.1.0 // indirect @@ -129,17 +150,19 @@ require ( 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.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.1.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.23.0 // indirect + go.opentelemetry.io/otel/metric v1.23.0 // indirect + go.opentelemetry.io/otel/trace v1.23.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -// use github.com/smallstep/pkcs7 fork with patches applied -replace go.mozilla.org/pkcs7 => github.com/smallstep/pkcs7 v0.0.0-20230302202335-4c094085c948 diff --git a/go.sum b/go.sum index a3553b19..a470c1ee 100644 --- a/go.sum +++ b/go.sum @@ -1,194 +1,83 @@ -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.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= -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.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q= -cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= -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.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= 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 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.1 h1:HUC3fAoepH3RpcQXiJhXWWYizjQ5r7YjI7SO9ZbHf9s= -cloud.google.com/go/kms v1.15.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= -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/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/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= -cloud.google.com/go/security v1.15.1 h1:jR3itwycg/TgGA0uIgTItcVhA55hKWiNJxaNNpQJaZE= -cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= -cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= -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.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -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= -filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= -filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/kms v1.15.6 h1:ktpEMQmsOAYj3VZwH020FcQlm23BVYg8T8O1woG2GcE= +cloud.google.com/go/kms v1.15.6/go.mod h1:yF75jttnIdHfGBoE51AKsD/Yqf+/jICzB9v1s1acsms= +cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= +cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/security v1.15.5 h1:wTKJQ10j8EYgvE8Y+KhovxDRVDk2iv/OsxZ6GrLP3kE= +cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 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.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= -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/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= 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/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 v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2/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/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= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= 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 v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -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/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.25.37/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.318 h1:Yl66rpbQHFUbxe9JBKLcvOvRivhVgP6+zH0b9KzARX8= -github.com/aws/aws-sdk-go v1.44.318/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/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= +github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.9 h1:W9PbZAZAEcelhhjb7KuwUtf+Lbc+i7ByYJRuWLlnxyQ= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.9/go.mod h1:2tFmR7fQnOdQlM2ZCEPpFnBIQD1U8wmXmduBgZbOag0= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= +github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= +github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/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= @@ -203,46 +92,23 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -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/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= 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-20190620071333-e64a0ec8b42a/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= @@ -251,275 +117,118 @@ github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70d github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 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.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/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/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/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/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 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/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= 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/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= -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.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= -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-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-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= +github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/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= -github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-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.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -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.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -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.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -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/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= 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.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= -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/go-attestation v0.3.2/go.mod h1:N0ADdnY0cr7eLJyZ75o8kofGGTUF2XrZTJuTPo5acwk= -github.com/google/go-attestation v0.4.4-0.20220404204839-8820d49b18d9/go.mod h1:KDsPHk8a2MX9g20kYSdxB21t7je5NghSaFeVn0Zu3Ao= +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.6.1 h1:NajHkAaLqN9/aW7bCFSUplUMtDgk2+HcN7jC2btFtk0= -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.2/go.mod h1:j71sMBTfp3X5jPHz852ZOfQMUOf65Gb/Th8pRmp7fvg= -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.2.1/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4= -github.com/google/go-tpm-tools v0.3.1/go.mod h1:PSg+r5hSZI5tP3X7LBQx2sW1VSZUqZHBSrKyDqrB21U= -github.com/google/go-tpm-tools v0.3.9/go.mod h1:22JvWmHcD5w55cs+nMeqDGDxgNS15/2pDq2cLqnc3rc= -github.com/google/go-tpm-tools v0.3.12 h1:hpWglH4RaZnGVbgOK3IThI5K++jnFvjQ94EIN34xrUU= -github.com/google/go-tpm-tools v0.3.12/go.mod h1:2OtmyPGPuaWWIOjr+IDhNQb6t5njjbSmZtzc350Q6Ro= -github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-sev-guest v0.9.3 h1:GOJ+EipURdeWFl/YYdgcCxyPeMgQUWlI056iFkBD8UU= +github.com/google/go-tdx-guest v0.2.3-0.20231011100059-4cf02bed9d33 h1:lRlUusuieEuqljjihCXb+Mr73VNitOYPJYWXzJKtBWs= +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.2 h1:iyaCPKt2N5Rd0yz0G8ANa022SgCNZkMpp+db6QELtvI= +github.com/google/go-tpm-tools v0.4.2/go.mod h1:fGUDZu4tw3V4hUVuFHmiYgRd0c58/IXivn9v3Ea/ck4= 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-20200507031123-427632fa3b1c/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.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= -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/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.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/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.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= -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/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.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.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -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.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -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= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -527,17 +236,13 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M= 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= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= @@ -545,44 +250,22 @@ github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3 github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/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/hashicorp/vault/api v1.12.0 h1:meCpJSesvzQyao8FCOgk2fGdoADAnbDu2WPJN1lDLJ4= +github.com/hashicorp/vault/api v1.12.0/go.mod h1:si+lJCYO7oGkIoNPAN8j3azBLTn9SjMGS+jFaHd1Cck= +github.com/hashicorp/vault/api/auth/approle v0.6.0 h1:ELfFFQlTM/e97WJKu1HvNFa7lQ3tlTwwzrR1NJE1V7Y= +github.com/hashicorp/vault/api/auth/approle v0.6.0/go.mod h1:CCoIl1xBC3lAWpd1HV+0ovk76Z8b8Mdepyk21h3pGk0= +github.com/hashicorp/vault/api/auth/kubernetes v0.6.0 h1:K8sKGhtTAqGKfzaaYvUSIOAqTOIn3Gk1EsCEAMzZHtM= +github.com/hashicorp/vault/api/auth/kubernetes v0.6.0/go.mod h1:Htwcjez5J9PwAHaZ1EYMBlgGq3/in5ajUV4+WCPihPE= 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= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -631,300 +314,124 @@ 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.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -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.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= 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-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.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.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -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/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 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= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/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= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -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.24.1 h1:qJc+cKtc0v9vrsnMHuHy4r6Fh9iigNJj3O3KUKPOD0M= -github.com/newrelic/go-agent/v3 v3.24.1/go.mod h1:29qGunRQA4+IGWn5WRiqVKA+pqYsCIk4ZK9nwygbKbc= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= -github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= -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.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= -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= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -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/newrelic/go-agent/v3 v3.30.0 h1:ZXHCT/Cot4iIPwcegCZURuRQOsfmGA6wilW+S3bfBjY= +github.com/newrelic/go-agent/v3 v3.30.0/go.mod h1:9utrgxlSryNqRrTvII2XBL+0lpofXbqXApvVWPpbzUg= +github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= 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= github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/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_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= 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.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= -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/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 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= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/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= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -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.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.20230509120429-e17291421738 h1:h+cZgVniTaE0uuRMdxTThLaJeuxsv4aas6oStz6f5VQ= -github.com/smallstep/go-attestation v0.4.4-0.20230509120429-e17291421738/go.mod h1:mk2hyNbyai1oon+ilW9t42BuBVw7ee8elDdgrPq4394= +github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA= +github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/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/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/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81 h1:B6cED3iLJTgxpdh4tuqByDjRRKan2EvtnOfHr2zHJVg= +github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y= +github.com/smallstep/scep v0.0.0-20231024192529-aee96d7ad34d h1:06LUHn4Ia2X6syjIaCMNaXXDNdU+1N/oOHynJbWgpXw= +github.com/smallstep/scep v0.0.0-20231024192529-aee96d7ad34d/go.mod h1:4d0ub42ut1mMtvGyMensjuHYEUpRrASvkzLEJvoRQcU= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -933,28 +440,15 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 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= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/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= @@ -966,366 +460,128 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 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.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= 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.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -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 v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= -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.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E= +go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= +go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= +go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= 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.0 h1:0N6ks5n1sdv4+biJMUTdqHjpTBKKN9zNqqBdOJIyHe4= -go.step.sm/crypto v0.35.0/go.mod h1:sBsrpVReoxmiLexbWL+vQRxZd6Gq4YBj/IRSUH+DZe4= -go.step.sm/linkedca v0.20.0 h1:bH41rvyDm3nSSJ5xgGsKUZOpzJcq5x2zacMIeqtq9oI= -go.step.sm/linkedca v0.20.0/go.mod h1:eybHw6ZTpuFmkUQnTBRWM2SPIGaP0VbYeo1bupfPT70= +go.step.sm/crypto v0.43.1 h1:18Z/M49SnFDPXvFbfoN/ugE1i0J7phLWARhSQs/XSDI= +go.step.sm/crypto v0.43.1/go.mod h1:9n90D/SWjH1hTyQn1hgviUGyK8YRv743S8UZHYbt4BU= +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.4.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-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/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-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 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.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -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/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 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= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-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= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-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-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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -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/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 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.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= 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.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/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20201207223542-d4d67f95c62d/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-20210316092937-0b90fd5c4c48/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-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= @@ -1334,275 +590,79 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc 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.5.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/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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/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/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-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-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -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/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -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.141.0 h1:Df6vfMgDoIM6ss0m7H4MPwFwY87WNXHfBIda/Bmfl4E= -google.golang.org/api v0.141.0/go.mod h1:iZqLkdPlXKyG0b90eu6KxVSE4D/ccRF2e/doKD2CnQQ= +google.golang.org/api v0.165.0 h1:zd5d4JIIIaYYsfVy1HzoXYZ9rWCSBxxAglbczzo7Bgc= +google.golang.org/api v0.165.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= 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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 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-20190927181202-20e1ac93f88c/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-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -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-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= -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-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe h1:USL2DhxfgRchafRvt/wYyyQNzwgL7ZiURcozOE/Pkvo= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= 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.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -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.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= -google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= 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= @@ -1611,65 +671,24 @@ 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.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= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f 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/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 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.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.6/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/internal/metrix/meter.go b/internal/metrix/meter.go new file mode 100644 index 00000000..a867b197 --- /dev/null +++ b/internal/metrix/meter.go @@ -0,0 +1,196 @@ +// Package metrix implements stats-related functionality. +package metrix + +import ( + "net/http" + "strconv" + "time" + + "github.com/smallstep/certificates/authority/provisioner" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +// New initializes and returns a new [Meter]. +func New() (m *Meter) { + initializedAt := time.Now() + + m = &Meter{ + uptime: prometheus.NewGaugeFunc( + prometheus.GaugeOpts(opts( + "", + "uptime_seconds", + "Number of seconds since service start", + )), + func() float64 { + return float64(time.Since(initializedAt) / time.Second) + }, + ), + ssh: newProvisionerInstruments("ssh"), + x509: newProvisionerInstruments("x509"), + kms: &kms{ + signed: prometheus.NewCounter(prometheus.CounterOpts(opts("kms", "signed", "Number of KMS-backed signatures"))), + errors: prometheus.NewCounter(prometheus.CounterOpts(opts("kms", "errors", "Number of KMS-related errors"))), + }, + } + + reg := prometheus.NewRegistry() + + reg.MustRegister( + m.uptime, + m.ssh.rekeyed, + m.ssh.renewed, + m.ssh.signed, + m.x509.rekeyed, + m.x509.renewed, + m.x509.signed, + m.kms.signed, + m.kms.errors, + ) + + h := promhttp.HandlerFor(reg, promhttp.HandlerOpts{ + Registry: reg, + Timeout: 5 * time.Second, + MaxRequestsInFlight: 10, + }) + + mux := http.NewServeMux() + mux.Handle("/metrics", h) + m.Handler = mux + + return +} + +// Meter wraps the functionality of a Prometheus-compatible HTTP handler. +type Meter struct { + http.Handler + + uptime prometheus.GaugeFunc + ssh *provisionerInstruments + x509 *provisionerInstruments + kms *kms +} + +// SSHRekeyed implements [authority.Meter] for [Meter]. +func (m *Meter) SSHRekeyed(p provisioner.Interface, err error) { + incrProvisionerCounter(m.ssh.rekeyed, p, err) +} + +// SSHRenewed implements [authority.Meter] for [Meter]. +func (m *Meter) SSHRenewed(p provisioner.Interface, err error) { + incrProvisionerCounter(m.ssh.renewed, p, err) +} + +// SSHSigned implements [authority.Meter] for [Meter]. +func (m *Meter) SSHSigned(p provisioner.Interface, err error) { + incrProvisionerCounter(m.ssh.signed, p, err) +} + +// SSHAuthorized implements [authority.Meter] for [Meter]. +func (m *Meter) SSHWebhookAuthorized(p provisioner.Interface, err error) { + incrProvisionerCounter(m.ssh.webhookAuthorized, p, err) +} + +// SSHEnriched implements [authority.Meter] for [Meter]. +func (m *Meter) SSHWebhookEnriched(p provisioner.Interface, err error) { + incrProvisionerCounter(m.ssh.webhookEnriched, p, err) +} + +// X509Rekeyed implements [authority.Meter] for [Meter]. +func (m *Meter) X509Rekeyed(p provisioner.Interface, err error) { + incrProvisionerCounter(m.x509.rekeyed, p, err) +} + +// X509Renewed implements [authority.Meter] for [Meter]. +func (m *Meter) X509Renewed(p provisioner.Interface, err error) { + incrProvisionerCounter(m.x509.renewed, p, err) +} + +// X509Signed implements [authority.Meter] for [Meter]. +func (m *Meter) X509Signed(p provisioner.Interface, err error) { + incrProvisionerCounter(m.x509.signed, p, err) +} + +// X509Authorized implements [authority.Meter] for [Meter]. +func (m *Meter) X509WebhookAuthorized(p provisioner.Interface, err error) { + incrProvisionerCounter(m.x509.webhookAuthorized, p, err) +} + +// X509Enriched implements [authority.Meter] for [Meter]. +func (m *Meter) X509WebhookEnriched(p provisioner.Interface, err error) { + incrProvisionerCounter(m.x509.webhookEnriched, p, err) +} + +func incrProvisionerCounter(cv *prometheus.CounterVec, p provisioner.Interface, err error) { + var name string + if p != nil { + name = p.GetName() + } + + cv.WithLabelValues(name, strconv.FormatBool(err == nil)).Inc() +} + +// KMSSigned implements [authority.Meter] for [Meter]. +func (m *Meter) KMSSigned(err error) { + if err == nil { + m.kms.signed.Inc() + } else { + m.kms.errors.Inc() + } +} + +// provisionerInstruments wraps the counters exported by provisioners. +type provisionerInstruments struct { + rekeyed *prometheus.CounterVec + renewed *prometheus.CounterVec + signed *prometheus.CounterVec + + webhookAuthorized *prometheus.CounterVec + webhookEnriched *prometheus.CounterVec +} + +func newProvisionerInstruments(subsystem string) *provisionerInstruments { + return &provisionerInstruments{ + rekeyed: newCounterVec(subsystem, "rekeyed_total", "Number of certificates rekeyed", + "provisioner", + "success", + ), + renewed: newCounterVec(subsystem, "renewed_total", "Number of certificates renewed", + "provisioner", + "success", + ), + signed: newCounterVec(subsystem, "signed_total", "Number of certificates signed", + "provisioner", + "success", + ), + webhookAuthorized: newCounterVec(subsystem, "webhook_authorized_total", "Number of authorizing webhooks called", + "provisioner", + "success", + ), + webhookEnriched: newCounterVec(subsystem, "webhook_enriched_total", "Number of enriching webhooks called", + "provisioner", + "success", + ), + } +} + +type kms struct { + signed prometheus.Counter + errors prometheus.Counter +} + +func newCounterVec(subsystem, name, help string, labels ...string) *prometheus.CounterVec { + opts := opts(subsystem, name, help) + + return prometheus.NewCounterVec(prometheus.CounterOpts(opts), labels) +} + +func opts(subsystem, name, help string) prometheus.Opts { + return prometheus.Opts{ + Namespace: "step_ca", + Subsystem: subsystem, + Name: name, + Help: help, + } +} 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 3c5cb5a9..3de2c2ec 100644 --- a/pki/helm.go +++ b/pki/helm.go @@ -1,6 +1,7 @@ package pki import ( + "fmt" "io" "text/template" @@ -49,21 +50,42 @@ func (p *PKI) WriteHelmTemplate(w io.Writer) error { // to what's in p.GenerateConfig(), but that codepath isn't taken when // writing the Helm template. The default JWK provisioner is added earlier in // the process and that's part of the provisioners above. + // + // To prevent name clashes for the default ACME provisioner, we append "-1" to + // the name if it already exists. See https://github.com/smallstep/cli/issues/1018 + // for the reason. + // // TODO(hs): consider refactoring the initialization, so that this becomes // easier to reason about and maintain. if p.options.enableACME { + acmeProvisionerName := "acme" + for _, prov := range provisioners { + if prov.GetName() == acmeProvisionerName { + acmeProvisionerName = fmt.Sprintf("%s-1", acmeProvisionerName) + break + } + } provisioners = append(provisioners, &provisioner.ACME{ Type: "ACME", - Name: "acme", + Name: acmeProvisionerName, }) } // Add default SSHPOP provisioner if enabled. Similar to the above, this is - // the same as what happens in p.GenerateConfig(). + // the same as what happens in p.GenerateConfig(). To prevent name clashes for the + // default SSHPOP provisioner, we append "-1" to it if it already exists. See + // https://github.com/smallstep/cli/issues/1018 for the reason. if p.options.enableSSH { + sshProvisionerName := "sshpop" + for _, prov := range provisioners { + if prov.GetName() == sshProvisionerName { + sshProvisionerName = fmt.Sprintf("%s-1", sshProvisionerName) + break + } + } provisioners = append(provisioners, &provisioner.SSHPOP{ Type: "SSHPOP", - Name: "sshpop", + Name: sshProvisionerName, Claims: &provisioner.Claims{ EnableSSHCA: &p.options.enableSSH, }, diff --git a/pki/helm_test.go b/pki/helm_test.go index 508f8c3e..3aa0d224 100644 --- a/pki/helm_test.go +++ b/pki/helm_test.go @@ -85,6 +85,13 @@ func TestPKI_WriteHelmTemplate(t *testing.T) { wantErr: false, } }, + "ok/with-acme-and-duplicate-provisioner-name": func(t *testing.T) test { + return test{ + pki: preparePKI(t, WithProvisioner("acme"), WithACME()), + testFile: "testdata/helm/with-acme-and-duplicate-provisioner-name.yml", + wantErr: false, + } + }, "ok/with-admin": func(t *testing.T) test { return test{ pki: preparePKI(t, WithAdmin()), @@ -99,6 +106,13 @@ func TestPKI_WriteHelmTemplate(t *testing.T) { wantErr: false, } }, + "ok/with-ssh-and-duplicate-provisioner-name": func(t *testing.T) test { + return test{ + pki: preparePKI(t, WithProvisioner("sshpop"), WithSSH()), + testFile: "testdata/helm/with-ssh-and-duplicate-provisioner-name.yml", + wantErr: false, + } + }, "ok/with-ssh-and-acme": func(t *testing.T) test { return test{ pki: preparePKI(t, WithSSH(), WithACME()), diff --git a/pki/pki.go b/pki/pki.go index 971c189b..234bae5a 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -319,7 +319,10 @@ type PKI struct { func New(o apiv1.Options, opts ...Option) (*PKI, error) { // TODO(hs): invoking `New` with a context active will use values from // that CA context while generating the context. Thay may or may not - // be fully expected and/or what we want. Check that. + // be fully expected and/or what we want. This specific behavior was + // changed after not relying on the `init` inside of `step`, resulting in + // the default context being active if `step.Init` isn't called explicitly. + // It can still result in surprising results, though. currentCtx := step.Contexts().GetCurrent() caService, err := cas.New(context.Background(), o) if err != nil { @@ -330,7 +333,7 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { if o.IsCreator { creator, ok := caService.(apiv1.CertificateAuthorityCreator) if !ok { - return nil, errors.Errorf("cas type '%s' does not implements CertificateAuthorityCreator", o.Type) + return nil, errors.Errorf("cas type %q does not implement CertificateAuthorityCreator", o.Type) } caCreator = creator } @@ -850,9 +853,16 @@ func (p *PKI) GenerateConfig(opt ...ConfigOption) (*authconfig.Config, error) { // Add default ACME provisioner if enabled if p.options.enableACME { + // To prevent name clashes for the default ACME provisioner, we append "-1" to + // the name if it already exists. See https://github.com/smallstep/cli/issues/1018 + // for the reason. + acmeProvisionerName := "acme" + if p.options.provisioner == acmeProvisionerName { + acmeProvisionerName = fmt.Sprintf("%s-1", acmeProvisionerName) + } provisioners = append(provisioners, &provisioner.ACME{ Type: "ACME", - Name: "acme", + Name: acmeProvisionerName, }) } @@ -867,10 +877,16 @@ func (p *PKI) GenerateConfig(opt ...ConfigOption) (*authconfig.Config, error) { EnableSSHCA: &enableSSHCA, } - // Add default SSHPOP provisioner + // Add default SSHPOP provisioner. To prevent name clashes for the default + // SSHPOP provisioner, we append "-1" to the name if it already exists. + // See https://github.com/smallstep/cli/issues/1018 for the reason. + sshProvisionerName := "sshpop" + if p.options.provisioner == sshProvisionerName { + sshProvisionerName = fmt.Sprintf("%s-1", sshProvisionerName) + } provisioners = append(provisioners, &provisioner.SSHPOP{ Type: "SSHPOP", - Name: "sshpop", + Name: sshProvisionerName, Claims: &provisioner.Claims{ EnableSSHCA: &enableSSHCA, }, @@ -910,10 +926,13 @@ func (p *PKI) GenerateConfig(opt ...ConfigOption) (*authconfig.Config, error) { if err != nil { return nil, err } + defer _db.Shutdown() // free DB resources; unlock BadgerDB file + adminDB, err := admindb.New(_db.(nosql.DB), admin.DefaultAuthorityID) if err != nil { return nil, err } + // Add all the provisioners to the db. var adminID string for i, p := range provisioners { diff --git a/pki/pki_test.go b/pki/pki_test.go new file mode 100644 index 00000000..7d5bc8c5 --- /dev/null +++ b/pki/pki_test.go @@ -0,0 +1,313 @@ +package pki + +import ( + "context" + "path/filepath" + "testing" + + "github.com/smallstep/certificates/authority/admin" + admindb "github.com/smallstep/certificates/authority/admin/db/nosql" + authconfig "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/provisioner" + "github.com/smallstep/certificates/cas/apiv1" + "github.com/smallstep/certificates/db" + "github.com/smallstep/nosql" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.step.sm/cli-utils/step" +) + +func withDBDataSource(t *testing.T, dataSource string) func(c *authconfig.Config) error { + return func(c *authconfig.Config) error { + if c == nil || c.DB == nil { + require.Fail(t, "withDBDataSource prerequisites not met") + } + c.DB.DataSource = dataSource + return nil + } +} + +func TestPKI_GenerateConfig(t *testing.T) { + var preparePKI = func(t *testing.T, opts ...Option) *PKI { + o := apiv1.Options{ + Type: "softcas", + IsCreator: true, + } + + // TODO(hs): invoking `New` doesn't perform all operations that are executed + // when `ca init` is executed. Ideally this logic should be handled in one + // place and probably inside of the PKI initialization. For testing purposes + // the missing operations are faked by `setKeyPair`. + p, err := New(o, opts...) + require.NoError(t, err) + + // setKeyPair sets a predefined JWK and a default JWK provisioner. This is one + // of the things performed in the `ca init` code that's not part of `New`, but + // performed after that in p.GenerateKeyPairs`. We're currently using the same + // JWK for every test to keep test variance small: we're not testing JWK generation + // here after all. It's a bit dangerous to redefine the function here, but it's + // the simplest way to make this fully testable without refactoring the init now. + // The password for the predefined encrypted key is \x01\x03\x03\x07. + setKeyPair(t, p) + + return p + } + type args struct { + opt []ConfigOption + } + type test struct { + pki *PKI + args args + want *authconfig.Config + wantErr bool + } + var tests = map[string]func(t *testing.T) test{ + "ok/simple": func(t *testing.T) test { + pki := preparePKI(t) + pki.options.deploymentType = StandaloneDeployment + pki.options.provisioner = "default-prov" + return test{ + pki: pki, + args: args{ + []ConfigOption{}, + }, + want: &authconfig.Config{ + Address: "127.0.0.1:9000", + InsecureAddress: "", + DNSNames: []string{"127.0.0.1"}, + AuthorityConfig: &authconfig.AuthConfig{ + DeploymentType: "", // TODO(hs): (why is) this is not set to standalone? + EnableAdmin: false, + Provisioners: provisioner.List{ + &provisioner.JWK{ + Type: "JWK", + Name: "default-prov", + }, + }, + }, + DB: &db.Config{ + Type: "badgerv2", + DataSource: filepath.Join(step.Path(), "db"), + }, + }, + wantErr: false, + } + }, + "ok/with-acme": func(t *testing.T) test { + pki := preparePKI(t) + pki.options.deploymentType = StandaloneDeployment + pki.options.provisioner = "default-prov" + pki.options.enableACME = true + return test{ + pki: pki, + args: args{ + []ConfigOption{}, + }, + want: &authconfig.Config{ + Address: "127.0.0.1:9000", + InsecureAddress: "", + DNSNames: []string{"127.0.0.1"}, + AuthorityConfig: &authconfig.AuthConfig{ + DeploymentType: "", // TODO(hs): (why is) this is not set to standalone? + EnableAdmin: false, + Provisioners: provisioner.List{ + &provisioner.JWK{ + Type: "JWK", + Name: "default-prov", + }, + &provisioner.ACME{ + Type: "ACME", + Name: "acme", + }, + }, + }, + DB: &db.Config{ + Type: "badgerv2", + DataSource: filepath.Join(step.Path(), "db"), + }, + }, + wantErr: false, + } + }, + "ok/with-acme-and-double-provisioner-name": func(t *testing.T) test { + pki := preparePKI(t) + pki.options.deploymentType = StandaloneDeployment + pki.options.provisioner = "acme" + pki.options.enableACME = true + return test{ + pki: pki, + args: args{ + []ConfigOption{}, + }, + want: &authconfig.Config{ + Address: "127.0.0.1:9000", + InsecureAddress: "", + DNSNames: []string{"127.0.0.1"}, + AuthorityConfig: &authconfig.AuthConfig{ + DeploymentType: "", // TODO(hs): (why is) this is not set to standalone? + EnableAdmin: false, + Provisioners: provisioner.List{ + &provisioner.JWK{ + Type: "JWK", + Name: "acme", + }, + &provisioner.ACME{ + Type: "ACME", + Name: "acme-1", + }, + }, + }, + DB: &db.Config{ + Type: "badgerv2", + DataSource: filepath.Join(step.Path(), "db"), + }, + }, + wantErr: false, + } + }, + "ok/with-ssh": func(t *testing.T) test { + pki := preparePKI(t) + pki.options.deploymentType = StandaloneDeployment + pki.options.provisioner = "default-prov" + pki.options.enableSSH = true + return test{ + pki: pki, + args: args{ + []ConfigOption{}, + }, + want: &authconfig.Config{ + Address: "127.0.0.1:9000", + InsecureAddress: "", + DNSNames: []string{"127.0.0.1"}, + AuthorityConfig: &authconfig.AuthConfig{ + DeploymentType: "", // TODO(hs): (why is) this is not set to standalone? + EnableAdmin: false, + Provisioners: provisioner.List{ + &provisioner.JWK{ + Type: "JWK", + Name: "default-prov", + }, + &provisioner.SSHPOP{ + Type: "SSHPOP", + Name: "sshpop", + }, + }, + }, + DB: &db.Config{ + Type: "badgerv2", + DataSource: filepath.Join(step.Path(), "db"), + }, + }, + wantErr: false, + } + }, + "ok/with-ssh-and-double-provisioner-name": func(t *testing.T) test { + pki := preparePKI(t) + pki.options.deploymentType = StandaloneDeployment + pki.options.provisioner = "sshpop" + pki.options.enableSSH = true + return test{ + pki: pki, + args: args{ + []ConfigOption{}, + }, + want: &authconfig.Config{ + Address: "127.0.0.1:9000", + InsecureAddress: "", + DNSNames: []string{"127.0.0.1"}, + AuthorityConfig: &authconfig.AuthConfig{ + DeploymentType: "", // TODO(hs): (why is) this is not set to standalone? + EnableAdmin: false, + Provisioners: provisioner.List{ + &provisioner.JWK{ + Type: "JWK", + Name: "sshpop", + }, + &provisioner.SSHPOP{ + Type: "SSHPOP", + Name: "sshpop-1", + }, + }, + }, + DB: &db.Config{ + Type: "badgerv2", + DataSource: filepath.Join(step.Path(), "db"), + }, + }, + wantErr: false, + } + }, + "ok/with-admin": func(t *testing.T) test { + pki := preparePKI(t) + pki.options.deploymentType = StandaloneDeployment + pki.options.provisioner = "default-prov" + pki.options.enableAdmin = true + tempDir := t.TempDir() + return test{ + pki: pki, + args: args{ + []ConfigOption{withDBDataSource(t, filepath.Join(tempDir, "db"))}, + }, + want: &authconfig.Config{ + Address: "127.0.0.1:9000", + InsecureAddress: "", + DNSNames: []string{"127.0.0.1"}, + AuthorityConfig: &authconfig.AuthConfig{ + DeploymentType: "", // TODO(hs): (why is) this is not set to standalone? + EnableAdmin: true, + Provisioners: provisioner.List{}, // when admin is enabled, provisioner list is expected to be empty + }, + DB: &db.Config{ + Type: "badgerv2", + DataSource: filepath.Join(tempDir, "db"), + }, + }, + wantErr: false, + } + }, + } + for name, run := range tests { + tc := run(t) + t.Run(name, func(t *testing.T) { + got, err := tc.pki.GenerateConfig(tc.args.opt...) + if tc.wantErr { + assert.NotNil(t, err) + assert.Nil(t, got) + return + } + + assert.Nil(t, err) + if assert.NotNil(t, got) { + assert.Equal(t, tc.want.Address, got.Address) + assert.Equal(t, tc.want.InsecureAddress, got.InsecureAddress) + assert.Equal(t, tc.want.DNSNames, got.DNSNames) + assert.Equal(t, tc.want.DB, got.DB) + if assert.NotNil(t, tc.want.AuthorityConfig) { + assert.Equal(t, tc.want.AuthorityConfig.DeploymentType, got.AuthorityConfig.DeploymentType) + assert.Equal(t, tc.want.AuthorityConfig.EnableAdmin, got.AuthorityConfig.EnableAdmin) + if numberOfProvisioners := len(tc.want.AuthorityConfig.Provisioners); numberOfProvisioners > 0 { + if assert.Len(t, got.AuthorityConfig.Provisioners, numberOfProvisioners) { + for i, p := range tc.want.AuthorityConfig.Provisioners { + assert.Equal(t, p.GetType(), got.AuthorityConfig.Provisioners[i].GetType()) + assert.Equal(t, p.GetName(), got.AuthorityConfig.Provisioners[i].GetName()) + } + } + } + if tc.want.AuthorityConfig.EnableAdmin { + _db, err := db.New(tc.want.DB) + require.NoError(t, err) + defer _db.Shutdown() + + adminDB, err := admindb.New(_db.(nosql.DB), admin.DefaultAuthorityID) + require.NoError(t, err) + + provs, err := adminDB.GetProvisioners(context.Background()) + require.NoError(t, err) + + assert.NotEmpty(t, provs) // currently about the best we can do in terms of checks + } + } + } + }) + } +} diff --git a/pki/testdata/helm/with-acme-and-duplicate-provisioner-name.yml b/pki/testdata/helm/with-acme-and-duplicate-provisioner-name.yml new file mode 100644 index 00000000..f4532207 --- /dev/null +++ b/pki/testdata/helm/with-acme-and-duplicate-provisioner-name.yml @@ -0,0 +1,82 @@ +# Helm template +inject: + enabled: true + # Config contains the configuration files ca.json and defaults.json + config: + files: + ca.json: + root: /home/step/certs/root_ca.crt + federateRoots: [] + crt: /home/step/certs/intermediate_ca.crt + key: /home/step/secrets/intermediate_ca_key + address: 127.0.0.1:9000 + dnsNames: + - 127.0.0.1 + logger: + format: json + db: + type: badgerv2 + dataSource: /home/step/db + authority: + enableAdmin: false + provisioners: + - {"type":"JWK","name":"acme","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","options":{"x509":{},"ssh":{}}} + - {"type":"ACME","name":"acme-1"} + tls: + cipherSuites: + - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + minVersion: 1.2 + maxVersion: 1.3 + renegotiation: false + + defaults.json: + ca-url: https://127.0.0.1 + ca-config: /home/step/config/ca.json + fingerprint: e543cad8e9f6417076bb5aed3471c588152118aac1e0ca7984a43ee7f76da5e3 + root: /home/step/certs/root_ca.crt + + # Certificates contains the root and intermediate certificate and + # optionally the SSH host and user public keys + certificates: + # intermediate_ca contains the text of the intermediate CA Certificate + intermediate_ca: | + -----BEGIN CERTIFICATE----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIGludGVybWVkaWF0ZSBDQSBjZXJ0IGJ5 + dGVz + -----END CERTIFICATE----- + + + # root_ca contains the text of the root CA Certificate + root_ca: | + -----BEGIN CERTIFICATE----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIHJvb3QgQ0EgY2VydCBieXRlcw== + -----END CERTIFICATE----- + + + # Secrets contains the root and intermediate keys and optionally the SSH + # private keys + secrets: + # ca_password contains the password used to encrypt x509.intermediate_ca_key, ssh.host_ca_key and ssh.user_ca_key + # This value must be base64 encoded. + ca_password: + provisioner_password: + + x509: + # intermediate_ca_key contains the contents of your encrypted intermediate CA key + intermediate_ca_key: | + -----BEGIN EC PRIVATE KEY----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIGludGVybWVkaWF0ZSBDQSBrZXkgYnl0 + ZXM= + -----END EC PRIVATE KEY----- + + + # root_ca_key contains the contents of your encrypted root CA key + # Note that this value can be omitted without impacting the functionality of step-certificates + # If supplied, this should be encrypted using a unique password that is not used for encrypting + # the intermediate_ca_key, ssh.host_ca_key or ssh.user_ca_key. + root_ca_key: | + -----BEGIN EC PRIVATE KEY----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIHJvb3QgQ0Ega2V5IGJ5dGVz + -----END EC PRIVATE KEY----- + diff --git a/pki/testdata/helm/with-ssh-and-duplicate-provisioner-name.yml b/pki/testdata/helm/with-ssh-and-duplicate-provisioner-name.yml new file mode 100644 index 00000000..a499b155 --- /dev/null +++ b/pki/testdata/helm/with-ssh-and-duplicate-provisioner-name.yml @@ -0,0 +1,104 @@ +# Helm template +inject: + enabled: true + # Config contains the configuration files ca.json and defaults.json + config: + files: + ca.json: + root: /home/step/certs/root_ca.crt + federateRoots: [] + crt: /home/step/certs/intermediate_ca.crt + key: /home/step/secrets/intermediate_ca_key + ssh: + hostKey: /home/step/secrets/ssh_host_ca_key + userKey: /home/step/secrets/ssh_user_ca_key + address: 127.0.0.1:9000 + dnsNames: + - 127.0.0.1 + logger: + format: json + db: + type: badgerv2 + dataSource: /home/step/db + authority: + enableAdmin: false + provisioners: + - {"type":"JWK","name":"sshpop","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-1","claims":{"enableSSHCA":true}} + tls: + cipherSuites: + - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + minVersion: 1.2 + maxVersion: 1.3 + renegotiation: false + + defaults.json: + ca-url: https://127.0.0.1 + ca-config: /home/step/config/ca.json + fingerprint: e543cad8e9f6417076bb5aed3471c588152118aac1e0ca7984a43ee7f76da5e3 + root: /home/step/certs/root_ca.crt + + # Certificates contains the root and intermediate certificate and + # optionally the SSH host and user public keys + certificates: + # intermediate_ca contains the text of the intermediate CA Certificate + intermediate_ca: | + -----BEGIN CERTIFICATE----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIGludGVybWVkaWF0ZSBDQSBjZXJ0IGJ5 + dGVz + -----END CERTIFICATE----- + + + # root_ca contains the text of the root CA Certificate + root_ca: | + -----BEGIN CERTIFICATE----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIHJvb3QgQ0EgY2VydCBieXRlcw== + -----END CERTIFICATE----- + + # ssh_host_ca contains the text of the public ssh key for the SSH root CA + ssh_host_ca: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ0IdS5sZm6KITBMZLEJD6b5ROVraYHcAOr3feFel8r1Wp4DRPR1oU0W00J/zjNBRBbANlJoYN4x/8WNNVZ49Ms= + + # ssh_user_ca contains the text of the public ssh key for the SSH root CA + ssh_user_ca: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEWA1qUxaGwVNErsvEOGe2d6TvLMF+aiVpuOiIEvpMJ3JeJmecLQctjWqeIbpSvy6/gRa7c82Ge5rLlapYmOChs= + + # Secrets contains the root and intermediate keys and optionally the SSH + # private keys + secrets: + # ca_password contains the password used to encrypt x509.intermediate_ca_key, ssh.host_ca_key and ssh.user_ca_key + # This value must be base64 encoded. + ca_password: + provisioner_password: + + x509: + # intermediate_ca_key contains the contents of your encrypted intermediate CA key + intermediate_ca_key: | + -----BEGIN EC PRIVATE KEY----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIGludGVybWVkaWF0ZSBDQSBrZXkgYnl0 + ZXM= + -----END EC PRIVATE KEY----- + + + # root_ca_key contains the contents of your encrypted root CA key + # Note that this value can be omitted without impacting the functionality of step-certificates + # If supplied, this should be encrypted using a unique password that is not used for encrypting + # the intermediate_ca_key, ssh.host_ca_key or ssh.user_ca_key. + root_ca_key: | + -----BEGIN EC PRIVATE KEY----- + dGhlc2UgYXJlIGp1c3Qgc29tZSBmYWtlIHJvb3QgQ0Ega2V5IGJ5dGVz + -----END EC PRIVATE KEY----- + + ssh: + # ssh_host_ca_key contains the contents of your encrypted SSH Host CA key + host_ca_key: | + -----BEGIN EC PRIVATE KEY----- + ZmFrZSBzc2ggaG9zdCBrZXkgYnl0ZXM= + -----END EC PRIVATE KEY----- + + + # ssh_user_ca_key contains the contents of your encrypted SSH User CA key + user_ca_key: | + -----BEGIN EC PRIVATE KEY----- + ZmFrZSBzc2ggdXNlciBrZXkgYnl0ZXM= + -----END EC PRIVATE KEY----- + diff --git a/scep/api/api.go b/scep/api/api.go index 98da818b..bab60302 100644 --- a/scep/api/api.go +++ b/scep/api/api.go @@ -12,12 +12,13 @@ import ( "net/url" "strings" - "github.com/go-chi/chi" - microscep "github.com/micromdm/scep/v2/scep" - "go.mozilla.org/pkcs7" + "github.com/go-chi/chi/v5" + "github.com/smallstep/pkcs7" + smallscep "github.com/smallstep/scep" "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" ) @@ -150,11 +151,14 @@ func decodeRequest(r *http.Request) (request, error) { defer r.Body.Close() method := r.Method - query := r.URL.Query() + query, err := url.ParseQuery(r.URL.RawQuery) + if err != nil { + return request{}, fmt.Errorf("failed parsing URL query: %w", err) + } - var operation string - if _, ok := query["operation"]; ok { - operation = query.Get("operation") + operation := query.Get("operation") + if operation == "" { + return request{}, errors.New("no operation provided") } switch method { @@ -166,14 +170,10 @@ func decodeRequest(r *http.Request) (request, error) { Message: []byte{}, }, nil case opnPKIOperation: - var message string - if _, ok := query["message"]; ok { - message = query.Get("message") - } - // TODO: verify this; right type of encoding? Needs additional transformations? - decodedMessage, err := base64.StdEncoding.DecodeString(message) + message := query.Get("message") + decodedMessage, err := decodeMessage(message, r) if err != nil { - return request{}, err + return request{}, fmt.Errorf("failed decoding message: %w", err) } return request{ Operation: operation, @@ -185,7 +185,7 @@ func decodeRequest(r *http.Request) (request, error) { case http.MethodPost: body, err := io.ReadAll(io.LimitReader(r.Body, maxPayloadSize)) if err != nil { - return request{}, err + return request{}, fmt.Errorf("failed reading request body: %w", err) } return request{ Operation: operation, @@ -196,6 +196,77 @@ func decodeRequest(r *http.Request) (request, error) { } } +func decodeMessage(message string, r *http.Request) ([]byte, error) { + if message == "" { + return nil, errors.New("message must not be empty") + } + + // decode the message, which should be base64 standard encoded. Any characters that + // were escaped in the original query, were unescaped as part of url.ParseQuery, so + // that doesn't need to be performed here. Return early if successful. + decodedMessage, err := base64.StdEncoding.DecodeString(message) + if err == nil { + return decodedMessage, nil + } + + // only interested in corrupt input errors below this. This type of error is the + // most likely to return, but better safe than sorry. + var cie base64.CorruptInputError + if !errors.As(err, &cie) { + return nil, fmt.Errorf("failed base64 decoding message: %w", err) + } + + // the below code is a workaround for macOS when it sends a GET PKIOperation, which seems to result + // in a query with the '+' and '/' not being percent encoded; only the padding ('=') is encoded. + // When that is unescaped in the code before this, this results in invalid base64. The workaround + // is to obtain the original query, extract the message, apply transformation(s) to make it valid + // base64 and try decoding it again. If it succeeds, the happy path can be followed with the patched + // message. Otherwise we still return an error. + rawQuery, err := parseRawQuery(r.URL.RawQuery) + if err != nil { + return nil, fmt.Errorf("failed to parse raw query: %w", err) + } + + rawMessage := rawQuery.Get("message") + if rawMessage == "" { + return nil, errors.New("no message in raw query") + } + + rawMessage = strings.ReplaceAll(rawMessage, "%3D", "=") // apparently the padding arrives encoded; the others (+, /) not? + decodedMessage, err = base64.StdEncoding.DecodeString(rawMessage) + if err != nil { + return nil, fmt.Errorf("failed base64 decoding raw message: %w", err) + } + + return decodedMessage, nil +} + +// parseRawQuery parses a URL query into url.Values. It skips +// unescaping keys and values. This code is based on url.ParseQuery. +func parseRawQuery(query string) (url.Values, error) { + m := make(url.Values) + err := parseRawQueryWithoutUnescaping(m, query) + return m, err +} + +// parseRawQueryWithoutUnescaping parses the raw query into url.Values, skipping +// unescaping of the parts. This code is based on url.parseQuery. +func parseRawQueryWithoutUnescaping(m url.Values, query string) (err error) { + for query != "" { + var key string + key, query, _ = strings.Cut(query, "&") + if strings.Contains(key, ";") { + return errors.New("invalid semicolon separator in query") + } + if key == "" { + continue + } + key, value, _ := strings.Cut(key, "=") + m[key] = append(m[key], value) + } + return err +} + // lookupProvisioner loads the provisioner associated with the request. // Responds 404 if the provisioner does not exist. func lookupProvisioner(next http.HandlerFunc) http.HandlerFunc { @@ -208,7 +279,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 +292,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)) } } @@ -249,7 +320,7 @@ func GetCACert(ctx context.Context) (Response, error) { // create degenerate pkcs7 certificate structure, according to // https://tools.ietf.org/html/rfc8894#section-4.2.1.2, because // not signed or encrypted data has to be returned. - data, err := microscep.DegenerateCertificates(certs) + data, err := smallscep.DegenerateCertificates(certs) if err != nil { return Response{}, err } @@ -274,16 +345,16 @@ func GetCACaps(ctx context.Context) (Response, error) { // PKIOperation performs PKI operations and returns a SCEP response func PKIOperation(ctx context.Context, req request) (Response, error) { - // parse the message using microscep implementation - microMsg, err := microscep.ParsePKIMessage(req.Message) + // parse the message using smallscep implementation + microMsg, err := smallscep.ParsePKIMessage(req.Message) if err != nil { // return the error, because we can't use the msg for creating a CertRep return Response{}, err } - // this is essentially doing the same as microscep.ParsePKIMessage, but + // this is essentially doing the same as smallscep.ParsePKIMessage, but // gives us access to the p7 itself in scep.PKIMessage. Essentially a small - // wrapper for the microscep implementation. + // wrapper for the smallscep implementation. p7, err := pkcs7.Parse(microMsg.Raw) if err != nil { return Response{}, err @@ -313,12 +384,12 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { // even if using the renewal flow as described in the README.md. MicroMDM SCEP client also only does PKCSreq by default, unless // 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 { - if err := auth.ValidateChallenge(ctx, challengePassword, transactionID); err != nil { + if msg.MessageType == smallscep.PKCSReq || msg.MessageType == smallscep.RenewalReq { + 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, smallscep.BadRequest, err) } - return createFailureResponse(ctx, csr, msg, microscep.BadRequest, errors.New("failed validating challenge password")) + return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, errors.New("failed validating challenge password")) } } @@ -332,7 +403,16 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { certRep, err := auth.SignCSR(ctx, csr, msg) if err != nil { - return createFailureResponse(ctx, csr, msg, microscep.BadRequest, fmt.Errorf("error when signing new certificate: %w", err)) + 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, smallscep.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{ @@ -368,7 +448,7 @@ func fail(w http.ResponseWriter, err error) { http.Error(w, err.Error(), http.StatusInternalServerError) } -func createFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *scep.PKIMessage, info microscep.FailInfo, failError error) (Response, error) { +func createFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *scep.PKIMessage, info smallscep.FailInfo, failError error) (Response, error) { auth := scep.MustFromContext(ctx) certRepMsg, err := auth.CreateFailureResponse(ctx, csr, msg, scep.FailInfoName(info), failError.Error()) if err != nil { diff --git a/scep/api/api_test.go b/scep/api/api_test.go index ef3e57ab..a1782933 100644 --- a/scep/api/api_test.go +++ b/scep/api/api_test.go @@ -3,15 +3,27 @@ package api import ( "bytes" + "encoding/base64" "errors" + "fmt" "net/http" "net/http/httptest" - "reflect" + "net/url" + "strings" "testing" "testing/iotest" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_decodeRequest(t *testing.T) { + randomB64 := "wx/1mQ49TpdLRfvVjQhXNSe8RB3hjZEarqYp5XVIxpSbvOhQSs8hP2TgucID1IputbA8JC6CbsUpcVae3+8hRNqs5pTsSHP2aNxsw8AHGSX9dZVymSclkUV8irk+ztfEfs7aLA==" + expectedRandom, err := base64.StdEncoding.DecodeString(randomB64) + require.NoError(t, err) + weirdMacOSCase := "wx/1mQ49TpdLRfvVjQhXNSe8RB3hjZEarqYp5XVIxpSbvOhQSs8hP2TgucID1IputbA8JC6CbsUpcVae3+8hRNqs5pTsSHP2aNxsw8AHGSX9dZVymSclkUV8irk+ztfEfs7aLA%3D%3D" + expectedWeirdMacOSCase, err := base64.StdEncoding.DecodeString(strings.ReplaceAll(weirdMacOSCase, "%3D", "=")) + require.NoError(t, err) type args struct { r *http.Request } @@ -21,6 +33,22 @@ func Test_decodeRequest(t *testing.T) { want request wantErr bool }{ + { + name: "fail/invalid-query", + args: args{ + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=bla;message=invalid-separator", http.NoBody), + }, + want: request{}, + wantErr: true, + }, + { + name: "fail/empty-operation", + args: args{ + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=", http.NoBody), + }, + want: request{}, + wantErr: true, + }, { name: "fail/unsupported-method", args: args{ @@ -37,6 +65,14 @@ func Test_decodeRequest(t *testing.T) { want: request{}, wantErr: true, }, + { + name: "fail/get-PKIOperation-empty-message", + args: args{ + r: httptest.NewRequest(http.MethodGet, "http://scep:8080/?operation=PKIOperation&message=", http.NoBody), + }, + want: request{}, + wantErr: true, + }, { name: "fail/get-PKIOperation", args: args{ @@ -86,6 +122,39 @@ func Test_decodeRequest(t *testing.T) { }, wantErr: false, }, + { + name: "ok/get-PKIOperation-escaped", + args: args{ + r: httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://scep:8080/?operation=PKIOperation&message=%s", url.QueryEscape(randomB64)), http.NoBody), + }, + want: request{ + Operation: "PKIOperation", + Message: expectedRandom, + }, + wantErr: false, + }, + { + name: "ok/get-PKIOperation-not-escaped", // bit of a special case, but this is supported because of the macOS case now + args: args{ + r: httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://scep:8080/?operation=PKIOperation&message=%s", randomB64), http.NoBody), + }, + want: request{ + Operation: "PKIOperation", + Message: expectedRandom, + }, + wantErr: false, + }, + { + name: "ok/get-PKIOperation-weird-macos-case", // a special case for macOS, which seems to result in the message not arriving fully percent-encoded + args: args{ + r: httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://scep:8080/?operation=PKIOperation&message=%s", weirdMacOSCase), http.NoBody), + }, + want: request{ + Operation: "PKIOperation", + Message: expectedWeirdMacOSCase, + }, + wantErr: false, + }, { name: "ok/post-PKIOperation", args: args{ @@ -101,13 +170,14 @@ func Test_decodeRequest(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := decodeRequest(tt.args.r) - if (err != nil) != tt.wantErr { - t.Errorf("decodeRequest() error = %v, wantErr %v", err, tt.wantErr) + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.want, got) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("decodeRequest() = %v, want %v", got, tt.want) - } + + assert.NoError(t, err) + assert.Equal(t, tt.want, got) }) } } diff --git a/scep/authority.go b/scep/authority.go index a7333aa7..e2aa759e 100644 --- a/scep/authority.go +++ b/scep/authority.go @@ -2,14 +2,15 @@ package scep import ( "context" + "crypto" "crypto/x509" "errors" "fmt" - "net/url" + "sync" - microx509util "github.com/micromdm/scep/v2/cryptoutil/x509util" - microscep "github.com/micromdm/scep/v2/scep" - "go.mozilla.org/pkcs7" + "github.com/smallstep/pkcs7" + smallscep "github.com/smallstep/scep" + smallscepx509util "github.com/smallstep/scep/x509util" "go.step.sm/crypto/x509util" @@ -18,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{} @@ -42,24 +48,14 @@ func FromContext(ctx context.Context) (a *Authority, ok bool) { // MustFromContext returns the current authority from the given context. It will // panic if the authority is not in the context. func MustFromContext(ctx context.Context) *Authority { - if a, ok := FromContext(ctx); !ok { + var ( + a *Authority + ok bool + ) + if a, ok = FromContext(ctx); !ok { panic("scep authority is not in the context") - } else { - return a } -} - -// 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 + return a } // SignAuthority is the interface for a signing authority @@ -70,24 +66,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 + } + + 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 } - // 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 + 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 authority, nil + 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,87 +148,58 @@ 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, _ ...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 } // DecryptPKIEnvelope decrypts an enveloped message -func (a *Authority) DecryptPKIEnvelope(_ context.Context, msg *PKIMessage) error { +func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error { p7c, err := pkcs7.Parse(msg.P7.Content) if err != nil { 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) } @@ -197,30 +207,33 @@ func (a *Authority) DecryptPKIEnvelope(_ context.Context, msg *PKIMessage) error msg.pkiEnvelope = envelope switch msg.MessageType { - case microscep.CertRep: - certs, err := microscep.CACerts(msg.pkiEnvelope) + case smallscep.CertRep: + certs, err := smallscep.CACerts(msg.pkiEnvelope) if err != nil { return fmt.Errorf("error extracting CA certs from pkcs7 degenerate data: %w", err) } msg.CertRepMessage.Certificate = certs[0] return nil - case microscep.PKCSReq, microscep.UpdateReq, microscep.RenewalReq: + case smallscep.PKCSReq, smallscep.UpdateReq, smallscep.RenewalReq: csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope) if err != nil { return fmt.Errorf("parse CSR from pkiEnvelope: %w", err) } - // check for challengePassword - cp, err := microx509util.ParseChallengePassword(msg.pkiEnvelope) + if err := csr.CheckSignature(); err != nil { + return fmt.Errorf("invalid CSR signature; %w", err) + } + // extract the challenge password + cp, err := smallscepx509util.ParseChallengePassword(msg.pkiEnvelope) if err != nil { return fmt.Errorf("parse challenge password in pkiEnvelope: %w", err) } - msg.CSRReqMessage = µscep.CSRReqMessage{ + msg.CSRReqMessage = &smallscep.CSRReqMessage{ RawDecrypted: msg.pkiEnvelope, CSR: csr, ChallengePassword: cp, } return nil - case microscep.GetCRL, microscep.GetCert, microscep.CertPoll: + case smallscep.GetCRL, smallscep.GetCert, smallscep.CertPoll: return errors.New("not implemented") } @@ -235,10 +248,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 { @@ -306,22 +316,15 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m cert := certChain[0] // and create a degenerate cert structure - deg, err := microscep.DegenerateCertificates([]*x509.Certificate{cert}) + deg, err := smallscep.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{ @@ -332,11 +335,11 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m }, { Type: oidSCEPpkiStatus, - Value: microscep.SUCCESS, + Value: smallscep.SUCCESS, }, { Type: oidSCEPmessageType, - Value: microscep.CertRep, + Value: smallscep.CertRep, }, { Type: oidSCEPrecipientNonce, @@ -359,10 +362,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 } @@ -372,8 +378,8 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m } cr := &CertRepMessage{ - PKIStatus: microscep.SUCCESS, - RecipientNonce: microscep.RecipientNonce(msg.SenderNonce), + PKIStatus: smallscep.SUCCESS, + RecipientNonce: smallscep.RecipientNonce(msg.SenderNonce), Certificate: cert, degenerate: deg, } @@ -382,15 +388,37 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m crepMsg := &PKIMessage{ Raw: certRepBytes, TransactionID: msg.TransactionID, - MessageType: microscep.CertRep, + MessageType: smallscep.CertRep, CertRepMessage: cr, } 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(_ context.Context, _ *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{ { @@ -399,7 +427,7 @@ func (a *Authority) CreateFailureResponse(_ context.Context, _ *x509.Certificate }, { Type: oidSCEPpkiStatus, - Value: microscep.FAILURE, + Value: smallscep.FAILURE, }, { Type: oidSCEPfailInfo, @@ -411,7 +439,7 @@ func (a *Authority) CreateFailureResponse(_ context.Context, _ *x509.Certificate }, { Type: oidSCEPmessageType, - Value: microscep.CertRep, + Value: smallscep.CertRep, }, { Type: oidSCEPsenderNonce, @@ -429,8 +457,13 @@ func (a *Authority) CreateFailureResponse(_ context.Context, _ *x509.Certificate 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 } @@ -440,16 +473,16 @@ func (a *Authority) CreateFailureResponse(_ context.Context, _ *x509.Certificate } cr := &CertRepMessage{ - PKIStatus: microscep.FAILURE, - FailInfo: microscep.FailInfo(info), - RecipientNonce: microscep.RecipientNonce(msg.SenderNonce), + PKIStatus: smallscep.FAILURE, + FailInfo: smallscep.FailInfo(info), + RecipientNonce: smallscep.RecipientNonce(msg.SenderNonce), } // create a CertRep message from the original crepMsg := &PKIMessage{ Raw: certRepBytes, TransactionID: msg.TransactionID, - MessageType: microscep.CertRep, + MessageType: smallscep.CertRep, CertRepMessage: cr, } @@ -458,10 +491,7 @@ func (a *Authority) CreateFailureResponse(_ context.Context, _ *x509.Certificate // 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 { @@ -477,10 +507,63 @@ func (a *Authority) GetCACaps(ctx context.Context) []string { return caps } -func (a *Authority) ValidateChallenge(ctx context.Context, challenge, transactionID string) error { - p, err := provisionerFromContext(ctx) - if err != nil { - return err +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()) } - return p.ValidateChallenge(ctx, challenge, transactionID) + + 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..e7e786ae --- /dev/null +++ b/scep/authority_test.go @@ -0,0 +1,73 @@ +package scep + +import ( + "crypto/x509" + "crypto/x509/pkix" + "testing" + + "github.com/smallstep/pkcs7" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "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 8120057e..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 GetCapabilities() []string ShouldIncludeRootInChain() bool + ShouldIncludeIntermediateInChain() bool + GetDecrypter() (*x509.Certificate, crypto.Decrypter) + GetSigner() (*x509.Certificate, crypto.Signer) GetContentEncryptionAlgorithm() int - ValidateChallenge(ctx context.Context, challenge, transactionID string) error + 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/scep.go b/scep/scep.go index 372a5436..b89ed0ac 100644 --- a/scep/scep.go +++ b/scep/scep.go @@ -5,12 +5,12 @@ import ( "crypto/x509" "encoding/asn1" - microscep "github.com/micromdm/scep/v2/scep" - "go.mozilla.org/pkcs7" + "github.com/smallstep/pkcs7" + smallscep "github.com/smallstep/scep" ) // FailInfoName models the name/value of failInfo -type FailInfoName microscep.FailInfo +type FailInfoName smallscep.FailInfo // FailInfo models a failInfo object consisting of a // name/identifier and a failInfoText, the latter of @@ -35,10 +35,10 @@ var ( // PKIMessage defines the possible SCEP message types type PKIMessage struct { - microscep.TransactionID - microscep.MessageType - microscep.SenderNonce - *microscep.CSRReqMessage + smallscep.TransactionID + smallscep.MessageType + smallscep.SenderNonce + *smallscep.CSRReqMessage *CertRepMessage @@ -57,9 +57,9 @@ type PKIMessage struct { // CertRepMessage is a type of PKIMessage type CertRepMessage struct { - microscep.PKIStatus - microscep.RecipientNonce - microscep.FailInfo + smallscep.PKIStatus + smallscep.RecipientNonce + smallscep.FailInfo Certificate *x509.Certificate diff --git a/scep/service.go b/scep/service.go deleted file mode 100644 index 85f7c73f..00000000 --- a/scep/service.go +++ /dev/null @@ -1,28 +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 -} - -// NewService returns a new Service type. -func NewService(_ 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 5571bf86..86c5bc86 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -4,5 +4,5 @@ Please note that `install-step-ra.sh` is referenced on the `files.smallstep.com` ## badger-migration -badger-migration is a tool that allows migrating data data from BadgerDB (v1 or +badger-migration is a tool that allows migrating data from BadgerDB (v1 or v2) to MySQL or PostgreSQL. diff --git a/webhook/types.go b/webhook/types.go index 9eda0578..5e0e4d29 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 @@ -69,7 +70,8 @@ type X5CCertificate struct { // RequestBody is the body sent to webhook servers. type RequestBody struct { - Timestamp time.Time `json:"timestamp"` + Timestamp time.Time `json:"timestamp"` + ProvisionerName string `json:"provisionerName,omitempty"` // Only set after successfully completing acme device-attest-01 challenge AttestationData *AttestationData `json:"attestationData,omitempty"` // Set for most provisioners, but not acme or scep @@ -79,9 +81,11 @@ type RequestBody struct { X509Certificate *X509Certificate `json:"x509Certificate,omitempty"` SSHCertificateRequest *SSHCertificateRequest `json:"sshCertificateRequest,omitempty"` SSHCertificate *SSHCertificate `json:"sshCertificate,omitempty"` - // Only set for SCEP challenge validation requests - SCEPChallenge string `json:"scepChallenge,omitempty"` - SCEPTransactionID string `json:"scepTransactionID,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