summaryrefslogtreecommitdiffstats
path: root/pkg/signature/kms/gcp/signer.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/signature/kms/gcp/signer.go')
-rw-r--r--pkg/signature/kms/gcp/signer.go195
1 files changed, 195 insertions, 0 deletions
diff --git a/pkg/signature/kms/gcp/signer.go b/pkg/signature/kms/gcp/signer.go
new file mode 100644
index 0000000..445f9d9
--- /dev/null
+++ b/pkg/signature/kms/gcp/signer.go
@@ -0,0 +1,195 @@
+//
+// Copyright 2021 The Sigstore Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package gcp
+
+import (
+ "context"
+ "crypto"
+ "fmt"
+ "hash/crc32"
+ "io"
+
+ "github.com/sigstore/sigstore/pkg/signature"
+ "github.com/sigstore/sigstore/pkg/signature/options"
+ "google.golang.org/api/option"
+)
+
+var gcpSupportedHashFuncs = []crypto.Hash{
+ crypto.SHA256,
+ crypto.SHA512,
+ crypto.SHA384,
+}
+
+// SignerVerifier creates and verifies digital signatures over a message using GCP KMS service
+type SignerVerifier struct {
+ defaultCtx context.Context
+ client *gcpClient
+}
+
+// LoadSignerVerifier generates signatures using the specified key object in GCP KMS and hash algorithm.
+//
+// It also can verify signatures locally using the public key. hashFunc must not be crypto.Hash(0).
+func LoadSignerVerifier(defaultCtx context.Context, referenceStr string, opts ...option.ClientOption) (*SignerVerifier, error) {
+ g := &SignerVerifier{
+ defaultCtx: defaultCtx,
+ }
+
+ var err error
+ g.client, err = newGCPClient(defaultCtx, referenceStr, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ return g, nil
+}
+
+// SignMessage signs the provided message using GCP KMS. If the message is provided,
+// this method will compute the digest according to the hash function specified
+// when the Signer was created.
+//
+// SignMessage recognizes the following Options listed in order of preference:
+//
+// - WithContext()
+//
+// - WithDigest()
+//
+// - WithCryptoSignerOpts()
+//
+// All other options are ignored if specified.
+func (g *SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) {
+ ctx := context.Background()
+ var digest []byte
+ var signerOpts crypto.SignerOpts
+ var err error
+
+ signerOpts, err = g.client.getHashFunc()
+ if err != nil {
+ return nil, fmt.Errorf("getting fetching default hash function: %w", err)
+ }
+
+ for _, opt := range opts {
+ opt.ApplyContext(&ctx)
+ opt.ApplyDigest(&digest)
+ opt.ApplyCryptoSignerOpts(&signerOpts)
+ }
+
+ digest, hf, err := signature.ComputeDigestForSigning(message, signerOpts.HashFunc(), gcpSupportedHashFuncs, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ crc32cHasher := crc32.New(crc32.MakeTable(crc32.Castagnoli))
+ _, err = crc32cHasher.Write(digest)
+ if err != nil {
+ return nil, err
+ }
+
+ return g.client.sign(ctx, digest, hf, crc32cHasher.Sum32())
+}
+
+// PublicKey returns the public key that can be used to verify signatures created by
+// this signer. If the caller wishes to specify the context to use to obtain
+// the public key, pass option.WithContext(desiredCtx).
+//
+// All other options are ignored if specified.
+func (g *SignerVerifier) PublicKey(opts ...signature.PublicKeyOption) (crypto.PublicKey, error) {
+ ctx := context.Background()
+ for _, opt := range opts {
+ opt.ApplyContext(&ctx)
+ }
+
+ return g.client.public(ctx)
+}
+
+// VerifySignature verifies the signature for the given message. Unless provided
+// in an option, the digest of the message will be computed using the hash function specified
+// when the SignerVerifier was created.
+//
+// This function returns nil if the verification succeeded, and an error message otherwise.
+//
+// This function recognizes the following Options listed in order of preference:
+//
+// - WithDigest()
+//
+// All other options are ignored if specified.
+func (g *SignerVerifier) VerifySignature(signature, message io.Reader, opts ...signature.VerifyOption) error {
+ return g.client.verify(signature, message, opts...)
+}
+
+// CreateKey attempts to create a new key in Vault with the specified algorithm.
+func (g *SignerVerifier) CreateKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) {
+ return g.client.createKey(ctx, algorithm)
+}
+
+type cryptoSignerWrapper struct {
+ ctx context.Context
+ hashFunc crypto.Hash
+ sv *SignerVerifier
+ errFunc func(error)
+}
+
+func (c cryptoSignerWrapper) Public() crypto.PublicKey {
+ pk, err := c.sv.PublicKey(options.WithContext(c.ctx))
+ if err != nil && c.errFunc != nil {
+ c.errFunc(err)
+ }
+ return pk
+}
+
+func (c cryptoSignerWrapper) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
+ hashFunc := c.hashFunc
+ if opts != nil {
+ hashFunc = opts.HashFunc()
+ }
+ gcpOptions := []signature.SignOption{
+ options.WithContext(c.ctx),
+ options.WithDigest(digest),
+ options.WithCryptoSignerOpts(hashFunc),
+ }
+
+ return c.sv.SignMessage(nil, gcpOptions...)
+}
+
+// CryptoSigner returns a crypto.Signer object that uses the underlying SignerVerifier, along with a crypto.SignerOpts object
+// that allows the KMS to be used in APIs that only accept the standard golang objects
+func (g *SignerVerifier) CryptoSigner(ctx context.Context, errFunc func(error)) (crypto.Signer, crypto.SignerOpts, error) {
+ defaultHf, err := g.client.getHashFunc()
+ if err != nil {
+ return nil, nil, fmt.Errorf("getting fetching default hash function: %w", err)
+ }
+
+ csw := &cryptoSignerWrapper{
+ ctx: ctx,
+ sv: g,
+ hashFunc: defaultHf,
+ errFunc: errFunc,
+ }
+
+ return csw, defaultHf, nil
+}
+
+// SupportedAlgorithms returns the list of algorithms supported by the GCP KMS service
+func (g *SignerVerifier) SupportedAlgorithms() (result []string) {
+ for k := range algorithmMap {
+ result = append(result, k)
+ }
+ return
+}
+
+// DefaultAlgorithm returns the default algorithm for the GCP KMS service
+func (g *SignerVerifier) DefaultAlgorithm() string {
+ return AlgorithmECDSAP256SHA256
+}