From 4964a10e69574d4c8a003c8f611a48e39472f8ae Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Mon, 8 Jan 2024 14:29:53 +0000 Subject: [PATCH 01/27] first pass for implementing kms support Signed-off-by: chaosinthecrd --- cryptoutil/util.go | 72 +++++++ go.mod | 15 ++ go.sum | 30 +++ signer/kms/aws/client.go | 373 +++++++++++++++++++++++++++++++++++ signer/kms/aws/go.mod | 29 +++ signer/kms/aws/go.sum | 44 +++++ signer/kms/aws/signer.go | 232 ++++++++++++++++++++++ signer/kms/signerprovider.go | 140 +++++++++++++ 8 files changed, 935 insertions(+) create mode 100644 signer/kms/aws/client.go create mode 100644 signer/kms/aws/go.mod create mode 100644 signer/kms/aws/go.sum create mode 100644 signer/kms/aws/signer.go create mode 100644 signer/kms/signerprovider.go diff --git a/cryptoutil/util.go b/cryptoutil/util.go index 84d86f48..3685689e 100644 --- a/cryptoutil/util.go +++ b/cryptoutil/util.go @@ -20,6 +20,7 @@ import ( "crypto/x509" "encoding/hex" "encoding/pem" + "errors" "fmt" "io" ) @@ -147,3 +148,74 @@ func TryParseCertificate(data []byte) (*x509.Certificate, error) { return cert, nil } + +// ComputeDigestForSigning calculates the digest value for the specified message using a hash function selected by the following process: +// +// - if a digest value is already specified in a SignOption and the length of the digest matches that of the selected hash function, the +// digest value will be returned without any further computation +// - if a hash function is given using WithCryptoSignerOpts(opts) as a SignOption, it will be used (if it is in the supported list) +// - otherwise defaultHashFunc will be used (if it is in the supported list) +func ComputeDigestForSigning(rawMessage io.Reader, defaultHashFunc crypto.Hash, supportedHashFuncs []crypto.Hash) (digest []byte, hashedWith crypto.Hash, err error) { + var cryptoSignerOpts crypto.SignerOpts = defaultHashFunc + hashedWith = cryptoSignerOpts.HashFunc() + if !isSupportedAlg(hashedWith, supportedHashFuncs) { + return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) + } + if len(digest) > 0 { + if hashedWith != crypto.Hash(0) && len(digest) != hashedWith.Size() { + err = errors.New("unexpected length of digest for hash function specified") + } + return + } + digest, err = hashMessage(rawMessage, hashedWith) + return +} + +// ComputeDigestForVerifying calculates the digest value for the specified message using a hash function selected by the following process: +// +// - if a digest value is already specified in a SignOption and the length of the digest matches that of the selected hash function, the +// digest value will be returned without any further computation +// - if a hash function is given using WithCryptoSignerOpts(opts) as a SignOption, it will be used (if it is in the supported list) +// - otherwise defaultHashFunc will be used (if it is in the supported list) +func ComputeDigestForVerifying(rawMessage io.Reader, defaultHashFunc crypto.Hash, supportedHashFuncs []crypto.Hash) (digest []byte, hashedWith crypto.Hash, err error) { + var cryptoSignerOpts crypto.SignerOpts = defaultHashFunc + hashedWith = cryptoSignerOpts.HashFunc() + if !isSupportedAlg(hashedWith, supportedHashFuncs) { + return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) + } + if len(digest) > 0 { + if hashedWith != crypto.Hash(0) && len(digest) != hashedWith.Size() { + err = errors.New("unexpected length of digest for hash function specified") + } + return + } + digest, err = hashMessage(rawMessage, hashedWith) + return +} + +func isSupportedAlg(alg crypto.Hash, supportedAlgs []crypto.Hash) bool { + if supportedAlgs == nil { + return true + } + for _, supportedAlg := range supportedAlgs { + if alg == supportedAlg { + return true + } + } + return false +} + +func hashMessage(rawMessage io.Reader, hashFunc crypto.Hash) ([]byte, error) { + if rawMessage == nil { + return nil, errors.New("message cannot be nil") + } + if hashFunc == crypto.Hash(0) { + return io.ReadAll(rawMessage) + } + hasher := hashFunc.New() + // avoids reading entire message into memory + if _, err := io.Copy(hasher, rawMessage); err != nil { + return nil, fmt.Errorf("hashing message: %w", err) + } + return hasher.Sum(nil), nil +} diff --git a/go.mod b/go.mod index afee1830..2d53c0cb 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,16 @@ module github.com/in-toto/go-witness go 1.19 require ( + github.com/aws/aws-sdk-go-v2 v1.17.5 + github.com/aws/aws-sdk-go-v2/config v1.18.14 + github.com/aws/aws-sdk-go-v2/service/kms v1.20.4 github.com/davecgh/go-spew v1.1.1 github.com/digitorus/pkcs7 v0.0.0-20230220124406-51331ccfc40f github.com/digitorus/timestamp v0.0.0-20230220124323-d542479a2425 github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d github.com/go-git/go-git/v5 v5.11.0 github.com/in-toto/archivista v0.2.0 + github.com/jellydator/ttlcache/v3 v3.1.1 github.com/mattn/go-isatty v0.0.20 github.com/open-policy-agent/opa v0.49.2 github.com/owenrumney/go-sarif v1.1.1 @@ -25,6 +29,16 @@ require ( dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.14 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.4 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/coreos/go-oidc/v3 v3.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -53,6 +67,7 @@ require ( github.com/zclconf/go-cty v1.12.1 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index dd3809c3..4f909f26 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,32 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdK github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/aws/aws-sdk-go v1.44.334 h1:h2bdbGb//fez6Sv6PaYv868s9liDeoYM6hYsAqTB4MU= github.com/aws/aws-sdk-go v1.44.334/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4= +github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.14 h1:rI47jCe0EzuJlAO5ptREe3LIBAyP5c7gR3wjyYVjuOM= +github.com/aws/aws-sdk-go-v2/config v1.18.14/go.mod h1:0pI6JQBHKwd0JnwAZS3VCapLKMO++UL2BOkWwyyzTnA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.14 h1:jE34fUepssrhmYpvPpdbd+d39PHpuignDpNPNJguP60= +github.com/aws/aws-sdk-go-v2/credentials v1.13.14/go.mod h1:85ckagDuzdIOnZRwws1eLKnymJs3ZM1QwVC1XcuNGOY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 h1:Kbiv9PGnQfG/imNI4L/heyUXvzKmcWSBeDvkrQz5pFc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23/go.mod h1:mOtmAg65GT1HIL/HT/PynwPbS+UG0BgCZ6vhkPqnxWo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 h1:IVx9L7YFhpPq0tTnGo8u8TpluFu7nAn9X3sUDMb11c0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30/go.mod h1:vsbq62AOBwQ1LJ/GWKFxX8beUEYeRp/Agitrxee2/qM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 h1:QoOybhwRfciWUBbZ0gp9S7XaDnCuSTeK/fySB99V1ls= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23/go.mod h1:9uPh+Hrz2Vn6oMnQYiUi/zbh3ovbnQk19YKINkQny44= +github.com/aws/aws-sdk-go-v2/service/kms v1.20.4 h1:FOY3JSIwgItCdaeuLKjtijD8Enx6BHy5nSS/V6COOeA= +github.com/aws/aws-sdk-go-v2/service/kms v1.20.4/go.mod h1:oTK4GAHgyFSGKzhReYfD19/vjtgUOPwCbm7v5MgWLW4= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.3 h1:bUeZTWfF1vBdZnoNnnq70rB/CzdZD7NR2Jg2Ax+rvjA= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.3/go.mod h1:jtLIhd+V+lft6ktxpItycqHqiVXrPIRjWIsFIlzMriw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3 h1:G/+7NUi+q+H0LG3v32jfV4OkaQIcpI92g0owbXKk6NY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3/go.mod h1:zVwRrfdSmbRZWkUkWjOItY7SOalnFnq/Yg2LVPqDjwc= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.4 h1:j0USUNbl9c/8tBJ8setEbwxc7wva0WyoeAaFRiyTUT8= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.4/go.mod h1:1mKZHLLpDMHTNSYPJ7qrcnCQdHCWsNQaT0xRvq2u80s= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= @@ -106,6 +132,8 @@ github.com/in-toto/archivista v0.2.0 h1:FViuHMVVETborvOqlmSYdROY8RmX3CO0V0MOhU/R github.com/in-toto/archivista v0.2.0/go.mod h1:qt9uN4TkHWUgR5A2wxRqQIBizSl32P2nI2AjESskkr0= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= +github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -213,6 +241,7 @@ github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtC go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.step.sm/crypto v0.25.2 h1:NgoI3bcNF0iLI+Rwq00brlJyFfMqseLOa8L8No3Daog= go.step.sm/crypto v0.25.2/go.mod h1:4pUEuZ+4OAf2f70RgW5oRv/rJudibcAAWQg5prC3DT8= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -255,6 +284,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go new file mode 100644 index 00000000..1287924c --- /dev/null +++ b/signer/kms/aws/client.go @@ -0,0 +1,373 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package aws implement the interface with amazon aws kms service +package aws + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "io" + "net/http" + "os" + "regexp" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + akms "github.com/aws/aws-sdk-go-v2/service/kms" + "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/signer/kms" + ttlcache "github.com/jellydator/ttlcache/v3" +) + +func init() { + kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { + return LoadSignerVerifier(ctx, ksp) + }) +} + +const ( + cacheKey = "signer" + // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets + ReferenceScheme = "awskms://" +) + +type awsClient struct { + client *akms.Client + endpoint string + keyID string + alias string + keyCache *ttlcache.Cache[string, cmk] +} + +var ( + errKMSReference = errors.New("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)") + + // Key ID/ALIAS/ARN conforms to KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id + // Key format examples: + // Key ID: awskms:///1234abcd-12ab-34cd-56ef-1234567890ab + // Key ID with endpoint: awskms://localhost:4566/1234abcd-12ab-34cd-56ef-1234567890ab + // Key ARN: awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab + // Key ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab + // Alias name: awskms:///alias/ExampleAlias + // Alias name with endpoint: awskms://localhost:4566/alias/ExampleAlias + // Alias ARN: awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias + // Alias ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias + uuidRE = `m?r?k?-?[A-Fa-f0-9]{8}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{12}` + arnRE = `arn:(?:aws|aws-us-gov|aws-cn):kms:[a-z0-9-]+:\d{12}:` + hostRE = `([^/]*)/` + keyIDRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + uuidRE + `)$`) + keyARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `key/` + uuidRE + `)$`) + aliasNameRE = regexp.MustCompile(`^awskms://` + hostRE + `((alias/.*))$`) + aliasARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `(alias/.*))$`) + allREs = []*regexp.Regexp{keyIDRE, keyARNRE, aliasNameRE, aliasARNRE} +) + +// ValidReference returns a non-nil error if the reference string is invalid +func ValidReference(ref string) error { + for _, re := range allREs { + if re.MatchString(ref) { + return nil + } + } + return errKMSReference +} + +// ParseReference parses an awskms-scheme URI into its constituent parts. +func ParseReference(resourceID string) (endpoint, keyID, alias string, err error) { + var v []string + for _, re := range allREs { + v = re.FindStringSubmatch(resourceID) + if len(v) >= 3 { + endpoint, keyID = v[1], v[2] + if len(v) == 4 { + alias = v[3] + } + return + } + } + err = fmt.Errorf("invalid awskms format %q", resourceID) + return +} + +func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, error) { + if err := ValidReference(ksp.Reference); err != nil { + return nil, err + } + a := &awsClient{} + var err error + a.endpoint, a.keyID, a.alias, err = ParseReference(ksp.Reference) + if err != nil { + return nil, err + } + + if err := a.setupClient(ctx, ksp); err != nil { + return nil, err + } + + a.keyCache = ttlcache.New[string, cmk]( + ttlcache.WithDisableTouchOnHit[string, cmk](), + ) + + return a, nil +} + +func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) (err error) { + opts := []func(*config.LoadOptions) error{} + if a.endpoint != "" { + opts = append(opts, config.WithEndpointResolverWithOptions( + aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) { + return aws.Endpoint{ + URL: "https://" + a.endpoint, + }, nil + }), + )) + } + if os.Getenv("AWS_TLS_INSECURE_SKIP_VERIFY") == "1" { + opts = append(opts, config.WithHTTPClient(&http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // nolint: gosec + }, + })) + } + + cfg, err := config.LoadDefaultConfig(ctx, opts...) + if err != nil { + return fmt.Errorf("loading AWS config: %w", err) + } + + a.client = akms.NewFromConfig(cfg) + return +} + +type cmk struct { + KeyMetadata *types.KeyMetadata + PublicKey crypto.PublicKey +} + +func (c *cmk) HashFunc() crypto.Hash { + switch c.KeyMetadata.SigningAlgorithms[0] { + case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecEcdsaSha256: + return crypto.SHA256 + case types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecEcdsaSha384: + return crypto.SHA384 + case types.SigningAlgorithmSpecRsassaPssSha512, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512, types.SigningAlgorithmSpecEcdsaSha512: + return crypto.SHA512 + default: + return 0 + } +} + +func (c *cmk) Verifier() (cryptoutil.Verifier, error) { + switch c.KeyMetadata.SigningAlgorithms[0] { + case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPssSha512: + pub, ok := c.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + return cryptoutil.NewRSAVerifier(pub, c.HashFunc()), nil + case types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512: + pub, ok := c.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + return cryptoutil.NewRSAVerifier(pub, c.HashFunc()), nil + case types.SigningAlgorithmSpecEcdsaSha256, types.SigningAlgorithmSpecEcdsaSha384, types.SigningAlgorithmSpecEcdsaSha512: + pub, ok := c.PublicKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not ecdsa") + } + return cryptoutil.NewECDSAVerifier(pub, c.HashFunc()), nil + default: + return nil, fmt.Errorf("signing algorithm unsupported") + } +} + +func (a *awsClient) fetchCMK(ctx context.Context) (*cmk, error) { + var err error + cmk := &cmk{} + cmk.PublicKey, err = a.fetchPublicKey(ctx) + if err != nil { + return nil, err + } + cmk.KeyMetadata, err = a.fetchKeyMetadata(ctx) + if err != nil { + return nil, err + } + return cmk, nil +} + +func (a *awsClient) getHashFunc(ctx context.Context) (crypto.Hash, error) { + cmk, err := a.getCMK(ctx) + if err != nil { + return 0, err + } + return cmk.HashFunc(), nil +} + +func (a *awsClient) getCMK(ctx context.Context) (*cmk, error) { + var lerr error + loader := ttlcache.LoaderFunc[string, cmk]( + func(c *ttlcache.Cache[string, cmk], key string) *ttlcache.Item[string, cmk] { + var k *cmk + k, lerr = a.fetchCMK(ctx) + if lerr == nil { + return c.Set(cacheKey, *k, time.Second*300) + } + return nil + }, + ) + + item := a.keyCache.Get(cacheKey, ttlcache.WithLoader[string, cmk](loader)) + if lerr == nil { + cmk := item.Value() + return &cmk, nil + } + return nil, lerr +} + +func (a *awsClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { + if a.alias == "" { + return nil, errors.New("must use alias key format") + } + + // look for existing key first + cmk, err := a.getCMK(ctx) + if err == nil { + out := cmk.PublicKey + return out, nil + } + + // return error if not *kms.NotFoundException + var errNotFound *types.NotFoundException + if !errors.As(err, &errNotFound) { + return nil, fmt.Errorf("looking up key: %w", err) + } + + usage := types.KeyUsageTypeSignVerify + description := "Created by Sigstore" + key, err := a.client.CreateKey(ctx, &akms.CreateKeyInput{ + CustomerMasterKeySpec: types.CustomerMasterKeySpec(algorithm), + KeyUsage: usage, + Description: &description, + }) + if err != nil { + return nil, fmt.Errorf("creating key: %w", err) + } + + _, err = a.client.CreateAlias(ctx, &akms.CreateAliasInput{ + AliasName: &a.alias, + TargetKeyId: key.KeyMetadata.KeyId, + }) + if err != nil { + return nil, fmt.Errorf("creating alias %q: %w", a.alias, err) + } + + cmk, err = a.getCMK(ctx) + if err != nil { + return nil, fmt.Errorf("retrieving PublicKey from cache: %w", err) + } + + return cmk.PublicKey, err +} + +func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { + cmk, err := a.getCMK(ctx) + if err != nil { + return err + } + verifier, err := cmk.Verifier() + if err != nil { + return err + } + + s, err := io.ReadAll(sig) + if err != nil { + return err + } + + return verifier.Verify(message, s) +} + +func (a *awsClient) verifyRemotely(ctx context.Context, sig, digest []byte) error { + cmk, err := a.getCMK(ctx) + if err != nil { + return err + } + alg := cmk.KeyMetadata.SigningAlgorithms[0] + messageType := types.MessageTypeDigest + if _, err := a.client.Verify(ctx, &akms.VerifyInput{ + KeyId: &a.keyID, + Message: digest, + MessageType: messageType, + Signature: sig, + SigningAlgorithm: alg, + }); err != nil { + return fmt.Errorf("unable to verify signature: %w", err) + } + return nil +} + +func (a *awsClient) sign(ctx context.Context, digest []byte, _ crypto.Hash) ([]byte, error) { + cmk, err := a.getCMK(ctx) + if err != nil { + return nil, err + } + alg := cmk.KeyMetadata.SigningAlgorithms[0] + + messageType := types.MessageTypeDigest + out, err := a.client.Sign(ctx, &akms.SignInput{ + KeyId: &a.keyID, + Message: digest, + MessageType: messageType, + SigningAlgorithm: alg, + }) + if err != nil { + return nil, fmt.Errorf("signing with kms: %w", err) + } + return out.Signature, nil +} + +func (a *awsClient) fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) { + out, err := a.client.GetPublicKey(ctx, &akms.GetPublicKeyInput{ + KeyId: &a.keyID, + }) + if err != nil { + return nil, fmt.Errorf("getting public key: %w", err) + } + key, err := x509.ParsePKIXPublicKey(out.PublicKey) + if err != nil { + return nil, fmt.Errorf("parsing public key: %w", err) + } + return key, nil +} + +func (a *awsClient) fetchKeyMetadata(ctx context.Context) (*types.KeyMetadata, error) { + out, err := a.client.DescribeKey(ctx, &akms.DescribeKeyInput{ + KeyId: &a.keyID, + }) + if err != nil { + return nil, fmt.Errorf("getting key metadata: %w", err) + } + return out.KeyMetadata, nil +} diff --git a/signer/kms/aws/go.mod b/signer/kms/aws/go.mod new file mode 100644 index 00000000..54b316db --- /dev/null +++ b/signer/kms/aws/go.mod @@ -0,0 +1,29 @@ +module github.com/in-toto/go-witness/signer/kms/aws + +replace github.com/in-toto/go-witness => ../../../ + +go 1.21 + +require ( + github.com/aws/aws-sdk-go-v2 v1.24.0 + github.com/aws/aws-sdk-go-v2/config v1.26.2 + github.com/aws/aws-sdk-go-v2/service/kms v1.27.7 + github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 + github.com/jellydator/ttlcache/v3 v3.1.1 +) + +require ( + github.com/aws/aws-sdk-go-v2/credentials v1.16.13 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // 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.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 // indirect + github.com/aws/smithy-go v1.19.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect + golang.org/x/sync v0.5.0 // indirect +) diff --git a/signer/kms/aws/go.sum b/signer/kms/aws/go.sum new file mode 100644 index 00000000..548d2378 --- /dev/null +++ b/signer/kms/aws/go.sum @@ -0,0 +1,44 @@ +github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= +github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/config v1.26.2 h1:+RWLEIWQIGgrz2pBPAUoGgNGs1TOyF4Hml7hCnYj2jc= +github.com/aws/aws-sdk-go-v2/config v1.26.2/go.mod h1:l6xqvUxt0Oj7PI/SUXYLNyZ9T/yBPn3YTQcJLLOdtR8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.13 h1:WLABQ4Cp4vXtXfOWOS3MEZKr6AAYUpMczLhgKtAjQ/8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.13/go.mod h1:Qg6x82FXwW0sJHzYruxGiuApNo31UEtJvXVSZAXeWiw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/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.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.7 h1:wN7AN7iOiAgT9HmdifZNSvbr6S7gSpLjSSOQHIaGmFc= +github.com/aws/aws-sdk-go-v2/service/kms v1.27.7/go.mod h1:D9FVDkZjkZnnFHymJ3fPVz0zOUlNSd0xcIIVmmrAac8= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 h1:HJeiuZ2fldpd0WqngyMR6KW7ofkXNLyOaHwEIGm39Cs= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.6/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= +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/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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= +github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= +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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go new file mode 100644 index 00000000..f0589f92 --- /dev/null +++ b/signer/kms/aws/signer.go @@ -0,0 +1,232 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aws + +import ( + "context" + "crypto" + "fmt" + "io" + + "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/in-toto/go-witness/cryptoutil" + kms "github.com/in-toto/go-witness/signer/kms" +) + +var awsSupportedAlgorithms = []types.CustomerMasterKeySpec{ + types.CustomerMasterKeySpecRsa2048, + types.CustomerMasterKeySpecRsa3072, + types.CustomerMasterKeySpecRsa4096, + types.CustomerMasterKeySpecEccNistP256, + types.CustomerMasterKeySpecEccNistP384, + types.CustomerMasterKeySpecEccNistP521, +} + +var awsSupportedHashFuncs = []crypto.Hash{ + crypto.SHA256, + crypto.SHA384, + crypto.SHA512, +} + +// SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service +type SignerVerifier struct { + client *awsClient +} + +// LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. +func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*SignerVerifier, error) { + a := &SignerVerifier{} + + var err error + a.client, err = newAWSClient(ctx, ksp) + if err != nil { + return nil, err + } + + return a, nil +} + +// NOTE: This might ben all wrong but setting it like so for now +// KeyID returnst the key identifier for the key used by this signer. +func (a *SignerVerifier) KeyID() (string, error) { + return a.client.keyID, nil +} + +// SignMessage signs the provided message using AWS KMS. If the message is provided, +// this method will compute the digest according to the hash function specified +// when the Signer was created. +// +// SignMessage recognizes the following Options listed in order of preference: +// +// - WithContext() +// +// - WithDigest() +// +// - WithCryptoSignerOpts() +// +// All other options are ignored if specified. +func (a *SignerVerifier) Sign(message io.Reader) ([]byte, error) { + var err error + ctx := context.Background() + var digest []byte + + var signerOpts crypto.SignerOpts + signerOpts, err = a.client.getHashFunc(ctx) + if err != nil { + return nil, fmt.Errorf("getting fetching default hash function: %w", err) + } + + hf := signerOpts.HashFunc() + + digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, awsSupportedHashFuncs) + if err != nil { + return nil, err + } + + return a.client.sign(ctx, digest, hf) +} + +// PublicKey returns the public key that can be used to verify signatures created by +// this signer. If the caller wishes to specify the context to use to obtain +// the public key, pass option.WithContext(desiredCtx). +// +// All other options are ignored if specified. +func (a *SignerVerifier) Verifier() (cryptoutil.Verifier, error) { + return a, nil +} + +// Bytes returns the bytes of the public key that can be used to verify signatures created by the signer. +func (a *SignerVerifier) Bytes() ([]byte, error) { + ctx := context.Background() + p, err := a.client.fetchPublicKey(ctx) + if err != nil { + return nil, err + } + + return cryptoutil.PublicPemBytes(p) +} + +// VerifySignature verifies the signature for the given message. Unless provided +// in an option, the digest of the message will be computed using the hash function specified +// when the SignerVerifier was created. +// +// This function returns nil if the verification succeeded, and an error message otherwise. +// +// This function recognizes the following Options listed in order of preference: +// +// - WithContext() +// +// - WithDigest() +// +// - WithRemoteVerification() +// +// - WithCryptoSignerOpts() +// +// All other options are ignored if specified. +func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { + ctx := context.Background() + var digest []byte + // var remoteVerification bool + + //for _, opt := range opts { + // opt.ApplyContext(&ctx) + // opt.ApplyDigest(&digest) + // opt.ApplyRemoteVerification(&remoteVerification) + //} + + var signerOpts crypto.SignerOpts + signerOpts, err = a.client.getHashFunc(ctx) + if err != nil { + return fmt.Errorf("getting hash func: %w", err) + } + hf := signerOpts.HashFunc() + + digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, awsSupportedHashFuncs) + if err != nil { + return err + } + + return a.client.verifyRemotely(ctx, sig, digest) +} + +// CreateKey attempts to create a new key in Vault with the specified algorithm. +func (a *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { + return a.client.createKey(ctx, algorithm) +} + +type cryptoSignerWrapper struct { + ctx context.Context + hashFunc crypto.Hash + sv *SignerVerifier + errFunc func(error) +} + +func (c cryptoSignerWrapper) Public() crypto.PublicKey { + ctx := context.Background() + + cmk, err := c.sv.client.getCMK(ctx) + if err != nil { + return nil + } + + return cmk.PublicKey +} + +func (c cryptoSignerWrapper) Sign(message io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { + //hashFunc := c.hashFunc + //if opts != nil { + // hashFunc = opts.HashFunc() + //} + //awsOptions := []signature.SignOption{ + // options.WithContext(c.ctx), + // options.WithDigest(digest), + // options.WithCryptoSignerOpts(hashFunc), + //} + + return c.sv.Sign(message) +} + +// CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object +// that allows the KMS to be used in APIs that only accept the standard golang objects +func (a *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { + defaultHf, err := a.client.getHashFunc(ctx) + if err != nil { + return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err) + } + + csw := &cryptoSignerWrapper{ + ctx: ctx, + sv: a, + hashFunc: defaultHf, + errFunc: errFunc, + } + + return csw, defaultHf, nil +} + +// SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service +func (*SignerVerifier) SupportedAlgorithms() []string { + s := make([]string, len(awsSupportedAlgorithms)) + for i := range awsSupportedAlgorithms { + s[i] = string(awsSupportedAlgorithms[i]) + } + return s +} + +// DefaultAlgorithm returns the default algorithm for the AWS KMS service +func (*SignerVerifier) DefaultAlgorithm() string { + return string(types.CustomerMasterKeySpecEccNistP256) +} diff --git a/signer/kms/signerprovider.go b/signer/kms/signerprovider.go new file mode 100644 index 00000000..d5f805fd --- /dev/null +++ b/signer/kms/signerprovider.go @@ -0,0 +1,140 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kms + +import ( + "context" + "crypto" + "fmt" + "strings" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/registry" + "github.com/in-toto/go-witness/signer" +) + +func init() { + signer.Register("kms", func() signer.SignerProvider { return New() }, + registry.StringConfigOption( + "ref", + "The KMS Reference URI to use for connecting to the KMS service", + "", + func(sp signer.SignerProvider, ref string) (signer.SignerProvider, error) { + ksp, ok := sp.(*KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + WithRef(ref)(ksp) + return ksp, nil + }, + ), + registry.StringConfigOption( + "hashType", + "The hash type to use for signing", + "", + func(sp signer.SignerProvider, hash string) (signer.SignerProvider, error) { + ksp, ok := sp.(*KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + WithHash(hash)(ksp) + return ksp, nil + }, + ), + ) +} + +type KMSSignerProvider struct { + Reference string + HashFunc crypto.Hash +} + +type Option func(*KMSSignerProvider) + +func WithRef(ref string) Option { + return func(ksp *KMSSignerProvider) { + ksp.Reference = ref + } +} + +func WithHash(hash string) Option { + return func(ksp *KMSSignerProvider) { + // case switch to match hash type string and set hashFunc + switch hash { + case "SHA224": + ksp.HashFunc = crypto.SHA224 + case "SHA256": + ksp.HashFunc = crypto.SHA256 + case "SHA384": + ksp.HashFunc = crypto.SHA384 + case "SHA512": + ksp.HashFunc = crypto.SHA512 + default: + ksp.HashFunc = crypto.SHA256 + } + } +} + +func New(opts ...Option) *KMSSignerProvider { + ksp := KMSSignerProvider{} + + for _, opt := range opts { + opt(&ksp) + } + + return &ksp +} + +// ProviderInit is a function that initializes provider-specific SignerVerifier. +// +// It takes a provider-specific resource ID and hash function, and returns a +// SignerVerifier using that resource, or any error that was encountered. +type ProviderInit func(context.Context, *KMSSignerProvider) (cryptoutil.Signer, error) + +// AddProvider adds the provider implementation into the local cache +func AddProvider(keyResourceID string, init ProviderInit) { + providersMap[keyResourceID] = init +} + +func (ksp *KMSSignerProvider) Signer(ctx context.Context) (cryptoutil.Signer, error) { + for ref, pi := range providersMap { + if strings.HasPrefix(ksp.Reference, ref) { + return pi(ctx, ksp) + } + } + return nil, &ProviderNotFoundError{ref: ksp.Reference} +} + +var providersMap = map[string]ProviderInit{} + +// SupportedProviders returns list of initialized providers +func SupportedProviders() []string { + keys := make([]string, 0, len(providersMap)) + for key := range providersMap { + keys = append(keys, key) + } + return keys +} + +// ProviderNotFoundError indicates that no matching KMS provider was found +type ProviderNotFoundError struct { + ref string +} + +func (e *ProviderNotFoundError) Error() string { + return fmt.Sprintf("no kms provider found for key reference: %s", e.ref) +} From 08538503028a8219de9d232071d33bcd5c5b05a3 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 9 Jan 2024 17:13:19 +0000 Subject: [PATCH 02/27] saving progress on hashtype flag for kms signer Signed-off-by: chaosinthecrd --- signer/kms/aws/signer.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index f0589f92..83028fa6 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -43,7 +43,8 @@ var awsSupportedHashFuncs = []crypto.Hash{ // SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service type SignerVerifier struct { - client *awsClient + client *awsClient + hashFunc crypto.Hash } // LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. @@ -56,6 +57,16 @@ func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*Signe return nil, err } + for _, hashFunc := range awsSupportedHashFuncs { + if hashFunc == ksp.HashFunc { + a.hashFunc = ksp.HashFunc + } + } + + if a.hashFunc == 0 { + return nil, fmt.Errorf("unsupported hash function: %v", ksp.HashFunc) + } + return a, nil } @@ -91,7 +102,7 @@ func (a *SignerVerifier) Sign(message io.Reader) ([]byte, error) { hf := signerOpts.HashFunc() - digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, awsSupportedHashFuncs) + digest, _, err = cryptoutil.ComputeDigestForSigning(message, hf, awsSupportedHashFuncs) if err != nil { return nil, err } From 1af768718451de7b1945491cc30989441b01ffd1 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 10 Jan 2024 17:10:19 +0000 Subject: [PATCH 03/27] saving kms progress for verifier Signed-off-by: chaosinthecrd --- registry/registry.go | 9 +++++++ signer/kms/signerprovider.go | 46 ++++++++++++++++++++++++++++++++++++ signer/registry.go | 23 +++++++++++++++++- verify.go | 2 +- 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 506f15a9..ea4c3e66 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -81,7 +81,16 @@ func (r Registry[T]) AllEntries() []Entry[T] { } return results +} +// AllEntries returns every Entry in the Registry that can be used as a Verifier +func (r Registry[T]) AllVerifierEntries() []Entry[T] { + results := make([]Entry[T], 0, len(r.entriesByName)) + for _, registration := range r.entriesByName { + results = append(results, registration) + } + + return results } // NewEntity creates a new entity with the the default options set diff --git a/signer/kms/signerprovider.go b/signer/kms/signerprovider.go index d5f805fd..645add04 100644 --- a/signer/kms/signerprovider.go +++ b/signer/kms/signerprovider.go @@ -51,6 +51,36 @@ func init() { return sp, fmt.Errorf("provided signer provider is not a kms signer provider") } + WithHash(hash)(ksp) + return ksp, nil + }, + ), + ) + signer.RegisterVerifier("kms", func() signer.VerifierProvider { return New() }, + registry.StringConfigOption( + "ref", + "The KMS Reference URI to use for connecting to the KMS service", + "", + func(sp signer.VerifierProvider, ref string) (signer.VerifierProvider, error) { + ksp, ok := sp.(*KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided verifier provider is not a kms verifier provider") + } + + WithRef(ref)(ksp) + return ksp, nil + }, + ), + registry.StringConfigOption( + "hashType", + "The hash type used for verifying", + "", + func(sp signer.VerifierProvider, hash string) (signer.VerifierProvider, error) { + ksp, ok := sp.(*KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + WithHash(hash)(ksp) return ksp, nil }, @@ -119,6 +149,22 @@ func (ksp *KMSSignerProvider) Signer(ctx context.Context) (cryptoutil.Signer, er return nil, &ProviderNotFoundError{ref: ksp.Reference} } +// NOTE: This is a temprorary implementation until we have a SignerVerifier interface +func (ksp *KMSSignerProvider) Verifier(ctx context.Context) (cryptoutil.Verifier, error) { + for ref, pi := range providersMap { + if strings.HasPrefix(ksp.Reference, ref) { + p, err := pi(ctx, ksp) + if err != nil { + return nil, err + } + + // we need to conver this into a cryptoutil.Verifier + return p.Verifier() + } + } + return nil, &ProviderNotFoundError{ref: ksp.Reference} +} + var providersMap = map[string]ProviderInit{} // SupportedProviders returns list of initialized providers diff --git a/signer/registry.go b/signer/registry.go index 3c828fde..b9d05d17 100644 --- a/signer/registry.go +++ b/signer/registry.go @@ -21,7 +21,10 @@ import ( "github.com/in-toto/go-witness/registry" ) -var signerRegistry = registry.New[SignerProvider]() +var ( + signerRegistry = registry.New[SignerProvider]() + verifierRegistry = registry.New[VerifierProvider]() +) type SignerProvider interface { Signer(context.Context) (cryptoutil.Signer, error) @@ -38,3 +41,21 @@ func RegistryEntries() []registry.Entry[SignerProvider] { func NewSignerProvider(name string, opts ...func(SignerProvider) (SignerProvider, error)) (SignerProvider, error) { return signerRegistry.NewEntity(name, opts...) } + +// NOTE: This is a temporary interface, and should not be used. It will be deprecated in a future release. +// The same applies to the functions that use this interface. +type VerifierProvider interface { + Verifier(context.Context) (cryptoutil.Verifier, error) +} + +func RegisterVerifier(name string, factory func() VerifierProvider, opts ...registry.Configurer) { + verifierRegistry.Register(name, factory, opts...) +} + +func VerifierRegistryEntries() []registry.Entry[VerifierProvider] { + return verifierRegistry.AllEntries() +} + +func NewVerifierProvider(name string, opts ...func(VerifierProvider) (VerifierProvider, error)) (VerifierProvider, error) { + return verifierRegistry.NewEntity(name, opts...) +} diff --git a/verify.go b/verify.go index bb20df6b..abc0d344 100644 --- a/verify.go +++ b/verify.go @@ -87,7 +87,7 @@ func Verify(ctx context.Context, policyEnvelope dsse.Envelope, policyVerifiers [ pubKeysById, err := pol.PublicKeyVerifiers() if err != nil { - return nil, fmt.Errorf("failed to get pulic keys from policy: %w", err) + return nil, fmt.Errorf("failed to get public keys from policy: %w", err) } pubkeys := make([]cryptoutil.Verifier, 0) From d14c4e90411827f0d24810d5ab1fd164c43f7ced Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 10 Jan 2024 17:11:00 +0000 Subject: [PATCH 04/27] updating go mod Signed-off-by: chaosinthecrd --- go.mod | 15 --------------- go.sum | 30 ------------------------------ 2 files changed, 45 deletions(-) diff --git a/go.mod b/go.mod index 2d53c0cb..afee1830 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,12 @@ module github.com/in-toto/go-witness go 1.19 require ( - github.com/aws/aws-sdk-go-v2 v1.17.5 - github.com/aws/aws-sdk-go-v2/config v1.18.14 - github.com/aws/aws-sdk-go-v2/service/kms v1.20.4 github.com/davecgh/go-spew v1.1.1 github.com/digitorus/pkcs7 v0.0.0-20230220124406-51331ccfc40f github.com/digitorus/timestamp v0.0.0-20230220124323-d542479a2425 github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d github.com/go-git/go-git/v5 v5.11.0 github.com/in-toto/archivista v0.2.0 - github.com/jellydator/ttlcache/v3 v3.1.1 github.com/mattn/go-isatty v0.0.20 github.com/open-policy-agent/opa v0.49.2 github.com/owenrumney/go-sarif v1.1.1 @@ -29,16 +25,6 @@ require ( dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.14 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.4 // indirect - github.com/aws/smithy-go v1.13.5 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/coreos/go-oidc/v3 v3.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -67,7 +53,6 @@ require ( github.com/zclconf/go-cty v1.12.1 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sync v0.5.0 // indirect golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 4f909f26..dd3809c3 100644 --- a/go.sum +++ b/go.sum @@ -19,32 +19,6 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdK github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/aws/aws-sdk-go v1.44.334 h1:h2bdbGb//fez6Sv6PaYv868s9liDeoYM6hYsAqTB4MU= github.com/aws/aws-sdk-go v1.44.334/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4= -github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.14 h1:rI47jCe0EzuJlAO5ptREe3LIBAyP5c7gR3wjyYVjuOM= -github.com/aws/aws-sdk-go-v2/config v1.18.14/go.mod h1:0pI6JQBHKwd0JnwAZS3VCapLKMO++UL2BOkWwyyzTnA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.14 h1:jE34fUepssrhmYpvPpdbd+d39PHpuignDpNPNJguP60= -github.com/aws/aws-sdk-go-v2/credentials v1.13.14/go.mod h1:85ckagDuzdIOnZRwws1eLKnymJs3ZM1QwVC1XcuNGOY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 h1:Kbiv9PGnQfG/imNI4L/heyUXvzKmcWSBeDvkrQz5pFc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23/go.mod h1:mOtmAg65GT1HIL/HT/PynwPbS+UG0BgCZ6vhkPqnxWo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 h1:IVx9L7YFhpPq0tTnGo8u8TpluFu7nAn9X3sUDMb11c0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30/go.mod h1:vsbq62AOBwQ1LJ/GWKFxX8beUEYeRp/Agitrxee2/qM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 h1:QoOybhwRfciWUBbZ0gp9S7XaDnCuSTeK/fySB99V1ls= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23/go.mod h1:9uPh+Hrz2Vn6oMnQYiUi/zbh3ovbnQk19YKINkQny44= -github.com/aws/aws-sdk-go-v2/service/kms v1.20.4 h1:FOY3JSIwgItCdaeuLKjtijD8Enx6BHy5nSS/V6COOeA= -github.com/aws/aws-sdk-go-v2/service/kms v1.20.4/go.mod h1:oTK4GAHgyFSGKzhReYfD19/vjtgUOPwCbm7v5MgWLW4= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.3 h1:bUeZTWfF1vBdZnoNnnq70rB/CzdZD7NR2Jg2Ax+rvjA= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.3/go.mod h1:jtLIhd+V+lft6ktxpItycqHqiVXrPIRjWIsFIlzMriw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3 h1:G/+7NUi+q+H0LG3v32jfV4OkaQIcpI92g0owbXKk6NY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3/go.mod h1:zVwRrfdSmbRZWkUkWjOItY7SOalnFnq/Yg2LVPqDjwc= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.4 h1:j0USUNbl9c/8tBJ8setEbwxc7wva0WyoeAaFRiyTUT8= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.4/go.mod h1:1mKZHLLpDMHTNSYPJ7qrcnCQdHCWsNQaT0xRvq2u80s= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= @@ -132,8 +106,6 @@ github.com/in-toto/archivista v0.2.0 h1:FViuHMVVETborvOqlmSYdROY8RmX3CO0V0MOhU/R github.com/in-toto/archivista v0.2.0/go.mod h1:qt9uN4TkHWUgR5A2wxRqQIBizSl32P2nI2AjESskkr0= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= -github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -241,7 +213,6 @@ github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtC go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.step.sm/crypto v0.25.2 h1:NgoI3bcNF0iLI+Rwq00brlJyFfMqseLOa8L8No3Daog= go.step.sm/crypto v0.25.2/go.mod h1:4pUEuZ+4OAf2f70RgW5oRv/rJudibcAAWQg5prC3DT8= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -284,7 +255,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 12deda238d202cfd84a37905203db60222df06a9 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Fri, 12 Jan 2024 18:17:11 +0000 Subject: [PATCH 05/27] saving progrsss Signed-off-by: chaosinthecrd --- signer/kms/aws/client.go | 8 +++++--- signer/kms/aws/signer.go | 15 +++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index 1287924c..aff01a8b 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -1,11 +1,10 @@ -// -// Copyright 2021 The Sigstore Authors. +// Copyright 2023 The Witness Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -296,6 +295,7 @@ func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { if err != nil { return err } + verifier, err := cmk.Verifier() if err != nil { return err @@ -314,6 +314,7 @@ func (a *awsClient) verifyRemotely(ctx context.Context, sig, digest []byte) erro if err != nil { return err } + alg := cmk.KeyMetadata.SigningAlgorithms[0] messageType := types.MessageTypeDigest if _, err := a.client.Verify(ctx, &akms.VerifyInput{ @@ -325,6 +326,7 @@ func (a *awsClient) verifyRemotely(ctx context.Context, sig, digest []byte) erro }); err != nil { return fmt.Errorf("unable to verify signature: %w", err) } + return nil } diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 83028fa6..5a93c232 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -1,11 +1,10 @@ -// -// Copyright 2021 The Sigstore Authors. +// Copyright 2023 The Witness Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -23,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/log" kms "github.com/in-toto/go-witness/signer/kms" ) @@ -170,7 +170,14 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { return err } - return a.client.verifyRemotely(ctx, sig, digest) + err = a.client.verifyRemotely(ctx, sig, digest) + if err != nil { + log.Info(err.Error()) + } else { + log.Info("Verification Succeeded") + } + + return err } // CreateKey attempts to create a new key in Vault with the specified algorithm. From eda08d57471c4fab99b817deec184a59bc8c70e8 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 17 Jan 2024 19:02:33 +0000 Subject: [PATCH 06/27] review of AWS KMS signer and adding scrappy implementation of GCP Signer - needs cleanup and testing Signed-off-by: chaosinthecrd --- signer/kms/aws/client.go | 19 +- signer/kms/aws/go.mod | 2 +- signer/kms/aws/signer.go | 69 ++---- signer/kms/gcp/client.go | 457 +++++++++++++++++++++++++++++++++++++++ signer/kms/gcp/go.mod | 54 +++++ signer/kms/gcp/go.sum | 217 +++++++++++++++++++ signer/kms/gcp/signer.go | 208 ++++++++++++++++++ 7 files changed, 961 insertions(+), 65 deletions(-) create mode 100644 signer/kms/gcp/client.go create mode 100644 signer/kms/gcp/go.mod create mode 100644 signer/kms/gcp/go.sum create mode 100644 signer/kms/gcp/signer.go diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index aff01a8b..7045fc08 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -51,14 +51,6 @@ const ( ReferenceScheme = "awskms://" ) -type awsClient struct { - client *akms.Client - endpoint string - keyID string - alias string - keyCache *ttlcache.Cache[string, cmk] -} - var ( errKMSReference = errors.New("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)") @@ -109,6 +101,14 @@ func ParseReference(resourceID string) (endpoint, keyID, alias string, err error return } +type awsClient struct { + client *akms.Client + endpoint string + keyID string + alias string + keyCache *ttlcache.Cache[string, cmk] +} + func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, error) { if err := ValidReference(ksp.Reference); err != nil { return nil, err @@ -264,7 +264,7 @@ func (a *awsClient) createKey(ctx context.Context, algorithm string) (crypto.Pub } usage := types.KeyUsageTypeSignVerify - description := "Created by Sigstore" + description := "Created by Witness" key, err := a.client.CreateKey(ctx, &akms.CreateKeyInput{ CustomerMasterKeySpec: types.CustomerMasterKeySpec(algorithm), KeyUsage: usage, @@ -290,6 +290,7 @@ func (a *awsClient) createKey(ctx context.Context, algorithm string) (crypto.Pub return cmk.PublicKey, err } +// At the moment this function lies unused, but it is here for future if necessary func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { cmk, err := a.getCMK(ctx) if err != nil { diff --git a/signer/kms/aws/go.mod b/signer/kms/aws/go.mod index 54b316db..6678a923 100644 --- a/signer/kms/aws/go.mod +++ b/signer/kms/aws/go.mod @@ -2,7 +2,7 @@ module github.com/in-toto/go-witness/signer/kms/aws replace github.com/in-toto/go-witness => ../../../ -go 1.21 +go 1.19 require ( github.com/aws/aws-sdk-go-v2 v1.24.0 diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 5a93c232..015e5e39 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -70,25 +70,16 @@ func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*Signe return a, nil } -// NOTE: This might ben all wrong but setting it like so for now -// KeyID returnst the key identifier for the key used by this signer. +// NOTE: This might be all wrong but setting it like so for now +// +// KeyID returns the key identifier for the key used by this signer. func (a *SignerVerifier) KeyID() (string, error) { return a.client.keyID, nil } -// SignMessage signs the provided message using AWS KMS. If the message is provided, +// Sign signs the provided message using AWS KMS. If the message is provided, // this method will compute the digest according to the hash function specified // when the Signer was created. -// -// SignMessage recognizes the following Options listed in order of preference: -// -// - WithContext() -// -// - WithDigest() -// -// - WithCryptoSignerOpts() -// -// All other options are ignored if specified. func (a *SignerVerifier) Sign(message io.Reader) ([]byte, error) { var err error ctx := context.Background() @@ -110,11 +101,7 @@ func (a *SignerVerifier) Sign(message io.Reader) ([]byte, error) { return a.client.sign(ctx, digest, hf) } -// PublicKey returns the public key that can be used to verify signatures created by -// this signer. If the caller wishes to specify the context to use to obtain -// the public key, pass option.WithContext(desiredCtx). -// -// All other options are ignored if specified. +// Verifier returns a cryptoutil.Verifier that can be used to verify signatures created by this signer. func (a *SignerVerifier) Verifier() (cryptoutil.Verifier, error) { return a, nil } @@ -130,33 +117,11 @@ func (a *SignerVerifier) Bytes() ([]byte, error) { return cryptoutil.PublicPemBytes(p) } -// VerifySignature verifies the signature for the given message. Unless provided -// in an option, the digest of the message will be computed using the hash function specified -// when the SignerVerifier was created. -// -// This function returns nil if the verification succeeded, and an error message otherwise. -// -// This function recognizes the following Options listed in order of preference: -// -// - WithContext() -// -// - WithDigest() -// -// - WithRemoteVerification() -// -// - WithCryptoSignerOpts() -// -// All other options are ignored if specified. +// VerifySignature verifies the signature for the given message, returning +// nil if the verification succeeded, and an error message otherwise. func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { ctx := context.Background() var digest []byte - // var remoteVerification bool - - //for _, opt := range opts { - // opt.ApplyContext(&ctx) - // opt.ApplyDigest(&digest) - // opt.ApplyRemoteVerification(&remoteVerification) - //} var signerOpts crypto.SignerOpts signerOpts, err = a.client.getHashFunc(ctx) @@ -173,13 +138,13 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { err = a.client.verifyRemotely(ctx, sig, digest) if err != nil { log.Info(err.Error()) - } else { - log.Info("Verification Succeeded") } return err } +// NOTE:Wondering if this should exist, at least for now +// // CreateKey attempts to create a new key in Vault with the specified algorithm. func (a *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { return a.client.createKey(ctx, algorithm) @@ -192,7 +157,7 @@ type cryptoSignerWrapper struct { errFunc func(error) } -func (c cryptoSignerWrapper) Public() crypto.PublicKey { +func (c *cryptoSignerWrapper) Public() crypto.PublicKey { ctx := context.Background() cmk, err := c.sv.client.getCMK(ctx) @@ -203,16 +168,10 @@ func (c cryptoSignerWrapper) Public() crypto.PublicKey { return cmk.PublicKey } -func (c cryptoSignerWrapper) Sign(message io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { - //hashFunc := c.hashFunc - //if opts != nil { - // hashFunc = opts.HashFunc() - //} - //awsOptions := []signature.SignOption{ - // options.WithContext(c.ctx), - // options.WithDigest(digest), - // options.WithCryptoSignerOpts(hashFunc), - //} +func (c *cryptoSignerWrapper) Sign(message io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { + if opts != nil { + c.hashFunc = opts.HashFunc() + } return c.sv.Sign(message) } diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go new file mode 100644 index 00000000..30f936f7 --- /dev/null +++ b/signer/kms/gcp/client.go @@ -0,0 +1,457 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package gcp implement the interface with google cloud kms service +package gcp + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "errors" + "fmt" + "hash/crc32" + "log" + "regexp" + "time" + + gcpkms "cloud.google.com/go/kms/apiv1" + "cloud.google.com/go/kms/apiv1/kmspb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/signer/kms" + "github.com/jellydator/ttlcache/v3" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" +) + +func init() { + kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { + return LoadSignerVerifier(ctx, ksp) + }) +} + +//nolint:revive +const ( + AlgorithmECDSAP256SHA256 = "ecdsa-p256-sha256" + AlgorithmECDSAP384SHA384 = "ecdsa-p384-sha384" + AlgorithmRSAPKCS1v152048SHA256 = "rsa-pkcs1v15-2048-sha256" + AlgorithmRSAPKCS1v153072SHA256 = "rsa-pkcs1v15-3072-sha256" + AlgorithmRSAPKCS1v154096SHA256 = "rsa-pkcs1v15-4096-sha256" + AlgorithmRSAPKCS1v154096SHA512 = "rsa-pkcs1v15-4096-sha512" + AlgorithmRSAPSS2048SHA256 = "rsa-pss-2048-sha256" + AlgorithmRSAPSS3072SHA256 = "rsa-pss-3072-sha256" + AlgorithmRSAPSS4096SHA256 = "rsa-pss-4096-sha256" + AlgorithmRSAPSS4096SHA512 = "rsa-pss-4096-sha512" +) + +var algorithmMap = map[string]kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm{ + AlgorithmECDSAP256SHA256: kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256, + AlgorithmECDSAP384SHA384: kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384, + AlgorithmRSAPKCS1v152048SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, + AlgorithmRSAPKCS1v153072SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256, + AlgorithmRSAPKCS1v154096SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256, + AlgorithmRSAPKCS1v154096SHA512: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512, + AlgorithmRSAPSS2048SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, + AlgorithmRSAPSS3072SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, + AlgorithmRSAPSS4096SHA256: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256, + AlgorithmRSAPSS4096SHA512: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512, +} + +var ( + errKMSReference = errors.New("kms specification should be in the format gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]") + + re = regexp.MustCompile(`^gcpkms://projects/([^/]+)/locations/([^/]+)/keyRings/([^/]+)/cryptoKeys/([^/]+)(?:/(?:cryptoKeyVersions|versions)/([^/]+))?$`) +) + +// ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets +const ReferenceScheme = "gcpkms://" + +// ValidReference returns a non-nil error if the reference string is invalid +func ValidReference(ref string) error { + if !re.MatchString(ref) { + return errKMSReference + } + return nil +} + +func parseReference(resourceID string) (projectID, locationID, keyRing, keyName, version string, err error) { + v := re.FindStringSubmatch(resourceID) + if len(v) != 6 { + err = fmt.Errorf("invalid gcpkms format %q", resourceID) + return + } + projectID, locationID, keyRing, keyName, version = v[1], v[2], v[3], v[4], v[5] + return +} + +type gcpClient struct { + keyID string + projectID string + locationID string + keyRing string + keyName string + version string + kvCache *ttlcache.Cache[string, cryptoKeyVersion] + client *gcpkms.KeyManagementClient +} + +func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, error) { + if err := ValidReference(ksp.Reference); err != nil { + return nil, err + } + + if ctx == nil { + ctx = context.Background() + } + + g := &gcpClient{ + kvCache: nil, + } + + var err error + g.projectID, g.locationID, g.keyRing, g.keyName, g.version, err = parseReference(ksp.Reference) + if err != nil { + return nil, err + } + + // NOTE: We need to think about how we want to handle passing in options here + g.client, err = gcpkms.NewKeyManagementClient(ctx) + if err != nil { + return nil, fmt.Errorf("new gcp kms client: %w", err) + } + + g.kvCache = ttlcache.New[string, cryptoKeyVersion]( + ttlcache.WithDisableTouchOnHit[string, cryptoKeyVersion](), + ) + + // prime the cache + g.kvCache.Get(cacheKey) + return g, nil +} + +type cryptoKeyVersion struct { + CryptoKeyVersion *kmspb.CryptoKeyVersion + Verifier cryptoutil.Verifier + PublicKey crypto.PublicKey + HashFunc crypto.Hash +} + +// use a consistent key for cache lookups +const cacheKey = "crypto_key_version" + +func (g *gcpClient) Verifier() (cryptoutil.Verifier, error) { + crv, err := g.getCKV() + if err != nil { + return nil, fmt.Errorf("transient error while getting KMS verifier: %w", err) + } + + return crv.Verifier, nil +} + +// keyVersionName returns the first key version found for a key in KMS +func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, error) { + parent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName) + + parentReq := &kmspb.GetCryptoKeyRequest{ + Name: parent, + } + key, err := g.client.GetCryptoKey(ctx, parentReq) + if err != nil { + return nil, err + } + if key.Purpose != kmspb.CryptoKey_ASYMMETRIC_SIGN { + return nil, errors.New("specified key cannot be used to sign") + } + + // if g.version was specified, use it explicitly + var kv *kmspb.CryptoKeyVersion + if g.version != "" { + req := &kmspb.GetCryptoKeyVersionRequest{ + Name: parent + fmt.Sprintf("/cryptoKeyVersions/%s", g.version), + } + kv, err = g.client.GetCryptoKeyVersion(ctx, req) + if err != nil { + return nil, err + } + } else { + req := &kmspb.ListCryptoKeyVersionsRequest{ + Parent: parent, + Filter: "state=ENABLED", + OrderBy: "name desc", + } + iterator := g.client.ListCryptoKeyVersions(ctx, req) + + // pick the key version that is enabled with the greatest version value + kv, err = iterator.Next() + if err != nil { + return nil, fmt.Errorf("unable to find an enabled key version in GCP KMS: %w", err) + } + } + + pubKey, err := g.fetchPublicKey(ctx, kv.Name) + if err != nil { + return nil, fmt.Errorf("unable to fetch public key while creating signer: %w", err) + } + + // kv is keyVersion to use + crv := cryptoKeyVersion{ + CryptoKeyVersion: kv, + PublicKey: pubKey, + } + + // crv.Verifier is set here to enable storing the public key & hash algorithm together, + // as well as using the in memory Verifier to perform the verify operations. + switch kv.Algorithm { + case kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256: + pub, ok := pubKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewECDSAVerifier(pub, crypto.SHA256) + crv.HashFunc = crypto.SHA256 + case kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384: + pub, ok := pubKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewECDSAVerifier(pub, crypto.SHA384) + crv.HashFunc = crypto.SHA384 + case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA256) + crv.HashFunc = crypto.SHA256 + case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA384) + crv.HashFunc = crypto.SHA384 + case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA256) + crv.HashFunc = crypto.SHA256 + case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA512) + crv.HashFunc = crypto.SHA512 + default: + return nil, errors.New("unknown algorithm specified by KMS") + } + if err != nil { + return nil, fmt.Errorf("initializing internal verifier: %w", err) + } + return &crv, nil +} + +func (g *gcpClient) fetchPublicKey(ctx context.Context, name string) (crypto.PublicKey, error) { + // Build the request. + pkreq := &kmspb.GetPublicKeyRequest{Name: name} + // Call the API. + pk, err := g.client.GetPublicKey(ctx, pkreq) + if err != nil { + return nil, fmt.Errorf("public key: %w", err) + } + return cryptoutils.UnmarshalPEMToPublicKey([]byte(pk.GetPem())) +} + +func (g *gcpClient) getHashFunc() (crypto.Hash, error) { + ckv, err := g.getCKV() + if err != nil { + return 0, err + } + return ckv.HashFunc, nil +} + +// getCKV gets the latest CryptoKeyVersion from the client's cache, which may trigger an actual +// call to GCP if the existing entry in the cache has expired. +func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) { + var lerr error + loader := ttlcache.LoaderFunc[string, cryptoKeyVersion]( + func(c *ttlcache.Cache[string, cryptoKeyVersion], key string) *ttlcache.Item[string, cryptoKeyVersion] { + var ttl time.Duration + var data *cryptoKeyVersion + + // if we're given an explicit version, cache this value forever + if g.version != "" { + ttl = time.Second * 0 + } else { + ttl = time.Second * 300 + } + data, lerr = g.keyVersionName(context.Background()) + if lerr == nil { + return c.Set(key, *data, ttl) + } + return nil + }, + ) + + // we get once and use consistently to ensure the cache value doesn't change underneath us + item := g.kvCache.Get(cacheKey, ttlcache.WithLoader[string, cryptoKeyVersion](loader)) + if item != nil { + v := item.Value() + return &v, nil + } + return nil, lerr +} + +func (g *gcpClient) sign(ctx context.Context, digest []byte, alg crypto.Hash, crc uint32) ([]byte, error) { + ckv, err := g.getCKV() + if err != nil { + return nil, err + } + + gcpSignReq := kmspb.AsymmetricSignRequest{ + Name: ckv.CryptoKeyVersion.Name, + Digest: &kmspb.Digest{}, + } + + if crc != 0 { + gcpSignReq.DigestCrc32C = wrapperspb.Int64(int64(crc)) + } + + switch alg { + case crypto.SHA256: + gcpSignReq.Digest.Digest = &kmspb.Digest_Sha256{ + Sha256: digest, + } + case crypto.SHA384: + gcpSignReq.Digest.Digest = &kmspb.Digest_Sha384{ + Sha384: digest, + } + case crypto.SHA512: + gcpSignReq.Digest.Digest = &kmspb.Digest_Sha512{ + Sha512: digest, + } + default: + return nil, errors.New("unsupported hash function") + } + + resp, err := g.client.AsymmetricSign(ctx, &gcpSignReq) + if err != nil { + return nil, fmt.Errorf("calling GCP AsymmetricSign: %w", err) + } + + // Optional, but recommended: perform integrity verification on result. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + if crc != 0 && !resp.VerifiedDigestCrc32C { + return nil, fmt.Errorf("AsymmetricSign: request corrupted in-transit") + } + if int64(crc32.Checksum(resp.Signature, crc32.MakeTable(crc32.Castagnoli))) != resp.SignatureCrc32C.Value { + return nil, fmt.Errorf("AsymmetricSign: response corrupted in-transit") + } + + return resp.Signature, nil +} + +func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { + crv, err := g.getCKV() + if err != nil { + return nil, fmt.Errorf("transient error getting info from KMS: %w", err) + } + return crv.PublicKey, nil +} + +// NOTE: Seems like GCP doesn't support any remote verification, so we'll just use the local verifier +func (g *gcpClient) verify(message []byte, sig []byte, opts ...signature.VerifyOption) error { + crv, err := g.getCKV() + if err != nil { + return fmt.Errorf("transient error getting info from KMS: %w", err) + } + + if err := crv.Verifier.Verify(bytes.NewBuffer(message), sig); err != nil { + // key could have been rotated, clear cache and try again if we're not pinned to a version + if g.version == "" { + g.kvCache.Delete(cacheKey) + crv, err = g.getCKV() + if err != nil { + return fmt.Errorf("transient error getting info from KMS: %w", err) + } + return crv.Verifier.Verify(bytes.NewBuffer(message), sig) + } + return fmt.Errorf("failed to verify for fixed version: %w", err) + } + return nil +} + +// NOTE: Not sure if we should be looking to keep this +func (g *gcpClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { + if err := g.createKeyRing(ctx); err != nil { + return nil, fmt.Errorf("creating key ring: %w", err) + } + + getKeyRequest := &kmspb.GetCryptoKeyRequest{ + Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName), + } + if _, err := g.client.GetCryptoKey(ctx, getKeyRequest); err == nil { + return g.public(ctx) + } + + if _, ok := algorithmMap[algorithm]; !ok { + return nil, errors.New("unknown algorithm requested") + } + + createKeyRequest := &kmspb.CreateCryptoKeyRequest{ + Parent: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", g.projectID, g.locationID, g.keyRing), + CryptoKeyId: g.keyName, + CryptoKey: &kmspb.CryptoKey{ + Purpose: kmspb.CryptoKey_ASYMMETRIC_SIGN, + VersionTemplate: &kmspb.CryptoKeyVersionTemplate{ + Algorithm: algorithmMap[algorithm], + }, + }, + } + if _, err := g.client.CreateCryptoKey(ctx, createKeyRequest); err != nil { + return nil, fmt.Errorf("creating crypto key: %w", err) + } + return g.public(ctx) +} + +func (g *gcpClient) createKeyRing(ctx context.Context) error { + getKeyRingRequest := &kmspb.GetKeyRingRequest{ + Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", g.projectID, g.locationID, g.keyRing), + } + if result, err := g.client.GetKeyRing(ctx, getKeyRingRequest); err == nil { + log.Printf("Key ring %s already exists in GCP KMS, moving on to creating key.\n", result.GetName()) + // key ring already exists, no need to create + return nil + } + // try to create key ring + createKeyRingRequest := &kmspb.CreateKeyRingRequest{ + Parent: fmt.Sprintf("projects/%s/locations/%s", g.projectID, g.locationID), + KeyRingId: g.keyRing, + } + result, err := g.client.CreateKeyRing(ctx, createKeyRingRequest) + log.Printf("Created key ring %s in GCP KMS.\n", result.GetName()) + return err +} diff --git a/signer/kms/gcp/go.mod b/signer/kms/gcp/go.mod new file mode 100644 index 00000000..98088b2b --- /dev/null +++ b/signer/kms/gcp/go.mod @@ -0,0 +1,54 @@ +module github.com/in-toto/go-witness/signer/kms/gcp + +replace github.com/in-toto/go-witness => ../../../ + +go 1.19 + +require ( + cloud.google.com/go/kms v1.15.5 + github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 + github.com/jellydator/ttlcache/v3 v3.1.1 + github.com/sigstore/sigstore v1.6.4 + google.golang.org/protobuf v1.32.0 +) + +require ( + 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.5 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-containerregistry v0.17.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/theupdateframework/go-tuf v0.5.2 // indirect + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.154.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect + google.golang.org/grpc v1.59.0 // indirect + gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/signer/kms/gcp/go.sum b/signer/kms/gcp/go.sum new file mode 100644 index 00000000..30d4ce25 --- /dev/null +++ b/signer/kms/gcp/go.sum @@ -0,0 +1,217 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +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/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.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= +cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/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/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk= +github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= +github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= +github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e h1:RLTpX495BXToqxpM90Ws4hXEo4Wfh81jr9DX1n/4WOo= +github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e/go.mod h1:EAuqr9VFWxBi9nD5jc/EA2MT1RFty9288TF6zdtYoCU= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/sigstore/sigstore v1.6.4 h1:jH4AzR7qlEH/EWzm+opSpxCfuUcjHL+LJPuQE7h40WE= +github.com/sigstore/sigstore v1.6.4/go.mod h1:pjR64lBxnjoSrAr+Ydye/FV73IfrgtoYlAI11a8xMfA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA= +github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.154.0 h1:X7QkVKZBskztmpPKWQXgjJRPA2dJYrL6r+sYPRLj050= +google.golang.org/api v0.154.0/go.mod h1:qhSMkM85hgqiokIYsrRyKxrjfBeIhgl4Z2JmeRkYylc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f h1:Vn+VyHU5guc9KjB5KrjI2q0wCOWEOIh0OEsleqakHJg= +google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY= +google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.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.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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/go-jose/go-jose.v2 v2.6.1 h1:qEzJlIDmG9q5VO0M/o8tGS65QMHMS1w01TQJB1VPJ4U= +gopkg.in/go-jose/go-jose.v2 v2.6.1/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/signer/kms/gcp/signer.go b/signer/kms/gcp/signer.go new file mode 100644 index 00000000..18189b3a --- /dev/null +++ b/signer/kms/gcp/signer.go @@ -0,0 +1,208 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gcp + +import ( + "context" + "crypto" + "fmt" + "hash/crc32" + "io" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/log" + kms "github.com/in-toto/go-witness/signer/kms" +) + +var gcpSupportedHashFuncs = []crypto.Hash{ + crypto.SHA256, + crypto.SHA512, + crypto.SHA384, +} + +// SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service +type SignerVerifier struct { + client *gcpClient + hashFunc crypto.Hash +} + +// LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. +func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*SignerVerifier, error) { + g := &SignerVerifier{} + + var err error + g.client, err = newGCPClient(ctx, ksp) + if err != nil { + return nil, err + } + + for _, hashFunc := range gcpSupportedHashFuncs { + if hashFunc == ksp.HashFunc { + g.hashFunc = ksp.HashFunc + } + } + + if g.hashFunc == 0 { + return nil, fmt.Errorf("unsupported hash function: %v", ksp.HashFunc) + } + + return g, nil +} + +// NOTE: This might be all wrong but setting it like so for now +// +// KeyID returns the key identifier for the key used by this signer. +func (g *SignerVerifier) KeyID() (string, error) { + return g.client.keyID, nil +} + +// Sign signs the provided message using GCP KMS. If the message is provided, +// this method will compute the digest according to the hash function specified +// when the Signer was created. +func (g *SignerVerifier) Sign(message io.Reader) ([]byte, error) { + var err error + ctx := context.Background() + var digest []byte + + var signerOpts crypto.SignerOpts + signerOpts, err = g.client.getHashFunc() + if err != nil { + return nil, fmt.Errorf("getting fetching default hash function: %w", err) + } + + hf := signerOpts.HashFunc() + + digest, _, err = cryptoutil.ComputeDigestForSigning(message, hf, gcpSupportedHashFuncs) + if err != nil { + return nil, err + } + + crc32cHasher := crc32.New(crc32.MakeTable(crc32.Castagnoli)) + _, err = crc32cHasher.Write(digest) + if err != nil { + return nil, err + } + + return g.client.sign(ctx, digest, hf, crc32cHasher.Sum32()) +} + +// Verifier returns a cryptoutil.Verifier that can be used to verify signatures created by this signer. +func (g *SignerVerifier) Verifier() (cryptoutil.Verifier, error) { + return g, nil +} + +// PublicKey returns the public key that can be used to verify signatures created by +// this signer. +func (g *SignerVerifier) PublicKey(ctx context.Context) (crypto.PublicKey, error) { + return g.client.public(ctx) +} + +// Bytes returns the bytes of the public key that can be used to verify signatures created by the signer. +func (g *SignerVerifier) Bytes() ([]byte, error) { + ckv, err := g.client.getCKV() + if err != nil { + return nil, fmt.Errorf("failed to get KMS key version: %w", err) + } + + return cryptoutil.PublicPemBytes(ckv.PublicKey) +} + +// VerifySignature verifies the signature for the given message, returning +// nil if the verification succeeded, and an error message otherwise. +func (g *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { + var digest []byte + + var signerOpts crypto.SignerOpts + signerOpts, err = g.client.getHashFunc() + if err != nil { + return fmt.Errorf("getting hash func: %w", err) + } + hf := signerOpts.HashFunc() + + digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, gcpSupportedHashFuncs) + if err != nil { + return err + } + + err = g.client.verify(digest, sig) + if err != nil { + log.Info(err.Error()) + } + + return err +} + +// NOTE:Wondering if this should exist, at least for now +// +// CreateKey attempts to create a new key in Vault with the specified algorithm. +func (a *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { + return a.client.createKey(ctx, algorithm) +} + +type cryptoSignerWrapper struct { + ctx context.Context + hashFunc crypto.Hash + sv *SignerVerifier + errFunc func(error) +} + +func (c *cryptoSignerWrapper) Public() crypto.PublicKey { + ctx := context.Background() + + pk, err := c.sv.PublicKey(ctx) + if err != nil && c.errFunc != nil { + c.errFunc(err) + } + return pk +} + +func (c *cryptoSignerWrapper) Sign(message io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { + if opts != nil { + c.hashFunc = opts.HashFunc() + } + + return c.sv.Sign(message) +} + +// CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object +// that allows the KMS to be used in APIs that only accept the standard golang objects +func (g *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { + defaultHf, err := g.client.getHashFunc() + if err != nil { + return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err) + } + + csw := &cryptoSignerWrapper{ + ctx: ctx, + sv: g, + hashFunc: defaultHf, + errFunc: errFunc, + } + + return csw, defaultHf, nil +} + +// SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service +func (*SignerVerifier) SupportedAlgorithms() (result []string) { + for k := range algorithmMap { + result = append(result, k) + } + return +} + +// DefaultAlgorithm returns the default algorithm for the GCP KMS service +func (g *SignerVerifier) DefaultAlgorithm() string { + return AlgorithmECDSAP256SHA256 +} From d7d9b7493be77c8f6d9f296623d687ca84a19b29 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 24 Jan 2024 17:54:01 +0000 Subject: [PATCH 07/27] adding tests and some other changes Signed-off-by: chaosinthecrd --- policy/policy.go | 23 ++- signer/kms/aws/client.go | 142 +++++-------- signer/kms/aws/fakeclient.go | 182 +++++++++++++++++ signer/kms/aws/go.mod | 4 + signer/kms/aws/go.sum | 1 + signer/kms/aws/signer.go | 66 +----- signer/kms/aws/signer_test.go | 369 ++++++++++++++++++++++++++++++++++ signer/kms/gcp/client.go | 64 +----- signer/kms/gcp/signer.go | 79 +------- verify.go | 3 + 10 files changed, 656 insertions(+), 277 deletions(-) create mode 100644 signer/kms/aws/fakeclient.go create mode 100644 signer/kms/aws/signer_test.go diff --git a/policy/policy.go b/policy/policy.go index 3eddcd94..f9a4b25e 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -18,11 +18,14 @@ import ( "bytes" "context" "crypto/x509" + "fmt" + "strings" "time" "github.com/in-toto/go-witness/attestation" "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/log" + "github.com/in-toto/go-witness/signer/kms" "github.com/in-toto/go-witness/source" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -54,10 +57,24 @@ type PublicKey struct { // PublicKeyVerifiers returns verifiers for each of the policy's embedded public keys grouped by the key's ID func (p Policy) PublicKeyVerifiers() (map[string]cryptoutil.Verifier, error) { verifiers := make(map[string]cryptoutil.Verifier) + var verifier cryptoutil.Verifier + var err error + for _, key := range p.PublicKeys { - verifier, err := cryptoutil.NewVerifierFromReader(bytes.NewReader(key.Key)) - if err != nil { - return nil, err + for _, prefix := range kms.SupportedProviders() { + if strings.HasPrefix(key.KeyID, prefix) { + verifier, err = kms.New(kms.WithRef(key.KeyID), kms.WithHash("SHA256")).Verifier(context.TODO()) + if err != nil { + return nil, fmt.Errorf("KMS Key ID recognized but not valid: %w", err) + } + } + } + + if verifier == nil { + verifier, err = cryptoutil.NewVerifierFromReader(bytes.NewReader(key.Key)) + if err != nil { + return nil, err + } } keyID, err := verifier.KeyID() diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index 7045fc08..5c5048d6 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -39,6 +39,17 @@ import ( ttlcache "github.com/jellydator/ttlcache/v3" ) +type client interface { + sign(ctx context.Context, digest []byte, _ crypto.Hash) ([]byte, error) + verifyRemotely(ctx context.Context, sig, digest []byte) error + verify(ctx context.Context, sig, message io.Reader) error + fetchCMK(ctx context.Context) (*cmk, error) + getHashFunc(ctx context.Context) (crypto.Hash, error) + setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) (err error) + fetchKeyMetadata(ctx context.Context) (*types.KeyMetadata, error) + fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) +} + func init() { kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { return LoadSignerVerifier(ctx, ksp) @@ -159,49 +170,6 @@ func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) return } -type cmk struct { - KeyMetadata *types.KeyMetadata - PublicKey crypto.PublicKey -} - -func (c *cmk) HashFunc() crypto.Hash { - switch c.KeyMetadata.SigningAlgorithms[0] { - case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecEcdsaSha256: - return crypto.SHA256 - case types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecEcdsaSha384: - return crypto.SHA384 - case types.SigningAlgorithmSpecRsassaPssSha512, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512, types.SigningAlgorithmSpecEcdsaSha512: - return crypto.SHA512 - default: - return 0 - } -} - -func (c *cmk) Verifier() (cryptoutil.Verifier, error) { - switch c.KeyMetadata.SigningAlgorithms[0] { - case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPssSha512: - pub, ok := c.PublicKey.(*rsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - return cryptoutil.NewRSAVerifier(pub, c.HashFunc()), nil - case types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512: - pub, ok := c.PublicKey.(*rsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - return cryptoutil.NewRSAVerifier(pub, c.HashFunc()), nil - case types.SigningAlgorithmSpecEcdsaSha256, types.SigningAlgorithmSpecEcdsaSha384, types.SigningAlgorithmSpecEcdsaSha512: - pub, ok := c.PublicKey.(*ecdsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not ecdsa") - } - return cryptoutil.NewECDSAVerifier(pub, c.HashFunc()), nil - default: - return nil, fmt.Errorf("signing algorithm unsupported") - } -} - func (a *awsClient) fetchCMK(ctx context.Context) (*cmk, error) { var err error cmk := &cmk{} @@ -245,51 +213,6 @@ func (a *awsClient) getCMK(ctx context.Context) (*cmk, error) { return nil, lerr } -func (a *awsClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { - if a.alias == "" { - return nil, errors.New("must use alias key format") - } - - // look for existing key first - cmk, err := a.getCMK(ctx) - if err == nil { - out := cmk.PublicKey - return out, nil - } - - // return error if not *kms.NotFoundException - var errNotFound *types.NotFoundException - if !errors.As(err, &errNotFound) { - return nil, fmt.Errorf("looking up key: %w", err) - } - - usage := types.KeyUsageTypeSignVerify - description := "Created by Witness" - key, err := a.client.CreateKey(ctx, &akms.CreateKeyInput{ - CustomerMasterKeySpec: types.CustomerMasterKeySpec(algorithm), - KeyUsage: usage, - Description: &description, - }) - if err != nil { - return nil, fmt.Errorf("creating key: %w", err) - } - - _, err = a.client.CreateAlias(ctx, &akms.CreateAliasInput{ - AliasName: &a.alias, - TargetKeyId: key.KeyMetadata.KeyId, - }) - if err != nil { - return nil, fmt.Errorf("creating alias %q: %w", a.alias, err) - } - - cmk, err = a.getCMK(ctx) - if err != nil { - return nil, fmt.Errorf("retrieving PublicKey from cache: %w", err) - } - - return cmk.PublicKey, err -} - // At the moment this function lies unused, but it is here for future if necessary func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { cmk, err := a.getCMK(ctx) @@ -374,3 +297,46 @@ func (a *awsClient) fetchKeyMetadata(ctx context.Context) (*types.KeyMetadata, e } return out.KeyMetadata, nil } + +type cmk struct { + KeyMetadata *types.KeyMetadata + PublicKey crypto.PublicKey +} + +func (c *cmk) HashFunc() crypto.Hash { + switch c.KeyMetadata.SigningAlgorithms[0] { + case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecEcdsaSha256: + return crypto.SHA256 + case types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecEcdsaSha384: + return crypto.SHA384 + case types.SigningAlgorithmSpecRsassaPssSha512, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512, types.SigningAlgorithmSpecEcdsaSha512: + return crypto.SHA512 + default: + return 0 + } +} + +func (c *cmk) Verifier() (cryptoutil.Verifier, error) { + switch c.KeyMetadata.SigningAlgorithms[0] { + case types.SigningAlgorithmSpecRsassaPssSha256, types.SigningAlgorithmSpecRsassaPssSha384, types.SigningAlgorithmSpecRsassaPssSha512: + pub, ok := c.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + return cryptoutil.NewRSAVerifier(pub, c.HashFunc()), nil + case types.SigningAlgorithmSpecRsassaPkcs1V15Sha256, types.SigningAlgorithmSpecRsassaPkcs1V15Sha384, types.SigningAlgorithmSpecRsassaPkcs1V15Sha512: + pub, ok := c.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + return cryptoutil.NewRSAVerifier(pub, c.HashFunc()), nil + case types.SigningAlgorithmSpecEcdsaSha256, types.SigningAlgorithmSpecEcdsaSha384, types.SigningAlgorithmSpecEcdsaSha512: + pub, ok := c.PublicKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not ecdsa") + } + return cryptoutil.NewECDSAVerifier(pub, c.HashFunc()), nil + default: + return nil, fmt.Errorf("signing algorithm unsupported") + } +} diff --git a/signer/kms/aws/fakeclient.go b/signer/kms/aws/fakeclient.go new file mode 100644 index 00000000..9cc73edc --- /dev/null +++ b/signer/kms/aws/fakeclient.go @@ -0,0 +1,182 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package aws implement the interface with amazon aws kms service +package aws + +import ( + "bytes" + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "time" + + akms "github.com/aws/aws-sdk-go-v2/service/kms" + "github.com/aws/aws-sdk-go-v2/service/kms/types" + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/signer/kms" + ttlcache "github.com/jellydator/ttlcache/v3" +) + +var ( + aid = "012345678901" + arn = "arn:aws:kms:us-west-2:012345678901:key/12345678-1234-1234-1234-123456789012" +) + +func createRsaKey() (*rsa.PrivateKey, *rsa.PublicKey, error) { + privKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, err + } + + return privKey, &privKey.PublicKey, nil +} + +func createTestKey() (cryptoutil.Signer, cryptoutil.Verifier, error) { + privKey, pubKey, err := createRsaKey() + if err != nil { + return nil, nil, err + } + + signer := cryptoutil.NewRSASigner(privKey, crypto.SHA256) + verifier := cryptoutil.NewRSAVerifier(pubKey, crypto.SHA256) + return signer, verifier, nil +} + +type fakeAWSClient struct { + client *akms.Client + endpoint string + keyID string + alias string + keyCache *ttlcache.Cache[string, cmk] + privateKey *rsa.PrivateKey + hash crypto.Hash +} + +func newFakeAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*fakeAWSClient, error) { + a, err := newAWSClient(ctx, ksp) + if err != nil { + return nil, err + } + + c := &fakeAWSClient{ + client: a.client, + endpoint: a.endpoint, + keyID: a.keyID, + alias: a.alias, + keyCache: a.keyCache, + hash: ksp.HashFunc, + } + + return c, nil +} + +func (a *fakeAWSClient) fetchCMK(ctx context.Context) (*cmk, error) { + var err error + cmk := &cmk{} + cmk.PublicKey, err = a.fetchPublicKey(ctx) + if err != nil { + return nil, err + } + cmk.KeyMetadata, err = a.fetchKeyMetadata(ctx) + if err != nil { + return nil, err + } + return cmk, nil +} + +func (a *fakeAWSClient) getHashFunc(ctx context.Context) (crypto.Hash, error) { + cmk, err := a.getCMK(ctx) + if err != nil { + return 0, err + } + return cmk.HashFunc(), nil +} + +func (a *fakeAWSClient) getCMK(ctx context.Context) (*cmk, error) { + var lerr error + loader := ttlcache.LoaderFunc[string, cmk]( + func(c *ttlcache.Cache[string, cmk], key string) *ttlcache.Item[string, cmk] { + var k *cmk + k, lerr = a.fetchCMK(ctx) + if lerr == nil { + return c.Set(cacheKey, *k, time.Second*300) + } + return nil + }, + ) + + item := a.keyCache.Get(cacheKey, ttlcache.WithLoader[string, cmk](loader)) + if lerr == nil { + cmk := item.Value() + return &cmk, nil + } + return nil, lerr +} + +// At the moment this function lies unused, but it is here for future if necessary + +func (a *fakeAWSClient) verifyRemotely(ctx context.Context, sig, digest []byte) error { + c, err := a.getCMK(ctx) + if err != nil { + return err + } + + v, err := cryptoutil.NewVerifier(c.PublicKey, cryptoutil.VerifyWithHash(a.hash)) + if err != nil { + return err + } + + return v.Verify(bytes.NewReader(digest), sig) +} + +func (a *fakeAWSClient) sign(ctx context.Context, digest []byte, _ crypto.Hash) ([]byte, error) { + _, err := a.getCMK(ctx) + if err != nil { + return nil, err + } + + signer, err := cryptoutil.NewSigner(a.privateKey, cryptoutil.SignWithHash(a.hash)) + if err != nil { + return nil, err + } + + s, err := signer.Sign(bytes.NewReader(digest)) + if err != nil { + return nil, err + } + + return s, nil +} + +func (a *fakeAWSClient) fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) { + k, p, err := createRsaKey() + if err != nil { + return nil, err + } + a.privateKey = k + + return p, nil +} + +func (a *fakeAWSClient) fetchKeyMetadata(ctx context.Context) (*types.KeyMetadata, error) { + km := &types.KeyMetadata{ + KeyId: &a.keyID, + AWSAccountId: &aid, + Arn: &arn, + } + + return km, nil +} diff --git a/signer/kms/aws/go.mod b/signer/kms/aws/go.mod index 6678a923..3ade0453 100644 --- a/signer/kms/aws/go.mod +++ b/signer/kms/aws/go.mod @@ -24,6 +24,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 // indirect github.com/aws/smithy-go v1.19.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect golang.org/x/sync v0.5.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/signer/kms/aws/go.sum b/signer/kms/aws/go.sum index 548d2378..21ad0ede 100644 --- a/signer/kms/aws/go.sum +++ b/signer/kms/aws/go.sum @@ -40,5 +40,6 @@ go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 015e5e39..3724fbf4 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -22,7 +22,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/in-toto/go-witness/cryptoutil" - "github.com/in-toto/go-witness/log" kms "github.com/in-toto/go-witness/signer/kms" ) @@ -43,13 +42,16 @@ var awsSupportedHashFuncs = []crypto.Hash{ // SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service type SignerVerifier struct { - client *awsClient - hashFunc crypto.Hash + reference string + client client + hashFunc crypto.Hash } // LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*SignerVerifier, error) { - a := &SignerVerifier{} + a := &SignerVerifier{ + reference: ksp.Reference, + } var err error a.client, err = newAWSClient(ctx, ksp) @@ -74,7 +76,7 @@ func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*Signe // // KeyID returns the key identifier for the key used by this signer. func (a *SignerVerifier) KeyID() (string, error) { - return a.client.keyID, nil + return a.reference, nil } // Sign signs the provided message using AWS KMS. If the message is provided, @@ -130,6 +132,7 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { } hf := signerOpts.HashFunc() + // if we verify remotely, we need to compute the digest first digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, awsSupportedHashFuncs) if err != nil { return err @@ -137,63 +140,12 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { err = a.client.verifyRemotely(ctx, sig, digest) if err != nil { - log.Info(err.Error()) + return err } return err } -// NOTE:Wondering if this should exist, at least for now -// -// CreateKey attempts to create a new key in Vault with the specified algorithm. -func (a *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { - return a.client.createKey(ctx, algorithm) -} - -type cryptoSignerWrapper struct { - ctx context.Context - hashFunc crypto.Hash - sv *SignerVerifier - errFunc func(error) -} - -func (c *cryptoSignerWrapper) Public() crypto.PublicKey { - ctx := context.Background() - - cmk, err := c.sv.client.getCMK(ctx) - if err != nil { - return nil - } - - return cmk.PublicKey -} - -func (c *cryptoSignerWrapper) Sign(message io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { - if opts != nil { - c.hashFunc = opts.HashFunc() - } - - return c.sv.Sign(message) -} - -// CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object -// that allows the KMS to be used in APIs that only accept the standard golang objects -func (a *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { - defaultHf, err := a.client.getHashFunc(ctx) - if err != nil { - return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err) - } - - csw := &cryptoSignerWrapper{ - ctx: ctx, - sv: a, - hashFunc: defaultHf, - errFunc: errFunc, - } - - return csw, defaultHf, nil -} - // SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service func (*SignerVerifier) SupportedAlgorithms() []string { s := make([]string, len(awsSupportedAlgorithms)) diff --git a/signer/kms/aws/signer_test.go b/signer/kms/aws/signer_test.go new file mode 100644 index 00000000..e410993e --- /dev/null +++ b/signer/kms/aws/signer_test.go @@ -0,0 +1,369 @@ +package aws + +import ( + "bytes" + "context" + "crypto" + "fmt" + "testing" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/signer/kms" + "github.com/stretchr/testify/assert" +) + +func TestParseReference(t *testing.T) { + tests := []struct { + in string + wantEndpoint string + wantKeyID string + wantAlias string + wantErr bool + }{ + { + in: "awskms:///1234abcd-12ab-34cd-56ef-1234567890ab", + wantEndpoint: "", + wantKeyID: "1234abcd-12ab-34cd-56ef-1234567890ab", + wantAlias: "", + wantErr: false, + }, + { + // multi-region key + in: "awskms:///mrk-1234abcd12ab34cd56ef1234567890ab", + wantEndpoint: "", + wantKeyID: "mrk-1234abcd12ab34cd56ef1234567890ab", + wantAlias: "", + wantErr: false, + }, + { + in: "awskms:///1234ABCD-12AB-34CD-56EF-1234567890AB", + wantEndpoint: "", + wantKeyID: "1234ABCD-12AB-34CD-56EF-1234567890AB", + wantAlias: "", + wantErr: false, + }, + { + in: "awskms://localhost:4566/1234abcd-12ab-34cd-56ef-1234567890ab", + wantEndpoint: "localhost:4566", + wantKeyID: "1234abcd-12ab-34cd-56ef-1234567890ab", + wantAlias: "", + wantErr: false, + }, + { + in: "awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + wantEndpoint: "", + wantKeyID: "arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + wantAlias: "", + wantErr: false, + }, + { + in: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + wantEndpoint: "localhost:4566", + wantKeyID: "arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + wantAlias: "", + wantErr: false, + }, + { + in: "awskms:///alias/ExampleAlias", + wantEndpoint: "", + wantKeyID: "alias/ExampleAlias", + wantAlias: "alias/ExampleAlias", + wantErr: false, + }, + { + in: "awskms://localhost:4566/alias/ExampleAlias", + wantEndpoint: "localhost:4566", + wantKeyID: "alias/ExampleAlias", + wantAlias: "alias/ExampleAlias", + wantErr: false, + }, + { + in: "awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", + wantEndpoint: "", + wantKeyID: "arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", + wantAlias: "alias/ExampleAlias", + wantErr: false, + }, + { + in: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:alias/ExampleAlias", + wantEndpoint: "", + wantKeyID: "arn:aws-us-gov:kms:us-gov-west-1:111122223333:alias/ExampleAlias", + wantAlias: "alias/ExampleAlias", + wantErr: false, + }, + { + in: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + wantEndpoint: "", + wantKeyID: "arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + wantAlias: "", + wantErr: false, + }, + { + in: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", + wantEndpoint: "localhost:4566", + wantKeyID: "arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", + wantAlias: "alias/ExampleAlias", + wantErr: false, + }, + { + // missing alias/ prefix + in: "awskms:///missingalias", + wantEndpoint: "", + wantKeyID: "", + wantAlias: "", + wantErr: true, + }, + { + // invalid UUID + in: "awskms:///1234abcd-12ab-YYYY-56ef-1234567890ab", + wantEndpoint: "", + wantKeyID: "", + wantAlias: "", + wantErr: true, + }, + { + // Currently, references without endpoints must use 3 + // slashes. It would be nice to support this format, + // but that would be harder to parse. + in: "awskms://1234abcd-12ab-34cd-56ef-1234567890ab", + wantEndpoint: "", + wantKeyID: "", + wantAlias: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.in, func(t *testing.T) { + gotEndpoint, gotKeyID, gotAlias, err := ParseReference(tt.in) + if (err != nil) != tt.wantErr { + t.Errorf("ParseReference() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotEndpoint != tt.wantEndpoint { + t.Errorf("ParseReference() gotEndpoint = %v, want %v", gotEndpoint, tt.wantEndpoint) + } + if gotKeyID != tt.wantKeyID { + t.Errorf("ParseReference() gotKeyID = %v, want %v", gotKeyID, tt.wantKeyID) + } + if gotAlias != tt.wantAlias { + t.Errorf("ParseReference() gotAlias = %v, want %v", gotAlias, tt.wantAlias) + } + }) + } +} + +func TestSign(t *testing.T) { + tests := []struct { + name string + ref string + hash crypto.Hash + message string + wantErr bool + expectedErr error + }{ + { + name: "successful sign", + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + hash: crypto.SHA256, + message: "foo", + wantErr: false, + }, + { + name: "SHA-512", + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + hash: crypto.SHA512, + message: "foo", + wantErr: false, + }, + { + name: "bad ref", + ref: "blablabla", + hash: crypto.SHA256, + message: "foo", + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + { + name: "unsupported hash algorithm", + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + hash: crypto.RIPEMD160, + message: "foo", + wantErr: true, + expectedErr: fmt.Errorf(`unsupported hash algorithm: "RIPEMD-160" not in [SHA-256 SHA-384 SHA-512]`), + }, + { + name: "gcp ref", + ref: "gcpkms://projects/testproject-23231/locations/europe-west2/keyRings/test/cryptoKeys/test", + hash: crypto.SHA256, + message: "foobarbaz", + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + } + + for _, tt := range tests { + fmt.Println("sign test: ", tt.name) + ctx := context.TODO() + dig, _, err := cryptoutil.ComputeDigestForSigning(bytes.NewReader([]byte(tt.message)), tt.hash, awsSupportedHashFuncs) + if tt.wantErr && err != nil { + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + ksp := kms.New(kms.WithRef(tt.ref), kms.WithHash(tt.hash.String())) + c, err := newFakeAWSClient(context.TODO(), ksp) + if tt.wantErr && err != nil { + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + s, err := c.sign(ctx, dig, tt.hash) + if tt.wantErr && err != nil { + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + if s == nil { + t.Fatal("signature is nil") + } + + if tt.wantErr { + t.Fatalf("expected test %s to fail", tt.name) + } + + } +} + +func TestVerify(t *testing.T) { + tests := []struct { + name string + ref string + hash crypto.Hash + mess []string + wantErr bool + expectedErr error + }{ + { + name: "successful sign", + hash: crypto.SHA256, + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + mess: []string{"foo", "bar", "baz"}, + wantErr: false, + }, + { + name: "SHA-512", + hash: crypto.SHA512, + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + mess: []string{"foo", "bar", "baz"}, + wantErr: false, + }, + { + name: "bad ref", + hash: crypto.SHA256, + ref: "blablabla", + mess: []string{"foo", "bar", "baz"}, + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + { + name: "unsupported hash algorithm", + hash: crypto.RIPEMD160, + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + mess: []string{"foo", "bar", "baz"}, + wantErr: true, + expectedErr: fmt.Errorf(`unsupported hash algorithm: "RIPEMD-160" not in [SHA-256 SHA-384 SHA-512]`), + }, + { + name: "gcp ref", + hash: crypto.SHA256, + ref: "gcpkms://projects/testproject-23231/locations/europe-west2/keyRings/test/cryptoKeys/test", + mess: []string{"foo", "bar", "baz"}, + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + } + + for _, tt := range tests { + errFound := false + fmt.Println("verify test: ", tt.name) + ctx := context.TODO() + ksp := kms.New(kms.WithRef(tt.ref), kms.WithHash(tt.hash.String())) + c, err := newFakeAWSClient(context.TODO(), ksp) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + for _, mess := range tt.mess { + bs, bv, err := createTestKey() + if err != nil { + t.Fatal(err) + } + + sdig, _, err := cryptoutil.ComputeDigestForSigning(bytes.NewReader([]byte(mess)), tt.hash, awsSupportedHashFuncs) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + sig, err := c.sign(ctx, []byte(sdig), crypto.SHA256) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + bsig, err := bs.Sign(bytes.NewReader([]byte(sdig))) + if err != nil { + t.Fatal(err) + } + + vdig, _, err := cryptoutil.ComputeDigestForVerifying(bytes.NewReader([]byte(mess)), tt.hash, awsSupportedHashFuncs) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + err = c.verifyRemotely(ctx, sig, vdig) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + err = c.verifyRemotely(ctx, bsig, vdig) + if err == nil { + t.Fatal("expected verification to fail") + } + + err = bv.Verify(bytes.NewReader([]byte(vdig)), sig) + if err == nil { + t.Fatal("expected verification to fail") + } + + } + + if tt.wantErr && !errFound { + t.Fatalf("expected test %s to fail with error %s", tt.name, tt.expectedErr.Error()) + } + } +} diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index 30f936f7..b8314d8e 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -17,7 +17,6 @@ package gcp import ( - "bytes" "context" "crypto" "crypto/ecdsa" @@ -25,7 +24,7 @@ import ( "errors" "fmt" "hash/crc32" - "log" + "io" "regexp" "time" @@ -101,7 +100,6 @@ func parseReference(resourceID string) (projectID, locationID, keyRing, keyName, } type gcpClient struct { - keyID string projectID string locationID string keyRing string @@ -382,14 +380,14 @@ func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { return crv.PublicKey, nil } -// NOTE: Seems like GCP doesn't support any remote verification, so we'll just use the local verifier -func (g *gcpClient) verify(message []byte, sig []byte, opts ...signature.VerifyOption) error { +// Seems like GCP doesn't support any remote verification, so we'll just use the local verifier +func (g *gcpClient) verify(message io.Reader, sig []byte, opts ...signature.VerifyOption) error { crv, err := g.getCKV() if err != nil { return fmt.Errorf("transient error getting info from KMS: %w", err) } - if err := crv.Verifier.Verify(bytes.NewBuffer(message), sig); err != nil { + if err := crv.Verifier.Verify(message, sig); err != nil { // key could have been rotated, clear cache and try again if we're not pinned to a version if g.version == "" { g.kvCache.Delete(cacheKey) @@ -397,61 +395,9 @@ func (g *gcpClient) verify(message []byte, sig []byte, opts ...signature.VerifyO if err != nil { return fmt.Errorf("transient error getting info from KMS: %w", err) } - return crv.Verifier.Verify(bytes.NewBuffer(message), sig) + return crv.Verifier.Verify(message, sig) } return fmt.Errorf("failed to verify for fixed version: %w", err) } return nil } - -// NOTE: Not sure if we should be looking to keep this -func (g *gcpClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { - if err := g.createKeyRing(ctx); err != nil { - return nil, fmt.Errorf("creating key ring: %w", err) - } - - getKeyRequest := &kmspb.GetCryptoKeyRequest{ - Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName), - } - if _, err := g.client.GetCryptoKey(ctx, getKeyRequest); err == nil { - return g.public(ctx) - } - - if _, ok := algorithmMap[algorithm]; !ok { - return nil, errors.New("unknown algorithm requested") - } - - createKeyRequest := &kmspb.CreateCryptoKeyRequest{ - Parent: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", g.projectID, g.locationID, g.keyRing), - CryptoKeyId: g.keyName, - CryptoKey: &kmspb.CryptoKey{ - Purpose: kmspb.CryptoKey_ASYMMETRIC_SIGN, - VersionTemplate: &kmspb.CryptoKeyVersionTemplate{ - Algorithm: algorithmMap[algorithm], - }, - }, - } - if _, err := g.client.CreateCryptoKey(ctx, createKeyRequest); err != nil { - return nil, fmt.Errorf("creating crypto key: %w", err) - } - return g.public(ctx) -} - -func (g *gcpClient) createKeyRing(ctx context.Context) error { - getKeyRingRequest := &kmspb.GetKeyRingRequest{ - Name: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", g.projectID, g.locationID, g.keyRing), - } - if result, err := g.client.GetKeyRing(ctx, getKeyRingRequest); err == nil { - log.Printf("Key ring %s already exists in GCP KMS, moving on to creating key.\n", result.GetName()) - // key ring already exists, no need to create - return nil - } - // try to create key ring - createKeyRingRequest := &kmspb.CreateKeyRingRequest{ - Parent: fmt.Sprintf("projects/%s/locations/%s", g.projectID, g.locationID), - KeyRingId: g.keyRing, - } - result, err := g.client.CreateKeyRing(ctx, createKeyRingRequest) - log.Printf("Created key ring %s in GCP KMS.\n", result.GetName()) - return err -} diff --git a/signer/kms/gcp/signer.go b/signer/kms/gcp/signer.go index 18189b3a..a4dd23e8 100644 --- a/signer/kms/gcp/signer.go +++ b/signer/kms/gcp/signer.go @@ -34,13 +34,16 @@ var gcpSupportedHashFuncs = []crypto.Hash{ // SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service type SignerVerifier struct { - client *gcpClient - hashFunc crypto.Hash + reference string + client *gcpClient + hashFunc crypto.Hash } // LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*SignerVerifier, error) { - g := &SignerVerifier{} + g := &SignerVerifier{ + reference: ksp.Reference, + } var err error g.client, err = newGCPClient(ctx, ksp) @@ -65,7 +68,7 @@ func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*Signe // // KeyID returns the key identifier for the key used by this signer. func (g *SignerVerifier) KeyID() (string, error) { - return g.client.keyID, nil + return g.reference, nil } // Sign signs the provided message using GCP KMS. If the message is provided, @@ -79,7 +82,7 @@ func (g *SignerVerifier) Sign(message io.Reader) ([]byte, error) { var signerOpts crypto.SignerOpts signerOpts, err = g.client.getHashFunc() if err != nil { - return nil, fmt.Errorf("getting fetching default hash function: %w", err) + return nil, fmt.Errorf("failed to get default hash function: %w", err) } hf := signerOpts.HashFunc() @@ -122,21 +125,7 @@ func (g *SignerVerifier) Bytes() ([]byte, error) { // VerifySignature verifies the signature for the given message, returning // nil if the verification succeeded, and an error message otherwise. func (g *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { - var digest []byte - - var signerOpts crypto.SignerOpts - signerOpts, err = g.client.getHashFunc() - if err != nil { - return fmt.Errorf("getting hash func: %w", err) - } - hf := signerOpts.HashFunc() - - digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, gcpSupportedHashFuncs) - if err != nil { - return err - } - - err = g.client.verify(digest, sig) + err = g.client.verify(message, sig) if err != nil { log.Info(err.Error()) } @@ -144,56 +133,6 @@ func (g *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { return err } -// NOTE:Wondering if this should exist, at least for now -// -// CreateKey attempts to create a new key in Vault with the specified algorithm. -func (a *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) { - return a.client.createKey(ctx, algorithm) -} - -type cryptoSignerWrapper struct { - ctx context.Context - hashFunc crypto.Hash - sv *SignerVerifier - errFunc func(error) -} - -func (c *cryptoSignerWrapper) Public() crypto.PublicKey { - ctx := context.Background() - - pk, err := c.sv.PublicKey(ctx) - if err != nil && c.errFunc != nil { - c.errFunc(err) - } - return pk -} - -func (c *cryptoSignerWrapper) Sign(message io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { - if opts != nil { - c.hashFunc = opts.HashFunc() - } - - return c.sv.Sign(message) -} - -// CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object -// that allows the KMS to be used in APIs that only accept the standard golang objects -func (g *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) { - defaultHf, err := g.client.getHashFunc() - if err != nil { - return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err) - } - - csw := &cryptoSignerWrapper{ - ctx: ctx, - sv: g, - hashFunc: defaultHf, - errFunc: errFunc, - } - - return csw, defaultHf, nil -} - // SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service func (*SignerVerifier) SupportedAlgorithms() (result []string) { for k := range algorithmMap { diff --git a/verify.go b/verify.go index abc0d344..18285009 100644 --- a/verify.go +++ b/verify.go @@ -23,6 +23,7 @@ import ( "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/dsse" + "github.com/in-toto/go-witness/log" "github.com/in-toto/go-witness/policy" "github.com/in-toto/go-witness/source" "github.com/in-toto/go-witness/timestamp" @@ -80,6 +81,8 @@ func Verify(ctx context.Context, policyEnvelope dsse.Envelope, policyVerifiers [ return nil, fmt.Errorf("could not verify policy: %w", err) } + log.Info("policy signature verified") + pol := policy.Policy{} if err := json.Unmarshal(vo.policyEnvelope.Payload, &pol); err != nil { return nil, fmt.Errorf("failed to unmarshal policy from envelope: %w", err) From 6c1d8cfe8edf1f6ca91d3dc0221c9c6244787e16 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 24 Jan 2024 17:58:42 +0000 Subject: [PATCH 08/27] fixing license headers Signed-off-by: chaosinthecrd --- signer/kms/aws/client.go | 1 - signer/kms/aws/fakeclient.go | 1 - signer/kms/aws/signer_test.go | 14 ++++++++++++++ signer/kms/gcp/client.go | 4 +--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index 5c5048d6..ffe307f4 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package aws implement the interface with amazon aws kms service package aws import ( diff --git a/signer/kms/aws/fakeclient.go b/signer/kms/aws/fakeclient.go index 9cc73edc..00d99837 100644 --- a/signer/kms/aws/fakeclient.go +++ b/signer/kms/aws/fakeclient.go @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package aws implement the interface with amazon aws kms service package aws import ( diff --git a/signer/kms/aws/signer_test.go b/signer/kms/aws/signer_test.go index e410993e..dd8f4180 100644 --- a/signer/kms/aws/signer_test.go +++ b/signer/kms/aws/signer_test.go @@ -1,3 +1,17 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package aws import ( diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index b8314d8e..d9c0b75b 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -1,11 +1,10 @@ -// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package gcp implement the interface with google cloud kms service package gcp import ( From da26fe4d2da6307291eb5e1c24aef14518609634 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 24 Jan 2024 17:59:12 +0000 Subject: [PATCH 09/27] fixing header Signed-off-by: chaosinthecrd --- signer/kms/gcp/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index d9c0b75b..9bf92ceb 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -1,4 +1,4 @@ -// Copyright 2021 The Sigstore Authors. +// Copyright 2023 The Witness Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 599b2cb2a12e6b0ee68e7ba1dfed223b3daed418 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Wed, 24 Jan 2024 18:40:33 +0000 Subject: [PATCH 10/27] small refactor Signed-off-by: chaosinthecrd --- cryptoutil/util.go | 44 +++++------------------------------ signer/kms/aws/signer.go | 4 ++-- signer/kms/aws/signer_test.go | 23 ++++++------------ signer/kms/gcp/signer.go | 2 +- 4 files changed, 16 insertions(+), 57 deletions(-) diff --git a/cryptoutil/util.go b/cryptoutil/util.go index 3685689e..5d139e6a 100644 --- a/cryptoutil/util.go +++ b/cryptoutil/util.go @@ -149,48 +149,16 @@ func TryParseCertificate(data []byte) (*x509.Certificate, error) { return cert, nil } -// ComputeDigestForSigning calculates the digest value for the specified message using a hash function selected by the following process: -// -// - if a digest value is already specified in a SignOption and the length of the digest matches that of the selected hash function, the -// digest value will be returned without any further computation -// - if a hash function is given using WithCryptoSignerOpts(opts) as a SignOption, it will be used (if it is in the supported list) -// - otherwise defaultHashFunc will be used (if it is in the supported list) -func ComputeDigestForSigning(rawMessage io.Reader, defaultHashFunc crypto.Hash, supportedHashFuncs []crypto.Hash) (digest []byte, hashedWith crypto.Hash, err error) { - var cryptoSignerOpts crypto.SignerOpts = defaultHashFunc - hashedWith = cryptoSignerOpts.HashFunc() +// ComputeDigest calculates the digest value for the specified message using the supplied hash function +func ComputeDigest(rawMessage io.Reader, hashFunc crypto.Hash, supportedHashFuncs []crypto.Hash) ([]byte, crypto.Hash, error) { + var cryptoSignerOpts crypto.SignerOpts = hashFunc + hashedWith := cryptoSignerOpts.HashFunc() if !isSupportedAlg(hashedWith, supportedHashFuncs) { return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) } - if len(digest) > 0 { - if hashedWith != crypto.Hash(0) && len(digest) != hashedWith.Size() { - err = errors.New("unexpected length of digest for hash function specified") - } - return - } - digest, err = hashMessage(rawMessage, hashedWith) - return -} -// ComputeDigestForVerifying calculates the digest value for the specified message using a hash function selected by the following process: -// -// - if a digest value is already specified in a SignOption and the length of the digest matches that of the selected hash function, the -// digest value will be returned without any further computation -// - if a hash function is given using WithCryptoSignerOpts(opts) as a SignOption, it will be used (if it is in the supported list) -// - otherwise defaultHashFunc will be used (if it is in the supported list) -func ComputeDigestForVerifying(rawMessage io.Reader, defaultHashFunc crypto.Hash, supportedHashFuncs []crypto.Hash) (digest []byte, hashedWith crypto.Hash, err error) { - var cryptoSignerOpts crypto.SignerOpts = defaultHashFunc - hashedWith = cryptoSignerOpts.HashFunc() - if !isSupportedAlg(hashedWith, supportedHashFuncs) { - return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) - } - if len(digest) > 0 { - if hashedWith != crypto.Hash(0) && len(digest) != hashedWith.Size() { - err = errors.New("unexpected length of digest for hash function specified") - } - return - } - digest, err = hashMessage(rawMessage, hashedWith) - return + digest, err := hashMessage(rawMessage, hashedWith) + return digest, hashedWith, err } func isSupportedAlg(alg crypto.Hash, supportedAlgs []crypto.Hash) bool { diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 3724fbf4..1f60018c 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -95,7 +95,7 @@ func (a *SignerVerifier) Sign(message io.Reader) ([]byte, error) { hf := signerOpts.HashFunc() - digest, _, err = cryptoutil.ComputeDigestForSigning(message, hf, awsSupportedHashFuncs) + digest, _, err = cryptoutil.ComputeDigest(message, hf, awsSupportedHashFuncs) if err != nil { return nil, err } @@ -133,7 +133,7 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { hf := signerOpts.HashFunc() // if we verify remotely, we need to compute the digest first - digest, _, err = cryptoutil.ComputeDigestForVerifying(message, hf, awsSupportedHashFuncs) + digest, _, err = cryptoutil.ComputeDigest(message, hf, awsSupportedHashFuncs) if err != nil { return err } diff --git a/signer/kms/aws/signer_test.go b/signer/kms/aws/signer_test.go index dd8f4180..9a848935 100644 --- a/signer/kms/aws/signer_test.go +++ b/signer/kms/aws/signer_test.go @@ -218,7 +218,7 @@ func TestSign(t *testing.T) { for _, tt := range tests { fmt.Println("sign test: ", tt.name) ctx := context.TODO() - dig, _, err := cryptoutil.ComputeDigestForSigning(bytes.NewReader([]byte(tt.message)), tt.hash, awsSupportedHashFuncs) + dig, _, err := cryptoutil.ComputeDigest(bytes.NewReader([]byte(tt.message)), tt.hash, awsSupportedHashFuncs) if tt.wantErr && err != nil { assert.ErrorAs(t, err, &tt.expectedErr) continue @@ -323,7 +323,7 @@ func TestVerify(t *testing.T) { t.Fatal(err) } - sdig, _, err := cryptoutil.ComputeDigestForSigning(bytes.NewReader([]byte(mess)), tt.hash, awsSupportedHashFuncs) + dig, _, err := cryptoutil.ComputeDigest(bytes.NewReader([]byte(mess)), tt.hash, awsSupportedHashFuncs) if tt.wantErr && err != nil { errFound = true assert.ErrorAs(t, err, &tt.expectedErr) @@ -332,7 +332,7 @@ func TestVerify(t *testing.T) { t.Fatal(err) } - sig, err := c.sign(ctx, []byte(sdig), crypto.SHA256) + sig, err := c.sign(ctx, []byte(dig), crypto.SHA256) if tt.wantErr && err != nil { errFound = true assert.ErrorAs(t, err, &tt.expectedErr) @@ -341,12 +341,12 @@ func TestVerify(t *testing.T) { t.Fatal(err) } - bsig, err := bs.Sign(bytes.NewReader([]byte(sdig))) + bsig, err := bs.Sign(bytes.NewReader([]byte(dig))) if err != nil { t.Fatal(err) } - vdig, _, err := cryptoutil.ComputeDigestForVerifying(bytes.NewReader([]byte(mess)), tt.hash, awsSupportedHashFuncs) + err = c.verifyRemotely(ctx, sig, dig) if tt.wantErr && err != nil { errFound = true assert.ErrorAs(t, err, &tt.expectedErr) @@ -355,21 +355,12 @@ func TestVerify(t *testing.T) { t.Fatal(err) } - err = c.verifyRemotely(ctx, sig, vdig) - if tt.wantErr && err != nil { - errFound = true - assert.ErrorAs(t, err, &tt.expectedErr) - continue - } else if err != nil { - t.Fatal(err) - } - - err = c.verifyRemotely(ctx, bsig, vdig) + err = c.verifyRemotely(ctx, bsig, dig) if err == nil { t.Fatal("expected verification to fail") } - err = bv.Verify(bytes.NewReader([]byte(vdig)), sig) + err = bv.Verify(bytes.NewReader([]byte(dig)), sig) if err == nil { t.Fatal("expected verification to fail") } diff --git a/signer/kms/gcp/signer.go b/signer/kms/gcp/signer.go index a4dd23e8..75d37429 100644 --- a/signer/kms/gcp/signer.go +++ b/signer/kms/gcp/signer.go @@ -87,7 +87,7 @@ func (g *SignerVerifier) Sign(message io.Reader) ([]byte, error) { hf := signerOpts.HashFunc() - digest, _, err = cryptoutil.ComputeDigestForSigning(message, hf, gcpSupportedHashFuncs) + digest, _, err = cryptoutil.ComputeDigest(message, hf, gcpSupportedHashFuncs) if err != nil { return nil, err } From 0ccdf110bc47b55ad6c974249a095cd81f66143c Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Fri, 26 Jan 2024 18:25:01 +0000 Subject: [PATCH 11/27] adding hashicorp vault kms signer Signed-off-by: chaosinthecrd --- signer/kms/hashivault/client.go | 344 +++++++++++++++++++++++++++++++ signer/kms/hashivault/go.mod | 46 +++++ signer/kms/hashivault/go.sum | 127 ++++++++++++ signer/kms/hashivault/rpcauth.go | 75 +++++++ signer/kms/hashivault/signer.go | 162 +++++++++++++++ signer/kms/signerprovider.go | 45 +++- 6 files changed, 794 insertions(+), 5 deletions(-) create mode 100644 signer/kms/hashivault/client.go create mode 100644 signer/kms/hashivault/go.mod create mode 100644 signer/kms/hashivault/go.sum create mode 100644 signer/kms/hashivault/rpcauth.go create mode 100644 signer/kms/hashivault/signer.go diff --git a/signer/kms/hashivault/client.go b/signer/kms/hashivault/client.go new file mode 100644 index 00000000..198bde61 --- /dev/null +++ b/signer/kms/hashivault/client.go @@ -0,0 +1,344 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package hashivault implement the interface with hashivault kms service +package hashivault + +import ( + "context" + "crypto" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + "regexp" + "strconv" + "time" + + vault "github.com/hashicorp/vault/api" + "github.com/in-toto/go-witness/cryptoutil" + kms "github.com/in-toto/go-witness/signer/kms" + "github.com/jellydator/ttlcache/v3" + "github.com/sigstore/sigstore/pkg/cryptoutils" +) + +func init() { + kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { + return LoadSignerVerifier(ctx, ksp) + }) +} + +type vaultClient struct { + client *vault.Client + keyPath string + transitSecretEnginePath string + keyCache *ttlcache.Cache[string, crypto.PublicKey] + keyVersion uint64 +} + +var ( + errReference = errors.New("kms specification should be in the format hashivault://") + referenceRegex = regexp.MustCompile(`^hashivault://(?P\w(([\w-.]+)?\w)?)$`) + prefixRegex = regexp.MustCompile("^vault:v[0-9]+:") +) + +const ( + vaultV1DataPrefix = "vault:v1:" + + // use a consistent key for cache lookups + cacheKey = "signer" + + // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets + ReferenceScheme = "hashivault://" +) + +// ValidReference returns a non-nil error if the reference string is invalid +func ValidReference(ref string) error { + if !referenceRegex.MatchString(ref) { + return errReference + } + return nil +} + +func parseReference(resourceID string) (keyPath string, err error) { + i := referenceRegex.SubexpIndex("path") + v := referenceRegex.FindStringSubmatch(resourceID) + if len(v) < i+1 { + err = fmt.Errorf("invalid vault format %q: %w", resourceID, err) + return + } + keyPath = v[i] + return +} + +func newVaultClient(ctx context.Context, ksp *kms.KMSSignerProvider, opts *RPCAuth) (*vaultClient, error) { + if err := ValidReference(ksp.Reference); err != nil { + return nil, err + } + + keyPath, err := parseReference(ksp.Reference) + if err != nil { + return nil, err + } + + client, err := vault.NewClient(&vault.Config{ + Address: opts.Address, + }) + if err != nil { + return nil, fmt.Errorf("new vault client: %w", err) + } + + client.SetToken(opts.Token) + + var keyVersionUint uint64 + if ksp.KeyVersion != "" { + keyVersionUint, err = strconv.ParseUint(ksp.KeyVersion, 10, 64) + if err != nil { + return nil, fmt.Errorf("parsing key version: %w", err) + } + } + + hvClient := &vaultClient{ + client: client, + keyPath: keyPath, + transitSecretEnginePath: opts.Path, + keyCache: ttlcache.New[string, crypto.PublicKey]( + ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](), + ), + keyVersion: keyVersionUint, + } + + return hvClient, nil +} + +// NOTE: Not quite sure where to integrate this, but keeping it around for now +func oidcLogin(_ context.Context, address, path, role, token string) (string, error) { + if address == "" { + address = os.Getenv("VAULT_ADDR") + } + if address == "" { + return "", errors.New("VAULT_ADDR is not set") + } + if path == "" { + path = "jwt" + } + + client, err := vault.NewClient(&vault.Config{ + Address: address, + }) + if err != nil { + return "", fmt.Errorf("new vault client: %w", err) + } + + loginData := map[string]interface{}{ + "role": role, + "jwt": token, + } + fullpath := fmt.Sprintf("auth/%s/login", path) + resp, err := client.Logical().Write(fullpath, loginData) + if err != nil { + return "", fmt.Errorf("vault oidc login: %w", err) + } + return resp.TokenID() +} + +func (h *vaultClient) fetchPublicKey(_ context.Context) (crypto.PublicKey, error) { + client := h.client.Logical() + + path := fmt.Sprintf("/%s/keys/%s", h.transitSecretEnginePath, h.keyPath) + + keyResult, err := client.Read(path) + if err != nil { + return nil, fmt.Errorf("public key: %w", err) + } + + if keyResult == nil { + return nil, fmt.Errorf("could not read data from transit key path: %s", path) + } + + keysData, hasKeys := keyResult.Data["keys"] + latestVersion, hasVersion := keyResult.Data["latest_version"] + if !hasKeys || !hasVersion { + return nil, errors.New("failed to read transit key keys: corrupted response") + } + + keys, ok := keysData.(map[string]interface{}) + if !ok { + return nil, errors.New("failed to read transit key keys: Invalid keys map") + } + + keyVersion, ok := latestVersion.(json.Number) + if !ok { + return nil, fmt.Errorf("format of 'latest_version' is not json.Number") + } + + keyData, ok := keys[string(keyVersion)] + if !ok { + return nil, errors.New("failed to read transit key keys: corrupted response") + } + + keyMap, ok := keyData.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not parse transit key keys data as map[string]interface{}") + } + + publicKeyPem, ok := keyMap["public_key"] + if !ok { + return nil, errors.New("failed to read transit key keys: corrupted response") + } + + strPublicKeyPem, ok := publicKeyPem.(string) + if !ok { + return nil, fmt.Errorf("could not parse public key pem as string") + } + + return cryptoutils.UnmarshalPEMToPublicKey([]byte(strPublicKeyPem)) +} + +func (h *vaultClient) public() (crypto.PublicKey, error) { + var lerr error + loader := ttlcache.LoaderFunc[string, crypto.PublicKey]( + func(c *ttlcache.Cache[string, crypto.PublicKey], key string) *ttlcache.Item[string, crypto.PublicKey] { + var pubkey crypto.PublicKey + pubkey, lerr = h.fetchPublicKey(context.Background()) + if lerr == nil { + item := c.Set(key, pubkey, 300*time.Second) + return item + } + return nil + }, + ) + + item := h.keyCache.Get(cacheKey, ttlcache.WithLoader[string, crypto.PublicKey](loader)) + if lerr != nil { + return nil, lerr + } + + if item == nil { + return nil, fmt.Errorf("unable to retrieve an item from the cache by the provided key") + } + + return item.Value(), nil +} + +func (h *vaultClient) sign(ctx context.Context, digest []byte, alg crypto.Hash) ([]byte, error) { + client := h.client.Logical() + + keyVersion := fmt.Sprintf("%d", h.keyVersion) + + if keyVersion != "" { + if _, err := strconv.ParseUint(keyVersion, 10, 64); err != nil { + return nil, fmt.Errorf("parsing requested key version: %w", err) + } + } + + signResult, err := client.Write(fmt.Sprintf("/%s/sign/%s%s", h.transitSecretEnginePath, h.keyPath, hashString(alg)), map[string]interface{}{ + "input": base64.StdEncoding.Strict().EncodeToString(digest), + "prehashed": alg != crypto.Hash(0), + "key_version": keyVersion, + }) + if err != nil { + return nil, fmt.Errorf("transit: failed to sign payload: %w", err) + } + + encodedSignature, ok := signResult.Data["signature"] + if !ok { + return nil, errors.New("transit: response corrupted in-transit") + } + + return vaultDecode(encodedSignature, &keyVersion) +} + +func (h vaultClient) verify(sig, digest []byte, alg crypto.Hash) error { + client := h.client.Logical() + encodedSig := base64.StdEncoding.EncodeToString(sig) + + var vaultDataPrefix string + vaultDataPrefix = os.Getenv("VAULT_KEY_PREFIX") + if vaultDataPrefix == "" { + if h.keyVersion > 0 { + vaultDataPrefix = fmt.Sprintf("vault:v%d:", h.keyVersion) + } else { + vaultDataPrefix = vaultV1DataPrefix + } + } + + result, err := client.Write(fmt.Sprintf("/%s/verify/%s/%s", h.transitSecretEnginePath, h.keyPath, hashString(alg)), map[string]interface{}{ + "input": base64.StdEncoding.EncodeToString(digest), + "prehashed": alg != crypto.Hash(0), + "signature": fmt.Sprintf("%s%s", vaultDataPrefix, encodedSig), + }) + if err != nil { + return fmt.Errorf("verify: %w", err) + } + + valid, ok := result.Data["valid"] + if !ok { + return errors.New("corrupted response") + } + + isValid, ok := valid.(bool) + if !ok { + return fmt.Errorf("received non-bool value from 'valid' key") + } + + if !isValid { + return errors.New("failed vault verification") + } + + return nil +} + +// Vault likes to prefix base64 data with a version prefix +func vaultDecode(data interface{}, keyVersionUsed *string) ([]byte, error) { + encoded, ok := data.(string) + if !ok { + return nil, errors.New("received non-string data") + } + + if keyVersionUsed != nil { + *keyVersionUsed = prefixRegex.FindString(encoded) + } + return base64.StdEncoding.DecodeString(prefixRegex.ReplaceAllString(encoded, "")) +} + +func hashString(h crypto.Hash) string { + var hashStr string + switch h { + case crypto.SHA224: + hashStr = "/sha2-224" + case crypto.SHA256: + hashStr = "/sha2-256" + case crypto.SHA384: + hashStr = "/sha2-384" + case crypto.SHA512: + hashStr = "/sha2-512" + default: + hashStr = "" + } + return hashStr +} + +func (h vaultClient) createKey(typeStr string) (crypto.PublicKey, error) { + client := h.client.Logical() + + if _, err := client.Write(fmt.Sprintf("/%s/keys/%s", h.transitSecretEnginePath, h.keyPath), map[string]interface{}{ + "type": typeStr, + }); err != nil { + return nil, fmt.Errorf("failed to create transit key: %w", err) + } + return h.public() +} diff --git a/signer/kms/hashivault/go.mod b/signer/kms/hashivault/go.mod new file mode 100644 index 00000000..e6613e4c --- /dev/null +++ b/signer/kms/hashivault/go.mod @@ -0,0 +1,46 @@ +module github.com/in-toto/go-witness/signer/kms/hashivault + +replace github.com/in-toto/go-witness => ../../../ + +go 1.19 + +require ( + github.com/hashicorp/vault/api v1.9.0 + github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 + github.com/jellydator/ttlcache/v3 v3.1.1 + github.com/mitchellh/go-homedir v1.1.0 + github.com/sigstore/sigstore v1.5.2 +) + +require ( + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-containerregistry v0.13.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 // indirect + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.2.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/grpc v1.60.1 // indirect + google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/signer/kms/hashivault/go.sum b/signer/kms/hashivault/go.sum new file mode 100644 index 00000000..1c11766a --- /dev/null +++ b/signer/kms/hashivault/go.sum @@ -0,0 +1,127 @@ +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/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/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= +github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= +github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-containerregistry v0.13.0 h1:y1C7Z3e149OJbOPDBxLYR8ITPz8dTKqQwjErKVHJC8k= +github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +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 v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= +github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= +github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc= +github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvznI6M3KdHc= +github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= +github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL43g16EQkPV/i8+b3l5bYQwLeoSBe7tS8= +github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +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/sigstore/sigstore v1.5.2 h1:rvZSPJDH2ysoc8kjW9v4nv1UX3XwSA8y4x6Dk7hA0D4= +github.com/sigstore/sigstore v1.5.2/go.mod h1:wxhp9KoaOpeb1VLKILruD283KJqPSqX+3TuBByVDZ6E= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 h1:1i/Afw3rmaR1gF3sfVkG2X6ldkikQwA9zY380LrR5YI= +github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4/go.mod h1:vAqWV3zEs89byeFsAYoh/Q14vJTgJkHwnnRCWBBBINY= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +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.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= +golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/hashivault/rpcauth.go b/signer/kms/hashivault/rpcauth.go new file mode 100644 index 00000000..0fb464ce --- /dev/null +++ b/signer/kms/hashivault/rpcauth.go @@ -0,0 +1,75 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hashivault + +import ( + "errors" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/mitchellh/go-homedir" +) + +// RPCAuth provides credentials for RPC calls, empty fields are ignored +type RPCAuth struct { + Address string // address is the remote server address, e.g. https://vault:8200 + Path string // path for the RPC, in vault this is the transit path which default to "transit" + Token string // token used for RPC, in vault this is the VAULT_TOKEN value + OIDC RPCAuthOIDC +} + +// RPCAuthOIDC is used to perform the RPC login using OIDC instead of a fixed token +type RPCAuthOIDC struct { + Path string // path defaults to "jwt" for vault + Role string // role is required for jwt logins + Token string // token is a jwt with vault +} + +func initRPCOpts() (*RPCAuth, error) { + opts := &RPCAuth{} + + opts.Address = os.Getenv("VAULT_ADDR") + if opts.Address == "" { + return nil, errors.New("VAULT_ADDR is not set") + } + + opts.Token = os.Getenv("VAULT_TOKEN") + if opts.Token == "" { + log.Printf("VAULT_TOKEN is not set, trying to read token from file at path ~/.vault-token") + homeDir, err := homedir.Dir() + if err != nil { + return nil, fmt.Errorf("get home directory: %w", err) + } + + tokenFromFile, err := os.ReadFile(filepath.Join(homeDir, ".vault-token")) + if err != nil { + return nil, fmt.Errorf("read .vault-token file: %w", err) + } + + opts.Token = string(tokenFromFile) + if opts.Token == "" { + return nil, errors.New("failed to get token from ~/.vault-token") + } + } + + opts.Path = os.Getenv("TRANSIT_SECRET_ENGINE_PATH") + if opts.Path == "" { + opts.Path = "transit" + } + + return opts, nil +} diff --git a/signer/kms/hashivault/signer.go b/signer/kms/hashivault/signer.go new file mode 100644 index 00000000..be3c47fa --- /dev/null +++ b/signer/kms/hashivault/signer.go @@ -0,0 +1,162 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hashivault + +import ( + "context" + "crypto" + "fmt" + "io" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/log" + kms "github.com/in-toto/go-witness/signer/kms" +) + +// Taken from https://www.vaultproject.io/api/secret/transit +// nolint:revive +const ( + AlgorithmECDSAP256 = "ecdsa-p256" + AlgorithmECDSAP384 = "ecdsa-p384" + AlgorithmECDSAP521 = "ecdsa-p521" + AlgorithmED25519 = "ed25519" + AlgorithmRSA2048 = "rsa-2048" + AlgorithmRSA3072 = "rsa-3072" + AlgorithmRSA4096 = "rsa-4096" +) + +var hvSupportedAlgorithms = []string{ + AlgorithmECDSAP256, + AlgorithmECDSAP384, + AlgorithmECDSAP521, + AlgorithmED25519, + AlgorithmRSA2048, + AlgorithmRSA3072, + AlgorithmRSA4096, +} + +var hvSupportedHashFuncs = []crypto.Hash{ + crypto.SHA224, + crypto.SHA256, + crypto.SHA384, + crypto.SHA512, + crypto.Hash(0), +} + +// SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service +type SignerVerifier struct { + reference string + client *vaultClient + hashFunc crypto.Hash +} + +// LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. +func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*SignerVerifier, error) { + h := &SignerVerifier{ + reference: ksp.Reference, + } + + rpcOpts, err := initRPCOpts() + if err != nil { + return nil, fmt.Errorf("failed to initialize RPC options: %w", err) + } + + h.client, err = newVaultClient(ctx, ksp, rpcOpts) + if err != nil { + return nil, err + } + + for _, hashFunc := range hvSupportedHashFuncs { + if hashFunc == ksp.HashFunc { + h.hashFunc = ksp.HashFunc + } + } + + if h.hashFunc == 0 { + return nil, fmt.Errorf("unsupported hash function: %v", ksp.HashFunc) + } + + return h, nil +} + +// NOTE: This might be all wrong but setting it like so for now +// +// KeyID returns the key identifier for the key used by this signer. +func (h *SignerVerifier) KeyID() (string, error) { + return h.reference, nil +} + +// Sign signs the provided message using GCP KMS. If the message is provided, +// this method will compute the digest according to the hash function specified +// when the Signer was created. +func (h *SignerVerifier) Sign(message io.Reader) ([]byte, error) { + var digest []byte + var err error + ctx := context.Background() + + var signerOpts crypto.SignerOpts + hf := signerOpts.HashFunc() + + digest, _, err = cryptoutil.ComputeDigest(message, hf, hvSupportedHashFuncs) + if err != nil { + return nil, err + } + + return h.client.sign(ctx, digest, hf) +} + +// Verifier returns a cryptoutil.Verifier that can be used to verify signatures created by this signer. +func (h *SignerVerifier) Verifier() (cryptoutil.Verifier, error) { + return h, nil +} + +// PublicKey returns the public key that can be used to verify signatures created by +// this signer. +func (h *SignerVerifier) PublicKey(ctx context.Context) (crypto.PublicKey, error) { + return h.client.public() +} + +// Bytes returns the bytes of the public key that can be used to verify signatures created by the signer. +func (h *SignerVerifier) Bytes() ([]byte, error) { + pub, err := h.client.public() + if err != nil { + return nil, err + } + + return cryptoutil.PublicPemBytes(pub) +} + +// VerifySignature verifies the signature for the given message, returning +// nil if the verification succeeded, and an error message otherwise. +func (h *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { + var digest []byte + hf := h.hashFunc + err = h.client.verify(sig, digest, hf) + if err != nil { + log.Info(err.Error()) + } + + return err +} + +// SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service +func (h *SignerVerifier) SupportedAlgorithms() (result []string) { + return hvSupportedAlgorithms +} + +// DefaultAlgorithm returns the default algorithm for the GCP KMS service +func (h *SignerVerifier) DefaultAlgorithm() string { + return AlgorithmECDSAP256 +} diff --git a/signer/kms/signerprovider.go b/signer/kms/signerprovider.go index 645add04..ce4f5600 100644 --- a/signer/kms/signerprovider.go +++ b/signer/kms/signerprovider.go @@ -55,7 +55,22 @@ func init() { return ksp, nil }, ), + registry.StringConfigOption( + "keyVersion", + "The key version to use for signing", + "", + func(sp signer.SignerProvider, keyVersion string) (signer.SignerProvider, error) { + ksp, ok := sp.(*KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + WithKeyVersion(keyVersion)(ksp) + return ksp, nil + }, + ), ) + signer.RegisterVerifier("kms", func() signer.VerifierProvider { return New() }, registry.StringConfigOption( "ref", @@ -78,19 +93,34 @@ func init() { func(sp signer.VerifierProvider, hash string) (signer.VerifierProvider, error) { ksp, ok := sp.(*KMSSignerProvider) if !ok { - return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + return sp, fmt.Errorf("provided verifier provider is not a kms verifier provider") } WithHash(hash)(ksp) return ksp, nil }, ), + registry.StringConfigOption( + "keyVersion", + "The key version to use for signing", + "", + func(sp signer.VerifierProvider, keyVersion string) (signer.VerifierProvider, error) { + ksp, ok := sp.(*KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided verifier provider is not a kms verifier provider") + } + + WithKeyVersion(keyVersion)(ksp) + return ksp, nil + }, + ), ) } type KMSSignerProvider struct { - Reference string - HashFunc crypto.Hash + Reference string + KeyVersion string + HashFunc crypto.Hash } type Option func(*KMSSignerProvider) @@ -102,8 +132,7 @@ func WithRef(ref string) Option { } func WithHash(hash string) Option { - return func(ksp *KMSSignerProvider) { - // case switch to match hash type string and set hashFunc + return func(ksp *KMSSignerProvider) { // case switch to match hash type string and set hashFunc switch hash { case "SHA224": ksp.HashFunc = crypto.SHA224 @@ -119,6 +148,12 @@ func WithHash(hash string) Option { } } +func WithKeyVersion(keyVersion string) Option { + return func(ksp *KMSSignerProvider) { + ksp.KeyVersion = keyVersion + } +} + func New(opts ...Option) *KMSSignerProvider { ksp := KMSSignerProvider{} From 0ee5f0c2bf5e766c72100d28ade9afafcae6ac3c Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Fri, 26 Jan 2024 19:14:24 +0000 Subject: [PATCH 12/27] small fixes Signed-off-by: chaosinthecrd --- cryptoutil/util.go | 27 +++++++++++++ signer/kms/aws/go.mod | 2 +- signer/kms/aws/go.sum | 2 +- signer/kms/gcp/client.go | 6 +-- signer/kms/gcp/go.mod | 11 +----- signer/kms/gcp/go.sum | 32 +--------------- signer/kms/hashivault/client.go | 9 ++--- signer/kms/hashivault/go.mod | 17 ++------- signer/kms/hashivault/go.sum | 67 +++++++++------------------------ 9 files changed, 59 insertions(+), 114 deletions(-) diff --git a/cryptoutil/util.go b/cryptoutil/util.go index 5d139e6a..534d15d9 100644 --- a/cryptoutil/util.go +++ b/cryptoutil/util.go @@ -25,6 +25,16 @@ import ( "io" ) +// PEMType is a specific type for string constants used during PEM encoding and decoding +type PEMType string + +const ( + // PublicKeyPEMType is the string "PUBLIC KEY" to be used during PEM encoding and decoding + PublicKeyPEMType PEMType = "PUBLIC KEY" + // PKCS1PublicKeyPEMType is the string "RSA PUBLIC KEY" used to parse PKCS#1-encoded public keys + PKCS1PublicKeyPEMType PEMType = "RSA PUBLIC KEY" +) + type ErrUnsupportedPEM struct { t string } @@ -86,6 +96,23 @@ func PublicPemBytes(pub interface{}) ([]byte, error) { return pemBytes, err } +// UnmarshalPEMToPublicKey converts a PEM-encoded byte slice into a crypto.PublicKey +func UnmarshalPEMToPublicKey(pemBytes []byte) (crypto.PublicKey, error) { + derBytes, _ := pem.Decode(pemBytes) + if derBytes == nil { + return nil, errors.New("PEM decoding failed") + } + switch derBytes.Type { + case string(PublicKeyPEMType): + return x509.ParsePKIXPublicKey(derBytes.Bytes) + case string(PKCS1PublicKeyPEMType): + return x509.ParsePKCS1PublicKey(derBytes.Bytes) + default: + return nil, fmt.Errorf("unknown Public key PEM file type: %v. Are you passing the correct public key?", + derBytes.Type) + } +} + func TryParsePEMBlock(block *pem.Block) (interface{}, error) { if block == nil { return nil, ErrInvalidPemBlock{} diff --git a/signer/kms/aws/go.mod b/signer/kms/aws/go.mod index 3ade0453..b6950b21 100644 --- a/signer/kms/aws/go.mod +++ b/signer/kms/aws/go.mod @@ -10,6 +10,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/kms v1.27.7 github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 github.com/jellydator/ttlcache/v3 v3.1.1 + github.com/stretchr/testify v1.8.4 ) require ( @@ -27,7 +28,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect golang.org/x/sync v0.5.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/signer/kms/aws/go.sum b/signer/kms/aws/go.sum index 21ad0ede..093573fa 100644 --- a/signer/kms/aws/go.sum +++ b/signer/kms/aws/go.sum @@ -37,9 +37,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index 9bf92ceb..2eea4814 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -33,8 +33,6 @@ import ( "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/signer/kms" "github.com/jellydator/ttlcache/v3" - "github.com/sigstore/sigstore/pkg/cryptoutils" - "github.com/sigstore/sigstore/pkg/signature" ) func init() { @@ -277,7 +275,7 @@ func (g *gcpClient) fetchPublicKey(ctx context.Context, name string) (crypto.Pub if err != nil { return nil, fmt.Errorf("public key: %w", err) } - return cryptoutils.UnmarshalPEMToPublicKey([]byte(pk.GetPem())) + return cryptoutil.UnmarshalPEMToPublicKey([]byte(pk.GetPem())) } func (g *gcpClient) getHashFunc() (crypto.Hash, error) { @@ -379,7 +377,7 @@ func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { } // Seems like GCP doesn't support any remote verification, so we'll just use the local verifier -func (g *gcpClient) verify(message io.Reader, sig []byte, opts ...signature.VerifyOption) error { +func (g *gcpClient) verify(message io.Reader, sig []byte) error { crv, err := g.getCKV() if err != nil { return fmt.Errorf("transient error getting info from KMS: %w", err) diff --git a/signer/kms/gcp/go.mod b/signer/kms/gcp/go.mod index 98088b2b..fa068ef7 100644 --- a/signer/kms/gcp/go.mod +++ b/signer/kms/gcp/go.mod @@ -8,7 +8,6 @@ require ( cloud.google.com/go/kms v1.15.5 github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 github.com/jellydator/ttlcache/v3 v3.1.1 - github.com/sigstore/sigstore v1.6.4 google.golang.org/protobuf v1.32.0 ) @@ -21,14 +20,9 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-containerregistry v0.17.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect - github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/theupdateframework/go-tuf v0.5.2 // indirect - github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect @@ -40,7 +34,6 @@ require ( golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.154.0 // indirect @@ -48,7 +41,5 @@ require ( google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect - google.golang.org/grpc v1.59.0 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + google.golang.org/grpc v1.60.1 // indirect ) diff --git a/signer/kms/gcp/go.sum b/signer/kms/gcp/go.sum index 30d4ce25..e10ba960 100644 --- a/signer/kms/gcp/go.sum +++ b/signer/kms/gcp/go.sum @@ -9,9 +9,7 @@ cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXE cloud.google.com/go/kms v1.15.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/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/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= @@ -30,7 +28,6 @@ github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -57,8 +54,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk= -github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -68,23 +63,9 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e h1:RLTpX495BXToqxpM90Ws4hXEo4Wfh81jr9DX1n/4WOo= -github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e/go.mod h1:EAuqr9VFWxBi9nD5jc/EA2MT1RFty9288TF6zdtYoCU= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/sigstore/sigstore v1.6.4 h1:jH4AzR7qlEH/EWzm+opSpxCfuUcjHL+LJPuQE7h40WE= -github.com/sigstore/sigstore v1.6.4/go.mod h1:pjR64lBxnjoSrAr+Ydye/FV73IfrgtoYlAI11a8xMfA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -92,10 +73,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA= -github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA= -github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= -github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -152,8 +129,6 @@ golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -191,8 +166,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= 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= @@ -207,9 +182,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ 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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/go-jose/go-jose.v2 v2.6.1 h1:qEzJlIDmG9q5VO0M/o8tGS65QMHMS1w01TQJB1VPJ4U= -gopkg.in/go-jose/go-jose.v2 v2.6.1/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/hashivault/client.go b/signer/kms/hashivault/client.go index 198bde61..28af1eb1 100644 --- a/signer/kms/hashivault/client.go +++ b/signer/kms/hashivault/client.go @@ -1,11 +1,10 @@ -// -// Copyright 2021 The Sigstore Authors. +// Copyright 2023 The Witness Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package hashivault implement the interface with hashivault kms service package hashivault import ( @@ -32,7 +30,6 @@ import ( "github.com/in-toto/go-witness/cryptoutil" kms "github.com/in-toto/go-witness/signer/kms" "github.com/jellydator/ttlcache/v3" - "github.com/sigstore/sigstore/pkg/cryptoutils" ) func init() { @@ -205,7 +202,7 @@ func (h *vaultClient) fetchPublicKey(_ context.Context) (crypto.PublicKey, error return nil, fmt.Errorf("could not parse public key pem as string") } - return cryptoutils.UnmarshalPEMToPublicKey([]byte(strPublicKeyPem)) + return cryptoutil.UnmarshalPEMToPublicKey([]byte(strPublicKeyPem)) } func (h *vaultClient) public() (crypto.PublicKey, error) { diff --git a/signer/kms/hashivault/go.mod b/signer/kms/hashivault/go.mod index e6613e4c..d6ec5b14 100644 --- a/signer/kms/hashivault/go.mod +++ b/signer/kms/hashivault/go.mod @@ -9,15 +9,15 @@ require ( github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 github.com/jellydator/ttlcache/v3 v3.1.1 github.com/mitchellh/go-homedir v1.1.0 - github.com/sigstore/sigstore v1.5.2 ) require ( github.com/cenkalti/backoff/v3 v3.2.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-containerregistry v0.13.0 // indirect + github.com/go-test/deep v1.1.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect @@ -25,22 +25,13 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 // indirect - github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.2.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect - google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/signer/kms/hashivault/go.sum b/signer/kms/hashivault/go.sum index 1c11766a..09706982 100644 --- a/signer/kms/hashivault/go.sum +++ b/signer/kms/hashivault/go.sum @@ -1,25 +1,17 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/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/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= -github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= -github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-containerregistry v0.13.0 h1:y1C7Z3e149OJbOPDBxLYR8ITPz8dTKqQwjErKVHJC8k= -github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= @@ -28,6 +20,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n 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 v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= +github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -46,21 +39,18 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= -github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc= -github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvznI6M3KdHc= github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4= -github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL43g16EQkPV/i8+b3l5bYQwLeoSBe7tS8= -github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -68,30 +58,17 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= 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/sigstore/sigstore v1.5.2 h1:rvZSPJDH2ysoc8kjW9v4nv1UX3XwSA8y4x6Dk7hA0D4= -github.com/sigstore/sigstore v1.5.2/go.mod h1:wxhp9KoaOpeb1VLKILruD283KJqPSqX+3TuBByVDZ6E= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 h1:1i/Afw3rmaR1gF3sfVkG2X6ldkikQwA9zY380LrR5YI= -github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4/go.mod h1:vAqWV3zEs89byeFsAYoh/Q14vJTgJkHwnnRCWBBBINY= -github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= -github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= @@ -100,26 +77,18 @@ golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= 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.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 0314ccfc4bac38dd9c453a4634311a38ad850425 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Mon, 29 Jan 2024 11:25:18 +0000 Subject: [PATCH 13/27] adding unfinished fake kms client Signed-off-by: chaosinthecrd --- signer/kms/gcp/fakeclient.go | 387 +++++++++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 signer/kms/gcp/fakeclient.go diff --git a/signer/kms/gcp/fakeclient.go b/signer/kms/gcp/fakeclient.go new file mode 100644 index 00000000..0b026ee9 --- /dev/null +++ b/signer/kms/gcp/fakeclient.go @@ -0,0 +1,387 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gcp + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "errors" + "fmt" + "hash/crc32" + "io" + "regexp" + "time" + + gcpkms "cloud.google.com/go/kms/apiv1" + "cloud.google.com/go/kms/apiv1/kmspb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/signer/kms" + "github.com/jellydator/ttlcache/v3" +) + +func createRsaKey() (*rsa.PrivateKey, *rsa.PublicKey, error) { + privKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, err + } + + return privKey, &privKey.PublicKey, nil +} + +func createTestKey() (cryptoutil.Signer, cryptoutil.Verifier, error) { + privKey, pubKey, err := createRsaKey() + if err != nil { + return nil, nil, err + } + + signer := cryptoutil.NewRSASigner(privKey, crypto.SHA256) + verifier := cryptoutil.NewRSAVerifier(pubKey, crypto.SHA256) + return signer, verifier, nil +} + +var ( + errKMSReference = errors.New("kms specification should be in the format gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]") + + re = regexp.MustCompile(`^gcpkms://projects/([^/]+)/locations/([^/]+)/keyRings/([^/]+)/cryptoKeys/([^/]+)(?:/(?:cryptoKeyVersions|versions)/([^/]+))?$`) +) + +// ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets +const ReferenceScheme = "gcpkms://" + +// ValidReference returns a non-nil error if the reference string is invalid +func ValidReference(ref string) error { + if !re.MatchString(ref) { + return errKMSReference + } + return nil +} + +func parseReference(resourceID string) (projectID, locationID, keyRing, keyName, version string, err error) { + v := re.FindStringSubmatch(resourceID) + if len(v) != 6 { + err = fmt.Errorf("invalid gcpkms format %q", resourceID) + return + } + projectID, locationID, keyRing, keyName, version = v[1], v[2], v[3], v[4], v[5] + return +} + +type gcpClient struct { + projectID string + locationID string + keyRing string + keyName string + version string + kvCache *ttlcache.Cache[string, cryptoKeyVersion] + client *gcpkms.KeyManagementClient +} + +func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, error) { + if err := ValidReference(ksp.Reference); err != nil { + return nil, err + } + + if ctx == nil { + ctx = context.Background() + } + + g := &gcpClient{ + kvCache: nil, + } + + var err error + g.projectID, g.locationID, g.keyRing, g.keyName, g.version, err = parseReference(ksp.Reference) + if err != nil { + return nil, err + } + + // NOTE: We need to think about how we want to handle passing in options here + g.client, err = gcpkms.NewKeyManagementClient(ctx) + if err != nil { + return nil, fmt.Errorf("new gcp kms client: %w", err) + } + + g.kvCache = ttlcache.New[string, cryptoKeyVersion]( + ttlcache.WithDisableTouchOnHit[string, cryptoKeyVersion](), + ) + + // prime the cache + g.kvCache.Get(cacheKey) + return g, nil +} + +type cryptoKeyVersion struct { + CryptoKeyVersion *kmspb.CryptoKeyVersion + Verifier cryptoutil.Verifier + PublicKey crypto.PublicKey + HashFunc crypto.Hash +} + +// use a consistent key for cache lookups +const cacheKey = "crypto_key_version" + +func (g *gcpClient) Verifier() (cryptoutil.Verifier, error) { + crv, err := g.getCKV() + if err != nil { + return nil, fmt.Errorf("transient error while getting KMS verifier: %w", err) + } + + return crv.Verifier, nil +} + +// keyVersionName returns the first key version found for a key in KMS +func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, error) { + parent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName) + + parentReq := &kmspb.GetCryptoKeyRequest{ + Name: parent, + } + key, err := g.client.GetCryptoKey(ctx, parentReq) + if err != nil { + return nil, err + } + if key.Purpose != kmspb.CryptoKey_ASYMMETRIC_SIGN { + return nil, errors.New("specified key cannot be used to sign") + } + + // if g.version was specified, use it explicitly + var kv *kmspb.CryptoKeyVersion + if g.version != "" { + req := &kmspb.GetCryptoKeyVersionRequest{ + Name: parent + fmt.Sprintf("/cryptoKeyVersions/%s", g.version), + } + kv, err = g.client.GetCryptoKeyVersion(ctx, req) + if err != nil { + return nil, err + } + } else { + req := &kmspb.ListCryptoKeyVersionsRequest{ + Parent: parent, + Filter: "state=ENABLED", + OrderBy: "name desc", + } + iterator := g.client.ListCryptoKeyVersions(ctx, req) + + // pick the key version that is enabled with the greatest version value + kv, err = iterator.Next() + if err != nil { + return nil, fmt.Errorf("unable to find an enabled key version in GCP KMS: %w", err) + } + } + + pubKey, err := g.fetchPublicKey(ctx, kv.Name) + if err != nil { + return nil, fmt.Errorf("unable to fetch public key while creating signer: %w", err) + } + + // kv is keyVersion to use + crv := cryptoKeyVersion{ + CryptoKeyVersion: kv, + PublicKey: pubKey, + } + + // crv.Verifier is set here to enable storing the public key & hash algorithm together, + // as well as using the in memory Verifier to perform the verify operations. + switch kv.Algorithm { + case kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256: + pub, ok := pubKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewECDSAVerifier(pub, crypto.SHA256) + crv.HashFunc = crypto.SHA256 + case kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384: + pub, ok := pubKey.(*ecdsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewECDSAVerifier(pub, crypto.SHA384) + crv.HashFunc = crypto.SHA384 + case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA256) + crv.HashFunc = crypto.SHA256 + case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA384) + crv.HashFunc = crypto.SHA384 + case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA256) + crv.HashFunc = crypto.SHA256 + case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512: + pub, ok := pubKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("public key is not rsa") + } + crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA512) + crv.HashFunc = crypto.SHA512 + default: + return nil, errors.New("unknown algorithm specified by KMS") + } + if err != nil { + return nil, fmt.Errorf("initializing internal verifier: %w", err) + } + return &crv, nil +} + +func (g *gcpClient) fetchPublicKey(ctx context.Context, name string) (crypto.PublicKey, error) { + // Build the request. + pkreq := &kmspb.GetPublicKeyRequest{Name: name} + // Call the API. + pk, err := g.client.GetPublicKey(ctx, pkreq) + if err != nil { + return nil, fmt.Errorf("public key: %w", err) + } + return cryptoutil.UnmarshalPEMToPublicKey([]byte(pk.GetPem())) +} + +func (g *gcpClient) getHashFunc() (crypto.Hash, error) { + ckv, err := g.getCKV() + if err != nil { + return 0, err + } + return ckv.HashFunc, nil +} + +// getCKV gets the latest CryptoKeyVersion from the client's cache, which may trigger an actual +// call to GCP if the existing entry in the cache has expired. +func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) { + var lerr error + loader := ttlcache.LoaderFunc[string, cryptoKeyVersion]( + func(c *ttlcache.Cache[string, cryptoKeyVersion], key string) *ttlcache.Item[string, cryptoKeyVersion] { + var ttl time.Duration + var data *cryptoKeyVersion + + // if we're given an explicit version, cache this value forever + if g.version != "" { + ttl = time.Second * 0 + } else { + ttl = time.Second * 300 + } + data, lerr = g.keyVersionName(context.Background()) + if lerr == nil { + return c.Set(key, *data, ttl) + } + return nil + }, + ) + + // we get once and use consistently to ensure the cache value doesn't change underneath us + item := g.kvCache.Get(cacheKey, ttlcache.WithLoader[string, cryptoKeyVersion](loader)) + if item != nil { + v := item.Value() + return &v, nil + } + return nil, lerr +} + +func (g *gcpClient) sign(ctx context.Context, digest []byte, alg crypto.Hash, crc uint32) ([]byte, error) { + ckv, err := g.getCKV() + if err != nil { + return nil, err + } + + gcpSignReq := kmspb.AsymmetricSignRequest{ + Name: ckv.CryptoKeyVersion.Name, + Digest: &kmspb.Digest{}, + } + + if crc != 0 { + gcpSignReq.DigestCrc32C = wrapperspb.Int64(int64(crc)) + } + + switch alg { + case crypto.SHA256: + gcpSignReq.Digest.Digest = &kmspb.Digest_Sha256{ + Sha256: digest, + } + case crypto.SHA384: + gcpSignReq.Digest.Digest = &kmspb.Digest_Sha384{ + Sha384: digest, + } + case crypto.SHA512: + gcpSignReq.Digest.Digest = &kmspb.Digest_Sha512{ + Sha512: digest, + } + default: + return nil, errors.New("unsupported hash function") + } + + resp, err := g.client.AsymmetricSign(ctx, &gcpSignReq) + if err != nil { + return nil, fmt.Errorf("calling GCP AsymmetricSign: %w", err) + } + + // Optional, but recommended: perform integrity verification on result. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + if crc != 0 && !resp.VerifiedDigestCrc32C { + return nil, fmt.Errorf("AsymmetricSign: request corrupted in-transit") + } + if int64(crc32.Checksum(resp.Signature, crc32.MakeTable(crc32.Castagnoli))) != resp.SignatureCrc32C.Value { + return nil, fmt.Errorf("AsymmetricSign: response corrupted in-transit") + } + + return resp.Signature, nil +} + +func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { + crv, err := g.getCKV() + if err != nil { + return nil, fmt.Errorf("transient error getting info from KMS: %w", err) + } + return crv.PublicKey, nil +} + +// Seems like GCP doesn't support any remote verification, so we'll just use the local verifier +func (g *gcpClient) verify(message io.Reader, sig []byte) error { + crv, err := g.getCKV() + if err != nil { + return fmt.Errorf("transient error getting info from KMS: %w", err) + } + + if err := crv.Verifier.Verify(message, sig); err != nil { + // key could have been rotated, clear cache and try again if we're not pinned to a version + if g.version == "" { + g.kvCache.Delete(cacheKey) + crv, err = g.getCKV() + if err != nil { + return fmt.Errorf("transient error getting info from KMS: %w", err) + } + return crv.Verifier.Verify(message, sig) + } + return fmt.Errorf("failed to verify for fixed version: %w", err) + } + return nil +} From 429293f52ae22d0717d3976af0e1030f79ca7b85 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 1 Feb 2024 16:54:37 +0000 Subject: [PATCH 14/27] completing fake client for gcp Signed-off-by: chaosinthecrd --- signer/kms/gcp/fakeclient.go | 185 +++++++---------------------------- signer/kms/gcp/go.mod | 4 + signer/kms/gcp/go.sum | 2 + 3 files changed, 42 insertions(+), 149 deletions(-) diff --git a/signer/kms/gcp/fakeclient.go b/signer/kms/gcp/fakeclient.go index 0b026ee9..1d87f942 100644 --- a/signer/kms/gcp/fakeclient.go +++ b/signer/kms/gcp/fakeclient.go @@ -15,6 +15,7 @@ package gcp import ( + "bytes" "context" "crypto" "crypto/ecdsa" @@ -22,14 +23,10 @@ import ( "crypto/rsa" "errors" "fmt" - "hash/crc32" "io" - "regexp" "time" - gcpkms "cloud.google.com/go/kms/apiv1" "cloud.google.com/go/kms/apiv1/kmspb" - "google.golang.org/protobuf/types/known/wrapperspb" "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/signer/kms" @@ -56,44 +53,18 @@ func createTestKey() (cryptoutil.Signer, cryptoutil.Verifier, error) { return signer, verifier, nil } -var ( - errKMSReference = errors.New("kms specification should be in the format gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]") - - re = regexp.MustCompile(`^gcpkms://projects/([^/]+)/locations/([^/]+)/keyRings/([^/]+)/cryptoKeys/([^/]+)(?:/(?:cryptoKeyVersions|versions)/([^/]+))?$`) -) - -// ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets -const ReferenceScheme = "gcpkms://" - -// ValidReference returns a non-nil error if the reference string is invalid -func ValidReference(ref string) error { - if !re.MatchString(ref) { - return errKMSReference - } - return nil -} - -func parseReference(resourceID string) (projectID, locationID, keyRing, keyName, version string, err error) { - v := re.FindStringSubmatch(resourceID) - if len(v) != 6 { - err = fmt.Errorf("invalid gcpkms format %q", resourceID) - return - } - projectID, locationID, keyRing, keyName, version = v[1], v[2], v[3], v[4], v[5] - return -} - -type gcpClient struct { +type fakeGCPClient struct { projectID string locationID string keyRing string keyName string version string kvCache *ttlcache.Cache[string, cryptoKeyVersion] - client *gcpkms.KeyManagementClient + signer cryptoutil.Signer } -func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, error) { +func newFakeGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*fakeGCPClient, error) { + fmt.Println(ksp.Reference) if err := ValidReference(ksp.Reference); err != nil { return nil, err } @@ -102,7 +73,7 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, ctx = context.Background() } - g := &gcpClient{ + g := &fakeGCPClient{ kvCache: nil, } @@ -112,12 +83,6 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, return nil, err } - // NOTE: We need to think about how we want to handle passing in options here - g.client, err = gcpkms.NewKeyManagementClient(ctx) - if err != nil { - return nil, fmt.Errorf("new gcp kms client: %w", err) - } - g.kvCache = ttlcache.New[string, cryptoKeyVersion]( ttlcache.WithDisableTouchOnHit[string, cryptoKeyVersion](), ) @@ -127,17 +92,7 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, return g, nil } -type cryptoKeyVersion struct { - CryptoKeyVersion *kmspb.CryptoKeyVersion - Verifier cryptoutil.Verifier - PublicKey crypto.PublicKey - HashFunc crypto.Hash -} - -// use a consistent key for cache lookups -const cacheKey = "crypto_key_version" - -func (g *gcpClient) Verifier() (cryptoutil.Verifier, error) { +func (g *fakeGCPClient) Verifier() (cryptoutil.Verifier, error) { crv, err := g.getCKV() if err != nil { return nil, fmt.Errorf("transient error while getting KMS verifier: %w", err) @@ -147,59 +102,26 @@ func (g *gcpClient) Verifier() (cryptoutil.Verifier, error) { } // keyVersionName returns the first key version found for a key in KMS -func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, error) { - parent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName) - - parentReq := &kmspb.GetCryptoKeyRequest{ - Name: parent, - } - key, err := g.client.GetCryptoKey(ctx, parentReq) - if err != nil { - return nil, err - } - if key.Purpose != kmspb.CryptoKey_ASYMMETRIC_SIGN { - return nil, errors.New("specified key cannot be used to sign") - } - - // if g.version was specified, use it explicitly - var kv *kmspb.CryptoKeyVersion - if g.version != "" { - req := &kmspb.GetCryptoKeyVersionRequest{ - Name: parent + fmt.Sprintf("/cryptoKeyVersions/%s", g.version), - } - kv, err = g.client.GetCryptoKeyVersion(ctx, req) - if err != nil { - return nil, err - } - } else { - req := &kmspb.ListCryptoKeyVersionsRequest{ - Parent: parent, - Filter: "state=ENABLED", - OrderBy: "name desc", - } - iterator := g.client.ListCryptoKeyVersions(ctx, req) - - // pick the key version that is enabled with the greatest version value - kv, err = iterator.Next() - if err != nil { - return nil, fmt.Errorf("unable to find an enabled key version in GCP KMS: %w", err) - } - } - - pubKey, err := g.fetchPublicKey(ctx, kv.Name) +func (g *fakeGCPClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, error) { + pubKey, err := g.fetchPublicKey(ctx, "1") if err != nil { return nil, fmt.Errorf("unable to fetch public key while creating signer: %w", err) } // kv is keyVersion to use crv := cryptoKeyVersion{ - CryptoKeyVersion: kv, - PublicKey: pubKey, + CryptoKeyVersion: &kmspb.CryptoKeyVersion{ + Name: "1", + Algorithm: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, + }, + PublicKey: pubKey, } + g.version = "1" + // crv.Verifier is set here to enable storing the public key & hash algorithm together, // as well as using the in memory Verifier to perform the verify operations. - switch kv.Algorithm { + switch crv.CryptoKeyVersion.Algorithm { case kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256: pub, ok := pubKey.(*ecdsa.PublicKey) if !ok { @@ -252,21 +174,22 @@ func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, erro if err != nil { return nil, fmt.Errorf("initializing internal verifier: %w", err) } + return &crv, nil } -func (g *gcpClient) fetchPublicKey(ctx context.Context, name string) (crypto.PublicKey, error) { - // Build the request. - pkreq := &kmspb.GetPublicKeyRequest{Name: name} - // Call the API. - pk, err := g.client.GetPublicKey(ctx, pkreq) +func (g *fakeGCPClient) fetchPublicKey(ctx context.Context, name string) (crypto.PublicKey, error) { + priv, pub, err := createRsaKey() if err != nil { - return nil, fmt.Errorf("public key: %w", err) + return nil, err } - return cryptoutil.UnmarshalPEMToPublicKey([]byte(pk.GetPem())) + sign := cryptoutil.NewRSASigner(priv, crypto.SHA256) + g.signer = sign + + return pub, nil } -func (g *gcpClient) getHashFunc() (crypto.Hash, error) { +func (g *fakeGCPClient) getHashFunc() (crypto.Hash, error) { ckv, err := g.getCKV() if err != nil { return 0, err @@ -276,7 +199,7 @@ func (g *gcpClient) getHashFunc() (crypto.Hash, error) { // getCKV gets the latest CryptoKeyVersion from the client's cache, which may trigger an actual // call to GCP if the existing entry in the cache has expired. -func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) { +func (g *fakeGCPClient) getCKV() (*cryptoKeyVersion, error) { var lerr error loader := ttlcache.LoaderFunc[string, cryptoKeyVersion]( func(c *ttlcache.Cache[string, cryptoKeyVersion], key string) *ttlcache.Item[string, cryptoKeyVersion] { @@ -303,60 +226,23 @@ func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) { v := item.Value() return &v, nil } + return nil, lerr } -func (g *gcpClient) sign(ctx context.Context, digest []byte, alg crypto.Hash, crc uint32) ([]byte, error) { - ckv, err := g.getCKV() +func (g *fakeGCPClient) sign(ctx context.Context, digest []byte, alg crypto.Hash, crc uint32) ([]byte, error) { + _, err := g.getCKV() if err != nil { return nil, err } - gcpSignReq := kmspb.AsymmetricSignRequest{ - Name: ckv.CryptoKeyVersion.Name, - Digest: &kmspb.Digest{}, - } - - if crc != 0 { - gcpSignReq.DigestCrc32C = wrapperspb.Int64(int64(crc)) - } + reader := bytes.NewReader(digest) + sig, err := g.signer.Sign(reader) - switch alg { - case crypto.SHA256: - gcpSignReq.Digest.Digest = &kmspb.Digest_Sha256{ - Sha256: digest, - } - case crypto.SHA384: - gcpSignReq.Digest.Digest = &kmspb.Digest_Sha384{ - Sha384: digest, - } - case crypto.SHA512: - gcpSignReq.Digest.Digest = &kmspb.Digest_Sha512{ - Sha512: digest, - } - default: - return nil, errors.New("unsupported hash function") - } - - resp, err := g.client.AsymmetricSign(ctx, &gcpSignReq) - if err != nil { - return nil, fmt.Errorf("calling GCP AsymmetricSign: %w", err) - } - - // Optional, but recommended: perform integrity verification on result. - // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: - // https://cloud.google.com/kms/docs/data-integrity-guidelines - if crc != 0 && !resp.VerifiedDigestCrc32C { - return nil, fmt.Errorf("AsymmetricSign: request corrupted in-transit") - } - if int64(crc32.Checksum(resp.Signature, crc32.MakeTable(crc32.Castagnoli))) != resp.SignatureCrc32C.Value { - return nil, fmt.Errorf("AsymmetricSign: response corrupted in-transit") - } - - return resp.Signature, nil + return sig, nil } -func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { +func (g *fakeGCPClient) public(ctx context.Context) (crypto.PublicKey, error) { crv, err := g.getCKV() if err != nil { return nil, fmt.Errorf("transient error getting info from KMS: %w", err) @@ -365,7 +251,7 @@ func (g *gcpClient) public(ctx context.Context) (crypto.PublicKey, error) { } // Seems like GCP doesn't support any remote verification, so we'll just use the local verifier -func (g *gcpClient) verify(message io.Reader, sig []byte) error { +func (g *fakeGCPClient) verify(message io.Reader, sig []byte) error { crv, err := g.getCKV() if err != nil { return fmt.Errorf("transient error getting info from KMS: %w", err) @@ -383,5 +269,6 @@ func (g *gcpClient) verify(message io.Reader, sig []byte) error { } return fmt.Errorf("failed to verify for fixed version: %w", err) } + return nil } diff --git a/signer/kms/gcp/go.mod b/signer/kms/gcp/go.mod index fa068ef7..e8fa31bf 100644 --- a/signer/kms/gcp/go.mod +++ b/signer/kms/gcp/go.mod @@ -8,6 +8,7 @@ require ( cloud.google.com/go/kms v1.15.5 github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 github.com/jellydator/ttlcache/v3 v3.1.1 + github.com/stretchr/testify v1.8.4 google.golang.org/protobuf v1.32.0 ) @@ -15,6 +16,7 @@ require ( 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.5 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -23,6 +25,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect @@ -42,4 +45,5 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect google.golang.org/grpc v1.60.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/signer/kms/gcp/go.sum b/signer/kms/gcp/go.sum index e10ba960..bc41fb34 100644 --- a/signer/kms/gcp/go.sum +++ b/signer/kms/gcp/go.sum @@ -73,6 +73,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -181,6 +182,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From c7c932923375522b6e55a343233cbd6d20c6140e Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 1 Feb 2024 16:55:19 +0000 Subject: [PATCH 15/27] adding signer test for gcp Signed-off-by: chaosinthecrd --- signer/kms/gcp/signer_test.go | 315 ++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 signer/kms/gcp/signer_test.go diff --git a/signer/kms/gcp/signer_test.go b/signer/kms/gcp/signer_test.go new file mode 100644 index 00000000..2adbdcc4 --- /dev/null +++ b/signer/kms/gcp/signer_test.go @@ -0,0 +1,315 @@ +// Copyright 2023 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gcp + +import ( + "bytes" + "context" + "crypto" + "fmt" + "testing" + + "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/signer/kms" + "github.com/stretchr/testify/assert" +) + +func TestParseReference(t *testing.T) { + tests := []struct { + in string + wantProjectID string + wantLocationID string + wantKeyRing string + wantKeyName string + wantKeyVersion string + wantErr bool + }{ + { + in: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + wantProjectID: "pp", + wantLocationID: "ll", + wantKeyRing: "rr", + wantKeyName: "kk", + wantErr: false, + }, + { + in: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk/versions/1", + wantProjectID: "pp", + wantLocationID: "ll", + wantKeyRing: "rr", + wantKeyName: "kk", + wantKeyVersion: "1", + wantErr: false, + }, + { + in: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk/cryptoKeyVersions/1", + wantProjectID: "pp", + wantLocationID: "ll", + wantKeyRing: "rr", + wantKeyName: "kk", + wantKeyVersion: "1", + wantErr: false, + }, + { + in: "gcpkms://projects/p1/p2/locations/l1/l2/keyRings/r1/r2/cryptoKeys/k1", + wantErr: true, + }, + { + in: "foo://bar", + wantErr: true, + }, + { + in: "", + wantErr: true, + }, + { + in: "gcpkms://projects/p1/p2/locations/l1/l2/keyRings/r1/r2/cryptoKeys/k1/versions", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.in, func(t *testing.T) { + gotProjectID, gotLocationID, gotKeyRing, gotKeyName, gotKeyVersion, err := parseReference(tt.in) + if (err != nil) != tt.wantErr { + t.Errorf("parseReference() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotProjectID != tt.wantProjectID { + t.Errorf("parseReference() gotProjectID = %v, want %v", gotProjectID, tt.wantProjectID) + } + if gotLocationID != tt.wantLocationID { + t.Errorf("parseReference() gotLocationID = %v, want %v", gotLocationID, tt.wantLocationID) + } + if gotKeyRing != tt.wantKeyRing { + t.Errorf("parseReference() gotKeyRing = %v, want %v", gotKeyRing, tt.wantKeyRing) + } + if gotKeyName != tt.wantKeyName { + t.Errorf("parseReference() gotKeyName = %v, want %v", gotKeyName, tt.wantKeyName) + } + if gotKeyVersion != tt.wantKeyVersion { + t.Errorf("parseReference() gotKeyVersion = %v, want %v", gotKeyVersion, tt.wantKeyVersion) + } + }) + } +} + +func TestSign(t *testing.T) { + tests := []struct { + name string + ref string + hash crypto.Hash + message string + wantErr bool + expectedErr error + }{ + { + name: "successful sign", + ref: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + hash: crypto.SHA256, + message: "foo", + wantErr: false, + }, + { + name: "SHA-512", + ref: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + hash: crypto.SHA512, + message: "foo", + wantErr: false, + }, + { + name: "bad ref", + ref: "blablabla", + hash: crypto.SHA256, + message: "foo", + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + { + name: "unsupported hash algorithm", + ref: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + hash: crypto.RIPEMD160, + message: "foo", + wantErr: true, + expectedErr: fmt.Errorf(`unsupported hash algorithm: "RIPEMD-160" not in [SHA-256 SHA-384 SHA-512]`), + }, + { + name: "aws ref", + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + hash: crypto.SHA256, + message: "foobarbaz", + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + } + + for _, tt := range tests { + fmt.Println("sign test: ", tt.name) + ctx := context.TODO() + dig, _, err := cryptoutil.ComputeDigest(bytes.NewReader([]byte(tt.message)), tt.hash, gcpSupportedHashFuncs) + if tt.wantErr && err != nil { + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + ksp := kms.New(kms.WithRef(tt.ref), kms.WithHash(tt.hash.String())) + c, err := newFakeGCPClient(context.TODO(), ksp) + if tt.wantErr && err != nil { + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + s, err := c.sign(ctx, dig, tt.hash, 00) + if tt.wantErr && err != nil { + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + if s == nil { + t.Fatal("signature is nil") + } + + if tt.wantErr { + t.Fatalf("expected test %s to fail", tt.name) + } + + } +} + +func TestVerify(t *testing.T) { + tests := []struct { + name string + ref string + hash crypto.Hash + mess []string + wantErr bool + expectedErr error + }{ + { + name: "successful verify", + hash: crypto.SHA256, + ref: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + mess: []string{"foo", "bar", "baz"}, + wantErr: false, + }, + { + name: "SHA-512", + hash: crypto.SHA512, + ref: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + mess: []string{"foo", "bar", "baz"}, + wantErr: false, + }, + { + name: "bad ref", + hash: crypto.SHA256, + ref: "blablabla", + mess: []string{"foo", "bar", "baz"}, + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + { + name: "unsupported hash algorithm", + hash: crypto.RIPEMD160, + ref: "gcpkms://projects/pp/locations/ll/keyRings/rr/cryptoKeys/kk", + mess: []string{"foo", "bar", "baz"}, + wantErr: true, + expectedErr: fmt.Errorf(`unsupported hash algorithm: "RIPEMD-160" not in [SHA-256 SHA-384 SHA-512]`), + }, + { + name: "aws ref", + hash: crypto.SHA256, + ref: "awskms:///arn:aws-us-gov:kms:us-gov-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", + mess: []string{"foo", "bar", "baz"}, + wantErr: true, + expectedErr: fmt.Errorf("kms specification should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)"), + }, + } + + for _, tt := range tests { + errFound := false + fmt.Println("verify test: ", tt.name) + ctx := context.TODO() + ksp := kms.New(kms.WithRef(tt.ref), kms.WithHash(tt.hash.String())) + c, err := newFakeGCPClient(context.TODO(), ksp) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + for _, mess := range tt.mess { + bs, bv, err := createTestKey() + if err != nil { + t.Fatal(err) + } + + dig, _, err := cryptoutil.ComputeDigest(bytes.NewReader([]byte(mess)), tt.hash, gcpSupportedHashFuncs) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + sig, err := c.sign(ctx, []byte(dig), crypto.SHA256, 00) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + bsig, err := bs.Sign(bytes.NewReader([]byte(dig))) + if err != nil { + t.Fatal(err) + } + + r := bytes.NewReader([]byte(dig)) + + err = c.verify(r, sig) + if tt.wantErr && err != nil { + errFound = true + assert.ErrorAs(t, err, &tt.expectedErr) + continue + } else if err != nil { + t.Fatal(err) + } + + err = c.verify(r, bsig) + if err == nil { + t.Fatal("expected verification to fail") + } + + err = bv.Verify(bytes.NewReader([]byte(dig)), sig) + if err == nil { + t.Fatal("expected verification to fail") + } + + } + + if tt.wantErr && !errFound { + t.Fatalf("expected test %s to fail with error %s", tt.name, tt.expectedErr.Error()) + } + } +} From 0a45306535dc62d8cb9c448cc82f3c63b27e6d6a Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 1 Feb 2024 19:00:05 +0000 Subject: [PATCH 16/27] fixing local verification and adding support for PKCS #1 v1.5 Signed-off-by: chaosinthecrd --- cryptoutil/rsa.go | 7 ++++++- cryptoutil/util.go | 17 +---------------- signer/kms/aws/signer.go | 18 +++++++++++------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/cryptoutil/rsa.go b/cryptoutil/rsa.go index 1dfbb504..a3d617fc 100644 --- a/cryptoutil/rsa.go +++ b/cryptoutil/rsa.go @@ -76,7 +76,12 @@ func (v *RSAVerifier) Verify(data io.Reader, sig []byte) error { Hash: v.hash, } - return rsa.VerifyPSS(v.pub, v.hash, digest, sig, pssOpts) + // AWS KMS introduces the chance that attestations get signed by PKCS1v15 instead of PSS + if err := rsa.VerifyPSS(v.pub, v.hash, digest, sig, pssOpts); err != nil { + return rsa.VerifyPKCS1v15(v.pub, v.hash, digest, sig) + } + + return nil } func (v *RSAVerifier) Bytes() ([]byte, error) { diff --git a/cryptoutil/util.go b/cryptoutil/util.go index 534d15d9..2b96280b 100644 --- a/cryptoutil/util.go +++ b/cryptoutil/util.go @@ -184,7 +184,7 @@ func ComputeDigest(rawMessage io.Reader, hashFunc crypto.Hash, supportedHashFunc return nil, crypto.Hash(0), fmt.Errorf("unsupported hash algorithm: %q not in %v", hashedWith.String(), supportedHashFuncs) } - digest, err := hashMessage(rawMessage, hashedWith) + digest, err := Digest(rawMessage, hashedWith) return digest, hashedWith, err } @@ -199,18 +199,3 @@ func isSupportedAlg(alg crypto.Hash, supportedAlgs []crypto.Hash) bool { } return false } - -func hashMessage(rawMessage io.Reader, hashFunc crypto.Hash) ([]byte, error) { - if rawMessage == nil { - return nil, errors.New("message cannot be nil") - } - if hashFunc == crypto.Hash(0) { - return io.ReadAll(rawMessage) - } - hasher := hashFunc.New() - // avoids reading entire message into memory - if _, err := io.Copy(hasher, rawMessage); err != nil { - return nil, fmt.Errorf("hashing message: %w", err) - } - return hasher.Sum(nil), nil -} diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 1f60018c..123a41c0 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -15,13 +15,16 @@ package aws import ( + "bytes" "context" "crypto" "fmt" "io" + "os" "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/log" kms "github.com/in-toto/go-witness/signer/kms" ) @@ -119,7 +122,7 @@ func (a *SignerVerifier) Bytes() ([]byte, error) { return cryptoutil.PublicPemBytes(p) } -// VerifySignature verifies the signature for the given message, returning +// Verify verifies the signature for the given message, returning // nil if the verification succeeded, and an error message otherwise. func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { ctx := context.Background() @@ -132,18 +135,19 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { } hf := signerOpts.HashFunc() - // if we verify remotely, we need to compute the digest first - digest, _, err = cryptoutil.ComputeDigest(message, hf, awsSupportedHashFuncs) - if err != nil { - return err + // we want to verify remotely unless we explicitly ask to verify locally + if os.Getenv("WITNESS_AWS_VERIFY_LOCALLY") == "1" { + log.Debug("Environment variable WITNESS_AWS_VERIFY_LOCALLY set to 1, verifying locally") + return a.client.verify(ctx, bytes.NewReader(sig), message) } - err = a.client.verifyRemotely(ctx, sig, digest) + // if we verify remotely, we need to compute the digest first + digest, _, err = cryptoutil.ComputeDigest(message, hf, awsSupportedHashFuncs) if err != nil { return err } - return err + return a.client.verifyRemotely(ctx, sig, digest) } // SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service From df50669d091bc03bd1ed45610c5a3ed6b28117bc Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 6 Feb 2024 15:53:28 +0000 Subject: [PATCH 17/27] the nested module isn't needed here Signed-off-by: chaosinthecrd --- signer/kms/aws/go.mod | 33 -------- signer/kms/aws/go.sum | 45 ---------- signer/kms/gcp/go.mod | 49 ----------- signer/kms/gcp/go.sum | 191 ------------------------------------------ 4 files changed, 318 deletions(-) delete mode 100644 signer/kms/aws/go.mod delete mode 100644 signer/kms/aws/go.sum delete mode 100644 signer/kms/gcp/go.mod delete mode 100644 signer/kms/gcp/go.sum diff --git a/signer/kms/aws/go.mod b/signer/kms/aws/go.mod deleted file mode 100644 index b6950b21..00000000 --- a/signer/kms/aws/go.mod +++ /dev/null @@ -1,33 +0,0 @@ -module github.com/in-toto/go-witness/signer/kms/aws - -replace github.com/in-toto/go-witness => ../../../ - -go 1.19 - -require ( - github.com/aws/aws-sdk-go-v2 v1.24.0 - github.com/aws/aws-sdk-go-v2/config v1.26.2 - github.com/aws/aws-sdk-go-v2/service/kms v1.27.7 - github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 - github.com/jellydator/ttlcache/v3 v3.1.1 - github.com/stretchr/testify v1.8.4 -) - -require ( - github.com/aws/aws-sdk-go-v2/credentials v1.16.13 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // 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.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 // indirect - github.com/aws/smithy-go v1.19.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sync v0.5.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/signer/kms/aws/go.sum b/signer/kms/aws/go.sum deleted file mode 100644 index 093573fa..00000000 --- a/signer/kms/aws/go.sum +++ /dev/null @@ -1,45 +0,0 @@ -github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= -github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.2 h1:+RWLEIWQIGgrz2pBPAUoGgNGs1TOyF4Hml7hCnYj2jc= -github.com/aws/aws-sdk-go-v2/config v1.26.2/go.mod h1:l6xqvUxt0Oj7PI/SUXYLNyZ9T/yBPn3YTQcJLLOdtR8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.13 h1:WLABQ4Cp4vXtXfOWOS3MEZKr6AAYUpMczLhgKtAjQ/8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.13/go.mod h1:Qg6x82FXwW0sJHzYruxGiuApNo31UEtJvXVSZAXeWiw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/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.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.7 h1:wN7AN7iOiAgT9HmdifZNSvbr6S7gSpLjSSOQHIaGmFc= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.7/go.mod h1:D9FVDkZjkZnnFHymJ3fPVz0zOUlNSd0xcIIVmmrAac8= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.6 h1:HJeiuZ2fldpd0WqngyMR6KW7ofkXNLyOaHwEIGm39Cs= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.6/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= -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/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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= -github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/gcp/go.mod b/signer/kms/gcp/go.mod deleted file mode 100644 index e8fa31bf..00000000 --- a/signer/kms/gcp/go.mod +++ /dev/null @@ -1,49 +0,0 @@ -module github.com/in-toto/go-witness/signer/kms/gcp - -replace github.com/in-toto/go-witness => ../../../ - -go 1.19 - -require ( - cloud.google.com/go/kms v1.15.5 - github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 - github.com/jellydator/ttlcache/v3 v3.1.1 - github.com/stretchr/testify v1.8.4 - google.golang.org/protobuf v1.32.0 -) - -require ( - 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.5 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-logr/logr v1.3.0 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/api v0.154.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect - google.golang.org/grpc v1.60.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/signer/kms/gcp/go.sum b/signer/kms/gcp/go.sum deleted file mode 100644 index bc41fb34..00000000 --- a/signer/kms/gcp/go.sum +++ /dev/null @@ -1,191 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= -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/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.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= -cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -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/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= -github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.154.0 h1:X7QkVKZBskztmpPKWQXgjJRPA2dJYrL6r+sYPRLj050= -google.golang.org/api v0.154.0/go.mod h1:qhSMkM85hgqiokIYsrRyKxrjfBeIhgl4Z2JmeRkYylc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f h1:Vn+VyHU5guc9KjB5KrjI2q0wCOWEOIh0OEsleqakHJg= -google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.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.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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 4c51653a6156ff036f1f5c35ed9cedfe0e6f8696 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 8 Feb 2024 18:13:38 +0000 Subject: [PATCH 18/27] adding implementation for kms provider options Signed-off-by: chaosinthecrd --- attestation/context.go | 2 +- go.mod | 26 ++++++- go.sum | 145 +++++++++++++++++++++++++++++++++++ signer/kms/aws/client.go | 72 +++++++++++++++-- signer/kms/aws/signer.go | 8 +- signer/kms/gcp/client.go | 3 +- signer/kms/signerprovider.go | 25 +++++- 7 files changed, 270 insertions(+), 11 deletions(-) diff --git a/attestation/context.go b/attestation/context.go index d73655da..bef8e7bc 100644 --- a/attestation/context.go +++ b/attestation/context.go @@ -137,7 +137,7 @@ func (ctx *AttestationContext) RunAttestors() error { order := runTypeOrder() for _, k := range order { - log.Debugf("starting %s attestors...", k.String()) + log.Debugf("Starting %s attestors...", k.String()) for _, att := range attestors[k] { log.Infof("Starting %v attestor...", att.Name()) ctx.runAttestor(att) diff --git a/go.mod b/go.mod index 08744613..238d6852 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,16 @@ module github.com/in-toto/go-witness go 1.21 require ( + cloud.google.com/go/kms v1.15.2 + github.com/aws/aws-sdk-go-v2 v1.17.5 + github.com/aws/aws-sdk-go-v2/config v1.18.14 + github.com/aws/aws-sdk-go-v2/service/kms v1.20.4 github.com/digitorus/pkcs7 v0.0.0-20230220124406-51331ccfc40f github.com/digitorus/timestamp v0.0.0-20230220124323-d542479a2425 github.com/edwarnicke/gitoid v0.0.0-20220710194850-1be5bfda1f9d github.com/go-git/go-git/v5 v5.11.0 github.com/in-toto/archivista v0.2.0 + github.com/jellydator/ttlcache/v3 v3.1.1 github.com/mattn/go-isatty v0.0.20 github.com/open-policy-agent/opa v0.49.2 github.com/owenrumney/go-sarif v1.1.1 @@ -21,9 +26,22 @@ require ( ) require ( + cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.2 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.14 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.4 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/coreos/go-oidc/v3 v3.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -36,6 +54,9 @@ require ( github.com/google/flatbuffers v2.0.8+incompatible // indirect github.com/google/go-containerregistry v0.13.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -51,9 +72,12 @@ require ( github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/zclconf/go-cty v1.12.1 // indirect + go.opencensus.io v0.24.0 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/tools v0.13.0 // indirect + google.golang.org/api v0.128.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect @@ -93,7 +117,7 @@ require ( golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.32.0 gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 7e9e1dbf..670806e9 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,21 @@ +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.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= +cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +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/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4= +cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE= +cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= @@ -14,6 +27,7 @@ github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRB github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= @@ -21,18 +35,53 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.44.334 h1:h2bdbGb//fez6Sv6PaYv868s9liDeoYM6hYsAqTB4MU= github.com/aws/aws-sdk-go v1.44.334/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.17.5 h1:TzCUW1Nq4H8Xscph5M/skINUitxM5UBAyvm2s7XBzL4= +github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.14 h1:rI47jCe0EzuJlAO5ptREe3LIBAyP5c7gR3wjyYVjuOM= +github.com/aws/aws-sdk-go-v2/config v1.18.14/go.mod h1:0pI6JQBHKwd0JnwAZS3VCapLKMO++UL2BOkWwyyzTnA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.14 h1:jE34fUepssrhmYpvPpdbd+d39PHpuignDpNPNJguP60= +github.com/aws/aws-sdk-go-v2/credentials v1.13.14/go.mod h1:85ckagDuzdIOnZRwws1eLKnymJs3ZM1QwVC1XcuNGOY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 h1:Kbiv9PGnQfG/imNI4L/heyUXvzKmcWSBeDvkrQz5pFc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23/go.mod h1:mOtmAg65GT1HIL/HT/PynwPbS+UG0BgCZ6vhkPqnxWo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29 h1:9/aKwwus0TQxppPXFmf010DFrE+ssSbzroLVYINA+xE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23 h1:b/Vn141DBuLVgXbhRWIrl9g+ww7G+ScV5SzniWR13jQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 h1:IVx9L7YFhpPq0tTnGo8u8TpluFu7nAn9X3sUDMb11c0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30/go.mod h1:vsbq62AOBwQ1LJ/GWKFxX8beUEYeRp/Agitrxee2/qM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23 h1:QoOybhwRfciWUBbZ0gp9S7XaDnCuSTeK/fySB99V1ls= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23/go.mod h1:9uPh+Hrz2Vn6oMnQYiUi/zbh3ovbnQk19YKINkQny44= +github.com/aws/aws-sdk-go-v2/service/kms v1.20.4 h1:FOY3JSIwgItCdaeuLKjtijD8Enx6BHy5nSS/V6COOeA= +github.com/aws/aws-sdk-go-v2/service/kms v1.20.4/go.mod h1:oTK4GAHgyFSGKzhReYfD19/vjtgUOPwCbm7v5MgWLW4= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.3 h1:bUeZTWfF1vBdZnoNnnq70rB/CzdZD7NR2Jg2Ax+rvjA= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.3/go.mod h1:jtLIhd+V+lft6ktxpItycqHqiVXrPIRjWIsFIlzMriw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3 h1:G/+7NUi+q+H0LG3v32jfV4OkaQIcpI92g0owbXKk6NY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.3/go.mod h1:zVwRrfdSmbRZWkUkWjOItY7SOalnFnq/Yg2LVPqDjwc= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.4 h1:j0USUNbl9c/8tBJ8setEbwxc7wva0WyoeAaFRiyTUT8= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.4/go.mod h1:1mKZHLLpDMHTNSYPJ7qrcnCQdHCWsNQaT0xRvq2u80s= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= 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/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 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= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= @@ -59,6 +108,12 @@ github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcej github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= @@ -95,12 +150,26 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/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/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.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.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -109,8 +178,12 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -120,6 +193,14 @@ github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbW github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= +github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A= github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH49WLF3F2LaWnYYuDVd+EWrc0= github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc= @@ -130,6 +211,8 @@ github.com/in-toto/archivista v0.2.0 h1:FViuHMVVETborvOqlmSYdROY8RmX3CO0V0MOhU/R github.com/in-toto/archivista v0.2.0/go.mod h1:qt9uN4TkHWUgR5A2wxRqQIBizSl32P2nI2AjESskkr0= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= +github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -180,6 +263,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= @@ -188,6 +272,7 @@ github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJf github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= @@ -212,11 +297,17 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spiffe/go-spiffe/v2 v2.1.7 h1:VUkM1yIyg/x8X7u1uXqSRVRCdMdfRIEdFBzpqoeASGk= github.com/spiffe/go-spiffe/v2 v2.1.7/go.mod h1:QJDGdhXllxjxvd5B+2XnhhXB/+rC8gr+lNrtOryiWeE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= @@ -256,30 +347,45 @@ github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.step.sm/crypto v0.25.2 h1:NgoI3bcNF0iLI+Rwq00brlJyFfMqseLOa8L8No3Daog= go.step.sm/crypto v0.25.2/go.mod h1:4pUEuZ+4OAf2f70RgW5oRv/rJudibcAAWQg5prC3DT8= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -291,9 +397,14 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +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-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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -301,9 +412,11 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -342,6 +455,10 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -353,18 +470,43 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= +google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a h1:fwgW9j3vHirt4ObdHoYNwuO24BEZjSzbh+zPaNWoiY8= google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.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.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= @@ -384,12 +526,15 @@ gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/apimachinery v0.26.13 h1:gTwNkZp+qrfZuhQFMD594ggzvcr06mbgAtLBTbdc4Mg= k8s.io/apimachinery v0.26.13/go.mod h1:2/HZp0l6coXtS26du1Bk36fCuAEr/lVs9Q9NbpBtd1Y= k8s.io/klog/v2 v2.90.0 h1:VkTxIV/FjRXn1fgNNcKGM8cfmL1Z33ZjXRTVxKCoF5M= diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index adec837d..4f6b451b 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -23,8 +23,8 @@ import ( "fmt" "io" "net/http" - "os" "regexp" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -32,23 +32,24 @@ import ( akms "github.com/aws/aws-sdk-go-v2/service/kms" "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/log" + "github.com/in-toto/go-witness/registry" + "github.com/in-toto/go-witness/signer" "github.com/in-toto/go-witness/signer/kms" ttlcache "github.com/jellydator/ttlcache/v3" ) type client interface { + getHashFunc(ctx context.Context) (crypto.Hash, error) sign(ctx context.Context, digest []byte, _ crypto.Hash) ([]byte, error) - verifyRemotely(ctx context.Context, sig, digest []byte) error verify(ctx context.Context, sig, message io.Reader) error - fetchCMK(ctx context.Context) (*cmk, error) - getHashFunc(ctx context.Context) (crypto.Hash, error) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) (err error) fetchKeyMetadata(ctx context.Context) (*types.KeyMetadata, error) fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) } func init() { - kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { + kms.AddProvider(ReferenceScheme, &awsClientOptions{}, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { return LoadSignerVerifier(ctx, ksp) }) } @@ -115,6 +116,54 @@ type awsClient struct { keyID string alias string keyCache *ttlcache.Cache[string, cmk] + options *awsClientOptions +} + +type awsClientOptions struct { + insecureSkipVerify bool +} + +type Option func(*awsClientOptions) + +func (a *awsClientOptions) Init() []registry.Configurer { + return []registry.Configurer{ + registry.BoolConfigOption( + "insecure-skip-verify", + "Skip verification of the server's certificate chain and host name", + false, + func(sp signer.SignerProvider, insecure bool) (signer.SignerProvider, error) { + ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + var clientOpts *awsClientOptions + for _, opt := range ksp.Options { + if clientOpts, ok = opt.(*awsClientOptions); !ok { + continue + } + } + + if clientOpts == nil { + return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + WithInsecureSkipVerify(insecure)(clientOpts) + return ksp, nil + }, + ), + } +} + +func (*awsClientOptions) ProviderName() string { + name := fmt.Sprintf("kms-%s", strings.TrimSuffix(ReferenceScheme, "kms://")) + return name +} + +func WithInsecureSkipVerify(insecure bool) Option { + return func(opts *awsClientOptions) { + opts.insecureSkipVerify = insecure + } } func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, error) { @@ -140,6 +189,16 @@ func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, } func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) (err error) { + clientOpts := &awsClientOptions{} + var ok bool + + for _, opt := range ksp.Options { + clientOpts, ok = opt.(*awsClientOptions) + if !ok { + break + } + } + opts := []func(*config.LoadOptions) error{} if a.endpoint != "" { opts = append(opts, config.WithEndpointResolverWithOptions( @@ -150,7 +209,8 @@ func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) }), )) } - if os.Getenv("AWS_TLS_INSECURE_SKIP_VERIFY") == "1" { + if clientOpts.insecureSkipVerify { + log.Warn("InsecureSkipVerify is enabled for AWS KMS attestor") opts = append(opts, config.WithHTTPClient(&http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // nolint: gosec diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 123a41c0..974df5f5 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -147,7 +147,13 @@ func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { return err } - return a.client.verifyRemotely(ctx, sig, digest) + // not sure if this is a good idea + c, ok := a.client.(*awsClient) + if !ok { + return fmt.Errorf("unable to cast client to awsClient") + } + + return c.verifyRemotely(ctx, sig, digest) } // SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index 2eea4814..8751ef58 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -36,7 +36,8 @@ import ( ) func init() { - kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { + // TODO: Need to setup opts + kms.AddProvider(ReferenceScheme, nil, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { return LoadSignerVerifier(ctx, ksp) }) } diff --git a/signer/kms/signerprovider.go b/signer/kms/signerprovider.go index ce4f5600..7e5b86e9 100644 --- a/signer/kms/signerprovider.go +++ b/signer/kms/signerprovider.go @@ -121,6 +121,12 @@ type KMSSignerProvider struct { Reference string KeyVersion string HashFunc crypto.Hash + Options []KMSClientOptions +} + +type KMSClientOptions interface { + Init() []registry.Configurer + ProviderName() string } type Option func(*KMSSignerProvider) @@ -161,6 +167,14 @@ func New(opts ...Option) *KMSSignerProvider { opt(&ksp) } + for _, opt := range providerOptionsMap { + if opt == nil { + continue + } + + ksp.Options = append(ksp.Options, opt) + } + return &ksp } @@ -171,8 +185,9 @@ func New(opts ...Option) *KMSSignerProvider { type ProviderInit func(context.Context, *KMSSignerProvider) (cryptoutil.Signer, error) // AddProvider adds the provider implementation into the local cache -func AddProvider(keyResourceID string, init ProviderInit) { +func AddProvider(keyResourceID string, opts KMSClientOptions, init ProviderInit) { providersMap[keyResourceID] = init + providerOptionsMap[keyResourceID] = opts } func (ksp *KMSSignerProvider) Signer(ctx context.Context) (cryptoutil.Signer, error) { @@ -202,6 +217,10 @@ func (ksp *KMSSignerProvider) Verifier(ctx context.Context) (cryptoutil.Verifier var providersMap = map[string]ProviderInit{} +var providerOptionsMap = map[string]KMSClientOptions{} + +var providersFlags = map[string][]Option{} + // SupportedProviders returns list of initialized providers func SupportedProviders() []string { keys := make([]string, 0, len(providersMap)) @@ -211,6 +230,10 @@ func SupportedProviders() []string { return keys } +func ProviderOptions() map[string]KMSClientOptions { + return providerOptionsMap +} + // ProviderNotFoundError indicates that no matching KMS provider was found type ProviderNotFoundError struct { ref string From 54b1a510918b82b14ccd24f1c62e1c090d70cb17 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 8 Feb 2024 18:21:57 +0000 Subject: [PATCH 19/27] removing hashivault kms for now (not finished) Signed-off-by: chaosinthecrd --- signer/kms/hashivault/client.go | 341 ------------------------------- signer/kms/hashivault/go.mod | 37 ---- signer/kms/hashivault/go.sum | 96 --------- signer/kms/hashivault/rpcauth.go | 75 ------- signer/kms/hashivault/signer.go | 162 --------------- 5 files changed, 711 deletions(-) delete mode 100644 signer/kms/hashivault/client.go delete mode 100644 signer/kms/hashivault/go.mod delete mode 100644 signer/kms/hashivault/go.sum delete mode 100644 signer/kms/hashivault/rpcauth.go delete mode 100644 signer/kms/hashivault/signer.go diff --git a/signer/kms/hashivault/client.go b/signer/kms/hashivault/client.go deleted file mode 100644 index 28af1eb1..00000000 --- a/signer/kms/hashivault/client.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2023 The Witness Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package hashivault - -import ( - "context" - "crypto" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "os" - "regexp" - "strconv" - "time" - - vault "github.com/hashicorp/vault/api" - "github.com/in-toto/go-witness/cryptoutil" - kms "github.com/in-toto/go-witness/signer/kms" - "github.com/jellydator/ttlcache/v3" -) - -func init() { - kms.AddProvider(ReferenceScheme, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { - return LoadSignerVerifier(ctx, ksp) - }) -} - -type vaultClient struct { - client *vault.Client - keyPath string - transitSecretEnginePath string - keyCache *ttlcache.Cache[string, crypto.PublicKey] - keyVersion uint64 -} - -var ( - errReference = errors.New("kms specification should be in the format hashivault://") - referenceRegex = regexp.MustCompile(`^hashivault://(?P\w(([\w-.]+)?\w)?)$`) - prefixRegex = regexp.MustCompile("^vault:v[0-9]+:") -) - -const ( - vaultV1DataPrefix = "vault:v1:" - - // use a consistent key for cache lookups - cacheKey = "signer" - - // ReferenceScheme schemes for various KMS services are copied from https://github.com/google/go-cloud/tree/master/secrets - ReferenceScheme = "hashivault://" -) - -// ValidReference returns a non-nil error if the reference string is invalid -func ValidReference(ref string) error { - if !referenceRegex.MatchString(ref) { - return errReference - } - return nil -} - -func parseReference(resourceID string) (keyPath string, err error) { - i := referenceRegex.SubexpIndex("path") - v := referenceRegex.FindStringSubmatch(resourceID) - if len(v) < i+1 { - err = fmt.Errorf("invalid vault format %q: %w", resourceID, err) - return - } - keyPath = v[i] - return -} - -func newVaultClient(ctx context.Context, ksp *kms.KMSSignerProvider, opts *RPCAuth) (*vaultClient, error) { - if err := ValidReference(ksp.Reference); err != nil { - return nil, err - } - - keyPath, err := parseReference(ksp.Reference) - if err != nil { - return nil, err - } - - client, err := vault.NewClient(&vault.Config{ - Address: opts.Address, - }) - if err != nil { - return nil, fmt.Errorf("new vault client: %w", err) - } - - client.SetToken(opts.Token) - - var keyVersionUint uint64 - if ksp.KeyVersion != "" { - keyVersionUint, err = strconv.ParseUint(ksp.KeyVersion, 10, 64) - if err != nil { - return nil, fmt.Errorf("parsing key version: %w", err) - } - } - - hvClient := &vaultClient{ - client: client, - keyPath: keyPath, - transitSecretEnginePath: opts.Path, - keyCache: ttlcache.New[string, crypto.PublicKey]( - ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](), - ), - keyVersion: keyVersionUint, - } - - return hvClient, nil -} - -// NOTE: Not quite sure where to integrate this, but keeping it around for now -func oidcLogin(_ context.Context, address, path, role, token string) (string, error) { - if address == "" { - address = os.Getenv("VAULT_ADDR") - } - if address == "" { - return "", errors.New("VAULT_ADDR is not set") - } - if path == "" { - path = "jwt" - } - - client, err := vault.NewClient(&vault.Config{ - Address: address, - }) - if err != nil { - return "", fmt.Errorf("new vault client: %w", err) - } - - loginData := map[string]interface{}{ - "role": role, - "jwt": token, - } - fullpath := fmt.Sprintf("auth/%s/login", path) - resp, err := client.Logical().Write(fullpath, loginData) - if err != nil { - return "", fmt.Errorf("vault oidc login: %w", err) - } - return resp.TokenID() -} - -func (h *vaultClient) fetchPublicKey(_ context.Context) (crypto.PublicKey, error) { - client := h.client.Logical() - - path := fmt.Sprintf("/%s/keys/%s", h.transitSecretEnginePath, h.keyPath) - - keyResult, err := client.Read(path) - if err != nil { - return nil, fmt.Errorf("public key: %w", err) - } - - if keyResult == nil { - return nil, fmt.Errorf("could not read data from transit key path: %s", path) - } - - keysData, hasKeys := keyResult.Data["keys"] - latestVersion, hasVersion := keyResult.Data["latest_version"] - if !hasKeys || !hasVersion { - return nil, errors.New("failed to read transit key keys: corrupted response") - } - - keys, ok := keysData.(map[string]interface{}) - if !ok { - return nil, errors.New("failed to read transit key keys: Invalid keys map") - } - - keyVersion, ok := latestVersion.(json.Number) - if !ok { - return nil, fmt.Errorf("format of 'latest_version' is not json.Number") - } - - keyData, ok := keys[string(keyVersion)] - if !ok { - return nil, errors.New("failed to read transit key keys: corrupted response") - } - - keyMap, ok := keyData.(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("could not parse transit key keys data as map[string]interface{}") - } - - publicKeyPem, ok := keyMap["public_key"] - if !ok { - return nil, errors.New("failed to read transit key keys: corrupted response") - } - - strPublicKeyPem, ok := publicKeyPem.(string) - if !ok { - return nil, fmt.Errorf("could not parse public key pem as string") - } - - return cryptoutil.UnmarshalPEMToPublicKey([]byte(strPublicKeyPem)) -} - -func (h *vaultClient) public() (crypto.PublicKey, error) { - var lerr error - loader := ttlcache.LoaderFunc[string, crypto.PublicKey]( - func(c *ttlcache.Cache[string, crypto.PublicKey], key string) *ttlcache.Item[string, crypto.PublicKey] { - var pubkey crypto.PublicKey - pubkey, lerr = h.fetchPublicKey(context.Background()) - if lerr == nil { - item := c.Set(key, pubkey, 300*time.Second) - return item - } - return nil - }, - ) - - item := h.keyCache.Get(cacheKey, ttlcache.WithLoader[string, crypto.PublicKey](loader)) - if lerr != nil { - return nil, lerr - } - - if item == nil { - return nil, fmt.Errorf("unable to retrieve an item from the cache by the provided key") - } - - return item.Value(), nil -} - -func (h *vaultClient) sign(ctx context.Context, digest []byte, alg crypto.Hash) ([]byte, error) { - client := h.client.Logical() - - keyVersion := fmt.Sprintf("%d", h.keyVersion) - - if keyVersion != "" { - if _, err := strconv.ParseUint(keyVersion, 10, 64); err != nil { - return nil, fmt.Errorf("parsing requested key version: %w", err) - } - } - - signResult, err := client.Write(fmt.Sprintf("/%s/sign/%s%s", h.transitSecretEnginePath, h.keyPath, hashString(alg)), map[string]interface{}{ - "input": base64.StdEncoding.Strict().EncodeToString(digest), - "prehashed": alg != crypto.Hash(0), - "key_version": keyVersion, - }) - if err != nil { - return nil, fmt.Errorf("transit: failed to sign payload: %w", err) - } - - encodedSignature, ok := signResult.Data["signature"] - if !ok { - return nil, errors.New("transit: response corrupted in-transit") - } - - return vaultDecode(encodedSignature, &keyVersion) -} - -func (h vaultClient) verify(sig, digest []byte, alg crypto.Hash) error { - client := h.client.Logical() - encodedSig := base64.StdEncoding.EncodeToString(sig) - - var vaultDataPrefix string - vaultDataPrefix = os.Getenv("VAULT_KEY_PREFIX") - if vaultDataPrefix == "" { - if h.keyVersion > 0 { - vaultDataPrefix = fmt.Sprintf("vault:v%d:", h.keyVersion) - } else { - vaultDataPrefix = vaultV1DataPrefix - } - } - - result, err := client.Write(fmt.Sprintf("/%s/verify/%s/%s", h.transitSecretEnginePath, h.keyPath, hashString(alg)), map[string]interface{}{ - "input": base64.StdEncoding.EncodeToString(digest), - "prehashed": alg != crypto.Hash(0), - "signature": fmt.Sprintf("%s%s", vaultDataPrefix, encodedSig), - }) - if err != nil { - return fmt.Errorf("verify: %w", err) - } - - valid, ok := result.Data["valid"] - if !ok { - return errors.New("corrupted response") - } - - isValid, ok := valid.(bool) - if !ok { - return fmt.Errorf("received non-bool value from 'valid' key") - } - - if !isValid { - return errors.New("failed vault verification") - } - - return nil -} - -// Vault likes to prefix base64 data with a version prefix -func vaultDecode(data interface{}, keyVersionUsed *string) ([]byte, error) { - encoded, ok := data.(string) - if !ok { - return nil, errors.New("received non-string data") - } - - if keyVersionUsed != nil { - *keyVersionUsed = prefixRegex.FindString(encoded) - } - return base64.StdEncoding.DecodeString(prefixRegex.ReplaceAllString(encoded, "")) -} - -func hashString(h crypto.Hash) string { - var hashStr string - switch h { - case crypto.SHA224: - hashStr = "/sha2-224" - case crypto.SHA256: - hashStr = "/sha2-256" - case crypto.SHA384: - hashStr = "/sha2-384" - case crypto.SHA512: - hashStr = "/sha2-512" - default: - hashStr = "" - } - return hashStr -} - -func (h vaultClient) createKey(typeStr string) (crypto.PublicKey, error) { - client := h.client.Logical() - - if _, err := client.Write(fmt.Sprintf("/%s/keys/%s", h.transitSecretEnginePath, h.keyPath), map[string]interface{}{ - "type": typeStr, - }); err != nil { - return nil, fmt.Errorf("failed to create transit key: %w", err) - } - return h.public() -} diff --git a/signer/kms/hashivault/go.mod b/signer/kms/hashivault/go.mod deleted file mode 100644 index d6ec5b14..00000000 --- a/signer/kms/hashivault/go.mod +++ /dev/null @@ -1,37 +0,0 @@ -module github.com/in-toto/go-witness/signer/kms/hashivault - -replace github.com/in-toto/go-witness => ../../../ - -go 1.19 - -require ( - github.com/hashicorp/vault/api v1.9.0 - github.com/in-toto/go-witness v0.0.0-00010101000000-000000000000 - github.com/jellydator/ttlcache/v3 v3.1.1 - github.com/mitchellh/go-homedir v1.1.0 -) - -require ( - github.com/cenkalti/backoff/v3 v3.2.2 // indirect - github.com/go-test/deep v1.1.0 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.1 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect - github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/ryanuber/go-glob v1.0.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sync v0.4.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.2.0 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect -) diff --git a/signer/kms/hashivault/go.sum b/signer/kms/hashivault/go.sum deleted file mode 100644 index 09706982..00000000 --- a/signer/kms/hashivault/go.sum +++ /dev/null @@ -1,96 +0,0 @@ -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= -github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -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/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -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 v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= -github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= -github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= -github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= -github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -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.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= -golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/signer/kms/hashivault/rpcauth.go b/signer/kms/hashivault/rpcauth.go deleted file mode 100644 index 0fb464ce..00000000 --- a/signer/kms/hashivault/rpcauth.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2023 The Witness Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package hashivault - -import ( - "errors" - "fmt" - "log" - "os" - "path/filepath" - - "github.com/mitchellh/go-homedir" -) - -// RPCAuth provides credentials for RPC calls, empty fields are ignored -type RPCAuth struct { - Address string // address is the remote server address, e.g. https://vault:8200 - Path string // path for the RPC, in vault this is the transit path which default to "transit" - Token string // token used for RPC, in vault this is the VAULT_TOKEN value - OIDC RPCAuthOIDC -} - -// RPCAuthOIDC is used to perform the RPC login using OIDC instead of a fixed token -type RPCAuthOIDC struct { - Path string // path defaults to "jwt" for vault - Role string // role is required for jwt logins - Token string // token is a jwt with vault -} - -func initRPCOpts() (*RPCAuth, error) { - opts := &RPCAuth{} - - opts.Address = os.Getenv("VAULT_ADDR") - if opts.Address == "" { - return nil, errors.New("VAULT_ADDR is not set") - } - - opts.Token = os.Getenv("VAULT_TOKEN") - if opts.Token == "" { - log.Printf("VAULT_TOKEN is not set, trying to read token from file at path ~/.vault-token") - homeDir, err := homedir.Dir() - if err != nil { - return nil, fmt.Errorf("get home directory: %w", err) - } - - tokenFromFile, err := os.ReadFile(filepath.Join(homeDir, ".vault-token")) - if err != nil { - return nil, fmt.Errorf("read .vault-token file: %w", err) - } - - opts.Token = string(tokenFromFile) - if opts.Token == "" { - return nil, errors.New("failed to get token from ~/.vault-token") - } - } - - opts.Path = os.Getenv("TRANSIT_SECRET_ENGINE_PATH") - if opts.Path == "" { - opts.Path = "transit" - } - - return opts, nil -} diff --git a/signer/kms/hashivault/signer.go b/signer/kms/hashivault/signer.go deleted file mode 100644 index be3c47fa..00000000 --- a/signer/kms/hashivault/signer.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2023 The Witness Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package hashivault - -import ( - "context" - "crypto" - "fmt" - "io" - - "github.com/in-toto/go-witness/cryptoutil" - "github.com/in-toto/go-witness/log" - kms "github.com/in-toto/go-witness/signer/kms" -) - -// Taken from https://www.vaultproject.io/api/secret/transit -// nolint:revive -const ( - AlgorithmECDSAP256 = "ecdsa-p256" - AlgorithmECDSAP384 = "ecdsa-p384" - AlgorithmECDSAP521 = "ecdsa-p521" - AlgorithmED25519 = "ed25519" - AlgorithmRSA2048 = "rsa-2048" - AlgorithmRSA3072 = "rsa-3072" - AlgorithmRSA4096 = "rsa-4096" -) - -var hvSupportedAlgorithms = []string{ - AlgorithmECDSAP256, - AlgorithmECDSAP384, - AlgorithmECDSAP521, - AlgorithmED25519, - AlgorithmRSA2048, - AlgorithmRSA3072, - AlgorithmRSA4096, -} - -var hvSupportedHashFuncs = []crypto.Hash{ - crypto.SHA224, - crypto.SHA256, - crypto.SHA384, - crypto.SHA512, - crypto.Hash(0), -} - -// SignerVerifier is a cryptoutil.SignerVerifier that uses the AWS Key Management Service -type SignerVerifier struct { - reference string - client *vaultClient - hashFunc crypto.Hash -} - -// LoadSignerVerifier generates signatures using the specified key object in AWS KMS and hash algorithm. -func LoadSignerVerifier(ctx context.Context, ksp *kms.KMSSignerProvider) (*SignerVerifier, error) { - h := &SignerVerifier{ - reference: ksp.Reference, - } - - rpcOpts, err := initRPCOpts() - if err != nil { - return nil, fmt.Errorf("failed to initialize RPC options: %w", err) - } - - h.client, err = newVaultClient(ctx, ksp, rpcOpts) - if err != nil { - return nil, err - } - - for _, hashFunc := range hvSupportedHashFuncs { - if hashFunc == ksp.HashFunc { - h.hashFunc = ksp.HashFunc - } - } - - if h.hashFunc == 0 { - return nil, fmt.Errorf("unsupported hash function: %v", ksp.HashFunc) - } - - return h, nil -} - -// NOTE: This might be all wrong but setting it like so for now -// -// KeyID returns the key identifier for the key used by this signer. -func (h *SignerVerifier) KeyID() (string, error) { - return h.reference, nil -} - -// Sign signs the provided message using GCP KMS. If the message is provided, -// this method will compute the digest according to the hash function specified -// when the Signer was created. -func (h *SignerVerifier) Sign(message io.Reader) ([]byte, error) { - var digest []byte - var err error - ctx := context.Background() - - var signerOpts crypto.SignerOpts - hf := signerOpts.HashFunc() - - digest, _, err = cryptoutil.ComputeDigest(message, hf, hvSupportedHashFuncs) - if err != nil { - return nil, err - } - - return h.client.sign(ctx, digest, hf) -} - -// Verifier returns a cryptoutil.Verifier that can be used to verify signatures created by this signer. -func (h *SignerVerifier) Verifier() (cryptoutil.Verifier, error) { - return h, nil -} - -// PublicKey returns the public key that can be used to verify signatures created by -// this signer. -func (h *SignerVerifier) PublicKey(ctx context.Context) (crypto.PublicKey, error) { - return h.client.public() -} - -// Bytes returns the bytes of the public key that can be used to verify signatures created by the signer. -func (h *SignerVerifier) Bytes() ([]byte, error) { - pub, err := h.client.public() - if err != nil { - return nil, err - } - - return cryptoutil.PublicPemBytes(pub) -} - -// VerifySignature verifies the signature for the given message, returning -// nil if the verification succeeded, and an error message otherwise. -func (h *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { - var digest []byte - hf := h.hashFunc - err = h.client.verify(sig, digest, hf) - if err != nil { - log.Info(err.Error()) - } - - return err -} - -// SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service -func (h *SignerVerifier) SupportedAlgorithms() (result []string) { - return hvSupportedAlgorithms -} - -// DefaultAlgorithm returns the default algorithm for the GCP KMS service -func (h *SignerVerifier) DefaultAlgorithm() string { - return AlgorithmECDSAP256 -} From 363dcc6fcaca1336c5905df672cdba6d3e8dca65 Mon Sep 17 00:00:00 2001 From: John Kjell Date: Thu, 8 Feb 2024 14:46:17 -0600 Subject: [PATCH 20/27] Resolve linter errors Signed-off-by: John Kjell --- .gitignore | 1 + signer/kms/aws/client.go | 8 ++++---- signer/kms/gcp/fakeclient.go | 23 +---------------------- signer/kms/signerprovider.go | 6 ++---- 4 files changed, 8 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index a8e05fde..7aed8053 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ log sarif-report.json test/log .idea/ +profile.cov diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index 4f6b451b..5fc23790 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -116,7 +116,6 @@ type awsClient struct { keyID string alias string keyCache *ttlcache.Cache[string, cmk] - options *awsClientOptions } type awsClientOptions struct { @@ -139,9 +138,11 @@ func (a *awsClientOptions) Init() []registry.Configurer { var clientOpts *awsClientOptions for _, opt := range ksp.Options { - if clientOpts, ok = opt.(*awsClientOptions); !ok { + co, optsOk := opt.(*awsClientOptions) + if !optsOk { continue } + clientOpts = co } if clientOpts == nil { @@ -270,7 +271,6 @@ func (a *awsClient) getCMK(ctx context.Context) (*cmk, error) { return nil, lerr } -// At the moment this function lies unused, but it is here for future if necessary func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { cmk, err := a.getCMK(ctx) if err != nil { @@ -374,5 +374,5 @@ func (c *cmk) HashFunc() crypto.Hash { } func (c *cmk) Verifier() (cryptoutil.Verifier, error) { - return c.Verifier() + return cryptoutil.NewVerifier(c.PublicKey, cryptoutil.VerifyWithHash(c.HashFunc())) } diff --git a/signer/kms/gcp/fakeclient.go b/signer/kms/gcp/fakeclient.go index 1d87f942..cf0c9457 100644 --- a/signer/kms/gcp/fakeclient.go +++ b/signer/kms/gcp/fakeclient.go @@ -69,10 +69,6 @@ func newFakeGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*fakeGCP return nil, err } - if ctx == nil { - ctx = context.Background() - } - g := &fakeGCPClient{ kvCache: nil, } @@ -189,14 +185,6 @@ func (g *fakeGCPClient) fetchPublicKey(ctx context.Context, name string) (crypto return pub, nil } -func (g *fakeGCPClient) getHashFunc() (crypto.Hash, error) { - ckv, err := g.getCKV() - if err != nil { - return 0, err - } - return ckv.HashFunc, nil -} - // getCKV gets the latest CryptoKeyVersion from the client's cache, which may trigger an actual // call to GCP if the existing entry in the cache has expired. func (g *fakeGCPClient) getCKV() (*cryptoKeyVersion, error) { @@ -237,17 +225,8 @@ func (g *fakeGCPClient) sign(ctx context.Context, digest []byte, alg crypto.Hash } reader := bytes.NewReader(digest) - sig, err := g.signer.Sign(reader) - return sig, nil -} - -func (g *fakeGCPClient) public(ctx context.Context) (crypto.PublicKey, error) { - crv, err := g.getCKV() - if err != nil { - return nil, fmt.Errorf("transient error getting info from KMS: %w", err) - } - return crv.PublicKey, nil + return g.signer.Sign(reader) } // Seems like GCP doesn't support any remote verification, so we'll just use the local verifier diff --git a/signer/kms/signerprovider.go b/signer/kms/signerprovider.go index 7e5b86e9..321a4711 100644 --- a/signer/kms/signerprovider.go +++ b/signer/kms/signerprovider.go @@ -44,7 +44,7 @@ func init() { registry.StringConfigOption( "hashType", "The hash type to use for signing", - "", + "sha256", func(sp signer.SignerProvider, hash string) (signer.SignerProvider, error) { ksp, ok := sp.(*KMSSignerProvider) if !ok { @@ -89,7 +89,7 @@ func init() { registry.StringConfigOption( "hashType", "The hash type used for verifying", - "", + "sha256", func(sp signer.VerifierProvider, hash string) (signer.VerifierProvider, error) { ksp, ok := sp.(*KMSSignerProvider) if !ok { @@ -219,8 +219,6 @@ var providersMap = map[string]ProviderInit{} var providerOptionsMap = map[string]KMSClientOptions{} -var providersFlags = map[string][]Option{} - // SupportedProviders returns list of initialized providers func SupportedProviders() []string { keys := make([]string, 0, len(providersMap)) From 4f8cd73356cf5fca92af7f90e1403e42d3627d26 Mon Sep 17 00:00:00 2001 From: John Kjell Date: Thu, 8 Feb 2024 14:48:35 -0600 Subject: [PATCH 21/27] Remove unused function Signed-off-by: John Kjell --- signer/kms/aws/fakeclient.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/signer/kms/aws/fakeclient.go b/signer/kms/aws/fakeclient.go index 00d99837..6193bbcc 100644 --- a/signer/kms/aws/fakeclient.go +++ b/signer/kms/aws/fakeclient.go @@ -96,14 +96,6 @@ func (a *fakeAWSClient) fetchCMK(ctx context.Context) (*cmk, error) { return cmk, nil } -func (a *fakeAWSClient) getHashFunc(ctx context.Context) (crypto.Hash, error) { - cmk, err := a.getCMK(ctx) - if err != nil { - return 0, err - } - return cmk.HashFunc(), nil -} - func (a *fakeAWSClient) getCMK(ctx context.Context) (*cmk, error) { var lerr error loader := ttlcache.LoaderFunc[string, cmk]( From 539f8766b418e971b1a9c1f105c5f7c88e118f74 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Mon, 12 Feb 2024 17:30:05 +0000 Subject: [PATCH 22/27] added all the obvious options for aws and gcp kms Signed-off-by: chaosinthecrd --- signer/kms/aws/client.go | 179 +++++++++++++++++++++++++++++++++++++-- signer/kms/aws/signer.go | 30 +------ signer/kms/gcp/client.go | 77 ++++++++++++++++- 3 files changed, 244 insertions(+), 42 deletions(-) diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index 5fc23790..dcd2bef8 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -116,16 +116,48 @@ type awsClient struct { keyID string alias string keyCache *ttlcache.Cache[string, cmk] + options *awsClientOptions } type awsClientOptions struct { insecureSkipVerify bool + credentialsFile string + configFile string + profile string + verifyRemotely bool } type Option func(*awsClientOptions) func (a *awsClientOptions) Init() []registry.Configurer { return []registry.Configurer{ + registry.BoolConfigOption( + "remote-verify", + "verify signature using AWS KMS remote verification. If false, the public key will be pulled from AWS KMS and verification will take place locally", + true, + func(sp signer.SignerProvider, insecure bool) (signer.SignerProvider, error) { + ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + var clientOpts *awsClientOptions + for _, opt := range ksp.Options { + co, optsOk := opt.(*awsClientOptions) + if !optsOk { + continue + } + clientOpts = co + } + + if clientOpts == nil { + return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + WithInsecureSkipVerify(insecure)(clientOpts) + return ksp, nil + }, + ), registry.BoolConfigOption( "insecure-skip-verify", "Skip verification of the server's certificate chain and host name", @@ -153,6 +185,87 @@ func (a *awsClientOptions) Init() []registry.Configurer { return ksp, nil }, ), + registry.StringConfigOption( + "credentials-file", + "The shared credentials file to use with the AWS KMS signer provider", + "", + func(sp signer.SignerProvider, cred string) (signer.SignerProvider, error) { + ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + var clientOpts *awsClientOptions + for _, opt := range ksp.Options { + co, optsOk := opt.(*awsClientOptions) + if !optsOk { + continue + } + clientOpts = co + } + + if clientOpts == nil { + return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + WithCredentialsFile(cred)(clientOpts) + return ksp, nil + }, + ), + registry.StringConfigOption( + "config-file", + "The shared configuration file to use with the AWS KMS signer provider", + "", + func(sp signer.SignerProvider, config string) (signer.SignerProvider, error) { + ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + var clientOpts *awsClientOptions + for _, opt := range ksp.Options { + co, optsOk := opt.(*awsClientOptions) + if !optsOk { + continue + } + clientOpts = co + } + + if clientOpts == nil { + return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + WithConfigFile(config)(clientOpts) + return ksp, nil + }, + ), + registry.StringConfigOption( + "profile", + "The shared configuration profile to use with the AWS KMS signer provider", + "", + func(sp signer.SignerProvider, profile string) (signer.SignerProvider, error) { + ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + var clientOpts *awsClientOptions + for _, opt := range ksp.Options { + co, optsOk := opt.(*awsClientOptions) + if !optsOk { + continue + } + clientOpts = co + } + + if clientOpts == nil { + return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + WithConfigFile(profile)(clientOpts) + return ksp, nil + }, + ), } } @@ -167,6 +280,24 @@ func WithInsecureSkipVerify(insecure bool) Option { } } +func WithCredentialsFile(cred string) Option { + return func(opts *awsClientOptions) { + opts.credentialsFile = cred + } +} + +func WithConfigFile(config string) Option { + return func(opts *awsClientOptions) { + opts.credentialsFile = config + } +} + +func WithProfile(profile string) Option { + return func(opts *awsClientOptions) { + opts.profile = profile + } +} + func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, error) { if err := ValidReference(ksp.Reference); err != nil { return nil, err @@ -190,16 +321,21 @@ func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, } func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) (err error) { - clientOpts := &awsClientOptions{} + var co *awsClientOptions var ok bool - for _, opt := range ksp.Options { - clientOpts, ok = opt.(*awsClientOptions) + co, ok = opt.(*awsClientOptions) if !ok { - break + continue } } + if co == nil { + return fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + a.options = co + opts := []func(*config.LoadOptions) error{} if a.endpoint != "" { opts = append(opts, config.WithEndpointResolverWithOptions( @@ -210,7 +346,8 @@ func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) }), )) } - if clientOpts.insecureSkipVerify { + + if a.options.insecureSkipVerify { log.Warn("InsecureSkipVerify is enabled for AWS KMS attestor") opts = append(opts, config.WithHTTPClient(&http.Client{ Transport: &http.Transport{ @@ -219,6 +356,18 @@ func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) })) } + if a.options.credentialsFile != "" { + opts = append(opts, config.WithSharedCredentialsFiles([]string{a.options.credentialsFile})) + } + + if a.options.configFile != "" { + opts = append(opts, config.WithSharedConfigFiles([]string{a.options.configFile})) + } + + if a.options.profile != "" { + opts = append(opts, config.WithSharedConfigProfile(a.options.profile)) + } + cfg, err := config.LoadDefaultConfig(ctx, opts...) if err != nil { return fmt.Errorf("loading AWS config: %w", err) @@ -272,17 +421,23 @@ func (a *awsClient) getCMK(ctx context.Context) (*cmk, error) { } func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { - cmk, err := a.getCMK(ctx) + s, err := io.ReadAll(sig) if err != nil { return err } - verifier, err := cmk.Verifier() + if a.options.verifyRemotely { + return a.verifyRemotely(ctx, s, message) + } + + log.Debug("Verifying signature with AWS KMS locally") + + cmk, err := a.getCMK(ctx) if err != nil { return err } - s, err := io.ReadAll(sig) + verifier, err := cmk.Verifier() if err != nil { return err } @@ -290,12 +445,18 @@ func (a *awsClient) verify(ctx context.Context, sig, message io.Reader) error { return verifier.Verify(message, s) } -func (a *awsClient) verifyRemotely(ctx context.Context, sig, digest []byte) error { +func (a *awsClient) verifyRemotely(ctx context.Context, sig []byte, message io.Reader) error { cmk, err := a.getCMK(ctx) if err != nil { return err } + // if we verify remotely, we need to compute the digest first + digest, _, err := cryptoutil.ComputeDigest(message, cmk.HashFunc(), awsSupportedHashFuncs) + if err != nil { + return err + } + alg := cmk.KeyMetadata.SigningAlgorithms[0] messageType := types.MessageTypeDigest if _, err := a.client.Verify(ctx, &akms.VerifyInput{ diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 974df5f5..755f1a50 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -20,11 +20,9 @@ import ( "crypto" "fmt" "io" - "os" "github.com/aws/aws-sdk-go-v2/service/kms/types" "github.com/in-toto/go-witness/cryptoutil" - "github.com/in-toto/go-witness/log" kms "github.com/in-toto/go-witness/signer/kms" ) @@ -126,34 +124,8 @@ func (a *SignerVerifier) Bytes() ([]byte, error) { // nil if the verification succeeded, and an error message otherwise. func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { ctx := context.Background() - var digest []byte - - var signerOpts crypto.SignerOpts - signerOpts, err = a.client.getHashFunc(ctx) - if err != nil { - return fmt.Errorf("getting hash func: %w", err) - } - hf := signerOpts.HashFunc() - - // we want to verify remotely unless we explicitly ask to verify locally - if os.Getenv("WITNESS_AWS_VERIFY_LOCALLY") == "1" { - log.Debug("Environment variable WITNESS_AWS_VERIFY_LOCALLY set to 1, verifying locally") - return a.client.verify(ctx, bytes.NewReader(sig), message) - } - - // if we verify remotely, we need to compute the digest first - digest, _, err = cryptoutil.ComputeDigest(message, hf, awsSupportedHashFuncs) - if err != nil { - return err - } - - // not sure if this is a good idea - c, ok := a.client.(*awsClient) - if !ok { - return fmt.Errorf("unable to cast client to awsClient") - } - return c.verifyRemotely(ctx, sig, digest) + return a.client.verify(ctx, bytes.NewReader(sig), message) } // SupportedAlgorithms returns the list of algorithms supported by the AWS KMS service diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index 8751ef58..24dd2b06 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -24,20 +24,23 @@ import ( "hash/crc32" "io" "regexp" + "strings" "time" gcpkms "cloud.google.com/go/kms/apiv1" "cloud.google.com/go/kms/apiv1/kmspb" + "google.golang.org/api/option" "google.golang.org/protobuf/types/known/wrapperspb" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/registry" + "github.com/in-toto/go-witness/signer" "github.com/in-toto/go-witness/signer/kms" "github.com/jellydator/ttlcache/v3" ) func init() { - // TODO: Need to setup opts - kms.AddProvider(ReferenceScheme, nil, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { + kms.AddProvider(ReferenceScheme, &gcpClientOptions{}, func(ctx context.Context, ksp *kms.KMSSignerProvider) (cryptoutil.Signer, error) { return LoadSignerVerifier(ctx, ksp) }) } @@ -104,6 +107,56 @@ type gcpClient struct { version string kvCache *ttlcache.Cache[string, cryptoKeyVersion] client *gcpkms.KeyManagementClient + options *gcpClientOptions +} + +type gcpClientOptions struct { + credentialsFile string +} + +type Option func(*gcpClientOptions) + +func (a *gcpClientOptions) Init() []registry.Configurer { + return []registry.Configurer{ + registry.StringConfigOption( + "credentials-file", + "The credentials file to use with the GCP KMS signer provider", + "", + func(sp signer.SignerProvider, cred string) (signer.SignerProvider, error) { + ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a kms signer provider") + } + + var clientOpts *gcpClientOptions + for _, opt := range ksp.Options { + co, optsOk := opt.(*gcpClientOptions) + if !optsOk { + continue + } + clientOpts = co + } + + if clientOpts == nil { + return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + } + + WithCredentialsFile(cred)(clientOpts) + return ksp, nil + }, + ), + } +} + +func (*gcpClientOptions) ProviderName() string { + name := fmt.Sprintf("kms-%s", strings.TrimSuffix(ReferenceScheme, "kms://")) + return name +} + +func WithCredentialsFile(cred string) Option { + return func(opts *gcpClientOptions) { + opts.credentialsFile = cred + } } func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, error) { @@ -125,8 +178,24 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, return nil, err } - // NOTE: We need to think about how we want to handle passing in options here - g.client, err = gcpkms.NewKeyManagementClient(ctx) + var co *gcpClientOptions + var ok bool + for _, opt := range ksp.Options { + co, ok = opt.(*gcpClientOptions) + if !ok { + continue + } + } + if co == nil { + return nil, fmt.Errorf("unable to find gcp client options in gcp kms signer provider") + } + + var opts []option.ClientOption + if co.credentialsFile != "" { + opts = append(opts, option.WithCredentialsFile(co.credentialsFile)) + } + + g.client, err = gcpkms.NewKeyManagementClient(ctx, opts...) if err != nil { return nil, fmt.Errorf("new gcp kms client: %w", err) } From 07575d1949042df9ed1aa848360714e35b4c9233 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Mon, 12 Feb 2024 18:21:45 +0000 Subject: [PATCH 23/27] fixing some linting errors Signed-off-by: chaosinthecrd --- signer/kms/aws/client.go | 7 ++----- signer/kms/gcp/client.go | 9 ++++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index dcd2bef8..a586ba29 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -321,21 +321,18 @@ func newAWSClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*awsClient, } func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) (err error) { - var co *awsClientOptions var ok bool for _, opt := range ksp.Options { - co, ok = opt.(*awsClientOptions) + a.options, ok = opt.(*awsClientOptions) if !ok { continue } } - if co == nil { + if a.options == nil { return fmt.Errorf("unable to find aws client options in aws kms signer provider") } - a.options = co - opts := []func(*config.LoadOptions) error{} if a.endpoint != "" { opts = append(opts, config.WithEndpointResolverWithOptions( diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index 24dd2b06..00040917 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -178,21 +178,20 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, return nil, err } - var co *gcpClientOptions var ok bool for _, opt := range ksp.Options { - co, ok = opt.(*gcpClientOptions) + g.options, ok = opt.(*gcpClientOptions) if !ok { continue } } - if co == nil { + if g.options == nil { return nil, fmt.Errorf("unable to find gcp client options in gcp kms signer provider") } var opts []option.ClientOption - if co.credentialsFile != "" { - opts = append(opts, option.WithCredentialsFile(co.credentialsFile)) + if g.options.credentialsFile != "" { + opts = append(opts, option.WithCredentialsFile(g.options.credentialsFile)) } g.client, err = gcpkms.NewKeyManagementClient(ctx, opts...) From fd9e21b31989b46d83719ff4f890328c17f8d00e Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 13 Feb 2024 14:12:16 +0000 Subject: [PATCH 24/27] some refactors made in the quest of folding out a bug Signed-off-by: chaosinthecrd --- go.mod | 1 + go.sum | 2 + signer/kms/aws/client.go | 134 +++++++++++++++-------------------- signer/kms/gcp/client.go | 5 +- signer/kms/signerprovider.go | 5 +- 5 files changed, 67 insertions(+), 80 deletions(-) diff --git a/go.mod b/go.mod index 238d6852..3b0672df 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect diff --git a/go.sum b/go.sum index 670806e9..194cfd3f 100644 --- a/go.sum +++ b/go.sum @@ -242,6 +242,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/signer/kms/aws/client.go b/signer/kms/aws/client.go index a586ba29..f67ac5ec 100644 --- a/signer/kms/aws/client.go +++ b/signer/kms/aws/client.go @@ -37,6 +37,7 @@ import ( "github.com/in-toto/go-witness/signer" "github.com/in-toto/go-witness/signer/kms" ttlcache "github.com/jellydator/ttlcache/v3" + "github.com/mitchellh/go-homedir" ) type client interface { @@ -73,14 +74,15 @@ var ( // Alias name with endpoint: awskms://localhost:4566/alias/ExampleAlias // Alias ARN: awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias // Alias ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias - uuidRE = `m?r?k?-?[A-Fa-f0-9]{8}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{12}` - arnRE = `arn:(?:aws|aws-us-gov|aws-cn):kms:[a-z0-9-]+:\d{12}:` - hostRE = `([^/]*)/` - keyIDRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + uuidRE + `)$`) - keyARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `key/` + uuidRE + `)$`) - aliasNameRE = regexp.MustCompile(`^awskms://` + hostRE + `((alias/.*))$`) - aliasARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `(alias/.*))$`) - allREs = []*regexp.Regexp{keyIDRE, keyARNRE, aliasNameRE, aliasARNRE} + uuidRE = `m?r?k?-?[A-Fa-f0-9]{8}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{12}` + arnRE = `arn:(?:aws|aws-us-gov|aws-cn):kms:[a-z0-9-]+:\d{12}:` + hostRE = `([^/]*)/` + keyIDRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + uuidRE + `)$`) + keyARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `key/` + uuidRE + `)$`) + aliasNameRE = regexp.MustCompile(`^awskms://` + hostRE + `((alias/.*))$`) + aliasARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `(alias/.*))$`) + allREs = []*regexp.Regexp{keyIDRE, keyARNRE, aliasNameRE, aliasARNRE} + providerName = fmt.Sprintf("kms-%s", strings.TrimSuffix(ReferenceScheme, "kms://")) ) // ValidReference returns a non-nil error if the reference string is invalid @@ -135,26 +137,18 @@ func (a *awsClientOptions) Init() []registry.Configurer { "remote-verify", "verify signature using AWS KMS remote verification. If false, the public key will be pulled from AWS KMS and verification will take place locally", true, - func(sp signer.SignerProvider, insecure bool) (signer.SignerProvider, error) { + func(sp signer.SignerProvider, verify bool) (signer.SignerProvider, error) { ksp, ok := sp.(*kms.KMSSignerProvider) if !ok { return sp, fmt.Errorf("provided signer provider is not a kms signer provider") } - var clientOpts *awsClientOptions - for _, opt := range ksp.Options { - co, optsOk := opt.(*awsClientOptions) - if !optsOk { - continue - } - clientOpts = co - } - - if clientOpts == nil { - return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + co, ok := ksp.Options[providerName].(*awsClientOptions) + if !ok { + return sp, fmt.Errorf("failed to get aws client options from aws kms signer provider") } - WithInsecureSkipVerify(insecure)(clientOpts) + WithRemoteVerify(verify)(co) return ksp, nil }, ), @@ -168,20 +162,12 @@ func (a *awsClientOptions) Init() []registry.Configurer { return sp, fmt.Errorf("provided signer provider is not a kms signer provider") } - var clientOpts *awsClientOptions - for _, opt := range ksp.Options { - co, optsOk := opt.(*awsClientOptions) - if !optsOk { - continue - } - clientOpts = co - } - - if clientOpts == nil { - return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + co, ok := ksp.Options[providerName].(*awsClientOptions) + if !ok { + return sp, fmt.Errorf("failed to get aws client options from aws kms signer provider") } - WithInsecureSkipVerify(insecure)(clientOpts) + WithInsecureSkipVerify(insecure)(co) return ksp, nil }, ), @@ -195,20 +181,12 @@ func (a *awsClientOptions) Init() []registry.Configurer { return sp, fmt.Errorf("provided signer provider is not a kms signer provider") } - var clientOpts *awsClientOptions - for _, opt := range ksp.Options { - co, optsOk := opt.(*awsClientOptions) - if !optsOk { - continue - } - clientOpts = co - } - - if clientOpts == nil { - return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + co, ok := ksp.Options[providerName].(*awsClientOptions) + if !ok { + return sp, fmt.Errorf("failed to get aws client options from aws kms signer provider") } - WithCredentialsFile(cred)(clientOpts) + WithCredentialsFile(cred)(co) return ksp, nil }, ), @@ -218,24 +196,17 @@ func (a *awsClientOptions) Init() []registry.Configurer { "", func(sp signer.SignerProvider, config string) (signer.SignerProvider, error) { ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { return sp, fmt.Errorf("provided signer provider is not a kms signer provider") } - var clientOpts *awsClientOptions - for _, opt := range ksp.Options { - co, optsOk := opt.(*awsClientOptions) - if !optsOk { - continue - } - clientOpts = co - } - - if clientOpts == nil { - return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + co, ok := ksp.Options[providerName].(*awsClientOptions) + if !ok { + return sp, fmt.Errorf("failed to get aws client options from aws kms signer provider") } - WithConfigFile(config)(clientOpts) + WithConfigFile(config)(co) return ksp, nil }, ), @@ -245,24 +216,17 @@ func (a *awsClientOptions) Init() []registry.Configurer { "", func(sp signer.SignerProvider, profile string) (signer.SignerProvider, error) { ksp, ok := sp.(*kms.KMSSignerProvider) + if !ok { return sp, fmt.Errorf("provided signer provider is not a kms signer provider") } - var clientOpts *awsClientOptions - for _, opt := range ksp.Options { - co, optsOk := opt.(*awsClientOptions) - if !optsOk { - continue - } - clientOpts = co - } - - if clientOpts == nil { - return nil, fmt.Errorf("unable to find aws client options in aws kms signer provider") + co, ok := ksp.Options[providerName].(*awsClientOptions) + if !ok { + return sp, fmt.Errorf("failed to get aws client options from aws kms signer provider") } - WithConfigFile(profile)(clientOpts) + WithProfile(profile)(co) return ksp, nil }, ), @@ -270,8 +234,7 @@ func (a *awsClientOptions) Init() []registry.Configurer { } func (*awsClientOptions) ProviderName() string { - name := fmt.Sprintf("kms-%s", strings.TrimSuffix(ReferenceScheme, "kms://")) - return name + return providerName } func WithInsecureSkipVerify(insecure bool) Option { @@ -280,6 +243,12 @@ func WithInsecureSkipVerify(insecure bool) Option { } } +func WithRemoteVerify(remote bool) Option { + return func(opts *awsClientOptions) { + opts.verifyRemotely = remote + } +} + func WithCredentialsFile(cred string) Option { return func(opts *awsClientOptions) { opts.credentialsFile = cred @@ -288,7 +257,7 @@ func WithCredentialsFile(cred string) Option { func WithConfigFile(config string) Option { return func(opts *awsClientOptions) { - opts.credentialsFile = config + opts.configFile = config } } @@ -324,8 +293,8 @@ func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) var ok bool for _, opt := range ksp.Options { a.options, ok = opt.(*awsClientOptions) - if !ok { - continue + if ok { + break } } @@ -354,14 +323,27 @@ func (a *awsClient) setupClient(ctx context.Context, ksp *kms.KMSSignerProvider) } if a.options.credentialsFile != "" { - opts = append(opts, config.WithSharedCredentialsFiles([]string{a.options.credentialsFile})) + f, err := homedir.Expand(a.options.credentialsFile) + if err != nil { + return fmt.Errorf("expanding credentials file to full path: %w", err) + } + + log.Debug("Using file ", f, " as credentials file for AWS KMS provider") + opts = append(opts, config.WithSharedCredentialsFiles([]string{f})) } if a.options.configFile != "" { - opts = append(opts, config.WithSharedConfigFiles([]string{a.options.configFile})) + f, err := homedir.Expand(a.options.configFile) + if err != nil { + return fmt.Errorf("expanding credentials file to full path: %w", err) + } + + log.Debug("Using file ", f, " as config file for AWS KMS provider") + opts = append(opts, config.WithSharedConfigFiles([]string{f})) } if a.options.profile != "" { + log.Debug("using profile ", a.options.profile, " for AWS KMS provider") opts = append(opts, config.WithSharedConfigProfile(a.options.profile)) } diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index 00040917..f8171c92 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -181,10 +181,11 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, var ok bool for _, opt := range ksp.Options { g.options, ok = opt.(*gcpClientOptions) - if !ok { - continue + if ok { + break } } + if g.options == nil { return nil, fmt.Errorf("unable to find gcp client options in gcp kms signer provider") } diff --git a/signer/kms/signerprovider.go b/signer/kms/signerprovider.go index 321a4711..4166b65f 100644 --- a/signer/kms/signerprovider.go +++ b/signer/kms/signerprovider.go @@ -121,7 +121,7 @@ type KMSSignerProvider struct { Reference string KeyVersion string HashFunc crypto.Hash - Options []KMSClientOptions + Options map[string]KMSClientOptions } type KMSClientOptions interface { @@ -167,12 +167,13 @@ func New(opts ...Option) *KMSSignerProvider { opt(&ksp) } + ksp.Options = make(map[string]KMSClientOptions) for _, opt := range providerOptionsMap { if opt == nil { continue } - ksp.Options = append(ksp.Options, opt) + ksp.Options[opt.ProviderName()] = opt } return &ksp From 1680e8c82f5007eeef4b703c6ca5c3c767f5ed97 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Tue, 13 Feb 2024 16:50:11 +0000 Subject: [PATCH 25/27] making final changes for PR Signed-off-by: chaosinthecrd --- signer/kms/aws/signer.go | 6 ++--- signer/kms/gcp/client.go | 58 +++++++++------------------------------- 2 files changed, 15 insertions(+), 49 deletions(-) diff --git a/signer/kms/aws/signer.go b/signer/kms/aws/signer.go index 755f1a50..937a23ea 100644 --- a/signer/kms/aws/signer.go +++ b/signer/kms/aws/signer.go @@ -85,7 +85,7 @@ func (a *SignerVerifier) KeyID() (string, error) { // when the Signer was created. func (a *SignerVerifier) Sign(message io.Reader) ([]byte, error) { var err error - ctx := context.Background() + ctx := context.TODO() var digest []byte var signerOpts crypto.SignerOpts @@ -111,7 +111,7 @@ func (a *SignerVerifier) Verifier() (cryptoutil.Verifier, error) { // Bytes returns the bytes of the public key that can be used to verify signatures created by the signer. func (a *SignerVerifier) Bytes() ([]byte, error) { - ctx := context.Background() + ctx := context.TODO() p, err := a.client.fetchPublicKey(ctx) if err != nil { return nil, err @@ -123,7 +123,7 @@ func (a *SignerVerifier) Bytes() ([]byte, error) { // Verify verifies the signature for the given message, returning // nil if the verification succeeded, and an error message otherwise. func (a *SignerVerifier) Verify(message io.Reader, sig []byte) (err error) { - ctx := context.Background() + ctx := context.TODO() return a.client.verify(ctx, bytes.NewReader(sig), message) } diff --git a/signer/kms/gcp/client.go b/signer/kms/gcp/client.go index f8171c92..1d797067 100644 --- a/signer/kms/gcp/client.go +++ b/signer/kms/gcp/client.go @@ -17,8 +17,6 @@ package gcp import ( "context" "crypto" - "crypto/ecdsa" - "crypto/rsa" "errors" "fmt" "hash/crc32" @@ -165,7 +163,7 @@ func newGCPClient(ctx context.Context, ksp *kms.KMSSignerProvider) (*gcpClient, } if ctx == nil { - ctx = context.Background() + ctx = context.TODO() } g := &gcpClient{ @@ -279,61 +277,29 @@ func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, erro PublicKey: pubKey, } - // crv.Verifier is set here to enable storing the public key & hash algorithm together, - // as well as using the in memory Verifier to perform the verify operations. switch kv.Algorithm { - case kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256: - pub, ok := pubKey.(*ecdsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - crv.Verifier = cryptoutil.NewECDSAVerifier(pub, crypto.SHA256) - crv.HashFunc = crypto.SHA256 - case kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384: - pub, ok := pubKey.(*ecdsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - crv.Verifier = cryptoutil.NewECDSAVerifier(pub, crypto.SHA384) - crv.HashFunc = crypto.SHA384 case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256, kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256, + kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256, kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256: - pub, ok := pubKey.(*rsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA256) crv.HashFunc = crypto.SHA256 - case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512: - pub, ok := pubKey.(*rsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA384) + case kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384: crv.HashFunc = crypto.SHA384 - case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256, - kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, - kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256: - pub, ok := pubKey.(*rsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA256) - crv.HashFunc = crypto.SHA256 - case kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512: - pub, ok := pubKey.(*rsa.PublicKey) - if !ok { - return nil, fmt.Errorf("public key is not rsa") - } - crv.Verifier = cryptoutil.NewRSAVerifier(pub, crypto.SHA512) + case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512, + kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512: crv.HashFunc = crypto.SHA512 default: return nil, errors.New("unknown algorithm specified by KMS") } + + crv.Verifier, err = cryptoutil.NewVerifier(pubKey, cryptoutil.VerifyWithHash(crv.HashFunc)) if err != nil { return nil, fmt.Errorf("initializing internal verifier: %w", err) } + return &crv, nil } @@ -371,7 +337,7 @@ func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) { } else { ttl = time.Second * 300 } - data, lerr = g.keyVersionName(context.Background()) + data, lerr = g.keyVersionName(context.TODO()) if lerr == nil { return c.Set(key, *data, ttl) } From 2d7d9f86b5c31046b30eb60b2932b19287161fc3 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 15 Feb 2024 16:47:13 +0000 Subject: [PATCH 26/27] added public key to parse function Signed-off-by: chaosinthecrd --- cryptoutil/util.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cryptoutil/util.go b/cryptoutil/util.go index 2b96280b..d8dbe67b 100644 --- a/cryptoutil/util.go +++ b/cryptoutil/util.go @@ -148,6 +148,16 @@ func TryParsePEMBlock(block *pem.Block) (interface{}, error) { return key, err } + key, err = x509.ParsePKIXPublicKey(block.Bytes) + if err == nil { + return key, err + } + + key, err = x509.ParsePKCS1PublicKey(block.Bytes) + if err == nil { + return key, err + } + return nil, ErrUnsupportedPEM{block.Type} } From 758242ed1dc6e8eb7c7254297753785245c363ae Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 15 Feb 2024 16:50:32 +0000 Subject: [PATCH 27/27] removing them again haha Signed-off-by: chaosinthecrd --- cryptoutil/util.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cryptoutil/util.go b/cryptoutil/util.go index d8dbe67b..2b96280b 100644 --- a/cryptoutil/util.go +++ b/cryptoutil/util.go @@ -148,16 +148,6 @@ func TryParsePEMBlock(block *pem.Block) (interface{}, error) { return key, err } - key, err = x509.ParsePKIXPublicKey(block.Bytes) - if err == nil { - return key, err - } - - key, err = x509.ParsePKCS1PublicKey(block.Bytes) - if err == nil { - return key, err - } - return nil, ErrUnsupportedPEM{block.Type} }