...

Source file src/github.com/sigstore/timestamp-authority/pkg/signer/tink.go

Documentation: github.com/sigstore/timestamp-authority/pkg/signer

     1  // Copyright 2022 The Sigstore Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package signer
    16  
    17  import (
    18  	"context"
    19  	"crypto"
    20  	"crypto/ecdsa"
    21  	"crypto/ed25519"
    22  	"errors"
    23  	"fmt"
    24  	"math/big"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  
    29  	"github.com/google/tink/go/core/registry"
    30  	"github.com/google/tink/go/integration/awskms"
    31  	"github.com/google/tink/go/integration/gcpkms"
    32  	"github.com/google/tink/go/integration/hcvault"
    33  	signatureSubtle "github.com/google/tink/go/signature/subtle"
    34  	"github.com/google/tink/go/subtle"
    35  	"github.com/google/tink/go/tink"
    36  
    37  	"github.com/golang/protobuf/proto" //lint:ignore SA1019 needed for unmarshalling
    38  	"github.com/google/tink/go/insecurecleartextkeyset"
    39  	"github.com/google/tink/go/keyset"
    40  	commonpb "github.com/google/tink/go/proto/common_go_proto"
    41  	ecdsapb "github.com/google/tink/go/proto/ecdsa_go_proto"
    42  	ed25519pb "github.com/google/tink/go/proto/ed25519_go_proto"
    43  	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
    44  )
    45  
    46  var (
    47  	ecdsaSignerKeyVersion   = 0
    48  	ecdsaSignerTypeURL      = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"
    49  	ed25519SignerKeyVersion = 0
    50  	ed25519SignerTypeURL    = "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey"
    51  )
    52  
    53  // NewTinkSigner creates a signer by decrypting a local Tink keyset with a remote KMS encryption key
    54  func NewTinkSigner(_ context.Context, tinkKeysetPath string, primaryKey tink.AEAD) (crypto.Signer, error) {
    55  	f, err := os.Open(filepath.Clean(tinkKeysetPath))
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	defer f.Close()
    60  
    61  	kh, err := keyset.Read(keyset.NewJSONReader(f), primaryKey)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	signer, err := KeyHandleToSigner(kh)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return signer, nil
    70  }
    71  
    72  // GetPrimaryKey returns a Tink AEAD encryption key from KMS
    73  // Supports GCP, AWS, and Vault
    74  func GetPrimaryKey(ctx context.Context, kmsKey, hcVaultToken string) (tink.AEAD, error) {
    75  	switch {
    76  	case strings.HasPrefix(kmsKey, "gcp-kms://"):
    77  		gcpClient, err := gcpkms.NewClientWithOptions(ctx, kmsKey)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  		registry.RegisterKMSClient(gcpClient)
    82  		return gcpClient.GetAEAD(kmsKey)
    83  	case strings.HasPrefix(kmsKey, "aws-kms://"):
    84  		awsClient, err := awskms.NewClient(kmsKey)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		registry.RegisterKMSClient(awsClient)
    89  		return awsClient.GetAEAD(kmsKey)
    90  	case strings.HasPrefix(kmsKey, "hcvault://"):
    91  		hcVaultClient, err := hcvault.NewClient(kmsKey, nil, hcVaultToken)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		registry.RegisterKMSClient(hcVaultClient)
    96  		return hcVaultClient.GetAEAD(kmsKey)
    97  	default:
    98  		return nil, errors.New("unsupported Tink KMS key type")
    99  	}
   100  }
   101  
   102  // KeyHandleToSigner converts a key handle to the crypto.Signer interface.
   103  // Heavily pulls from Tink's signature and subtle packages.
   104  func KeyHandleToSigner(kh *keyset.Handle) (crypto.Signer, error) {
   105  	// extract the key material from the key handle
   106  	ks := insecurecleartextkeyset.KeysetMaterial(kh)
   107  
   108  	k := getPrimaryKey(ks)
   109  	if k == nil {
   110  		return nil, errors.New("no enabled key found in keyset")
   111  	}
   112  
   113  	switch k.GetTypeUrl() {
   114  	case ecdsaSignerTypeURL:
   115  		// https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ecdsa_signer_key_manager.go#L48
   116  		privKey := new(ecdsapb.EcdsaPrivateKey)
   117  		if err := proto.Unmarshal(k.GetValue(), privKey); err != nil {
   118  			return nil, fmt.Errorf("error unmarshalling ecdsa private key: %w", err)
   119  		}
   120  		if err := validateEcdsaPrivKey(privKey); err != nil {
   121  			return nil, fmt.Errorf("error validating ecdsa private key: %w", err)
   122  		}
   123  		// https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/subtle/ecdsa_signer.go#L39
   124  		_, curve, _ := getECDSAParamNames(privKey.PublicKey.Params)
   125  		p := new(ecdsa.PrivateKey)
   126  		c := subtle.GetCurve(curve)
   127  		p.PublicKey.Curve = c
   128  		p.D = new(big.Int).SetBytes(privKey.GetKeyValue())
   129  		p.PublicKey.X, p.PublicKey.Y = c.ScalarBaseMult(privKey.GetKeyValue())
   130  		return p, nil
   131  	case ed25519SignerTypeURL:
   132  		// https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ed25519_signer_key_manager.go#L47
   133  		privKey := new(ed25519pb.Ed25519PrivateKey)
   134  		if err := proto.Unmarshal(k.GetValue(), privKey); err != nil {
   135  			return nil, fmt.Errorf("error unmarshalling ed25519 private key: %w", err)
   136  		}
   137  		if err := validateEd25519PrivKey(privKey); err != nil {
   138  			return nil, fmt.Errorf("error validating ed25519 private key: %w", err)
   139  		}
   140  		// https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/subtle/ed25519_signer.go#L29
   141  		p := ed25519.NewKeyFromSeed(privKey.GetKeyValue())
   142  		return p, nil
   143  	default:
   144  		return nil, fmt.Errorf("unsupported key type: %s", k.GetTypeUrl())
   145  	}
   146  }
   147  
   148  // getPrimaryKey returns the first enabled key from a keyset.
   149  func getPrimaryKey(ks *tinkpb.Keyset) *tinkpb.KeyData {
   150  	for _, k := range ks.GetKey() {
   151  		if k.GetKeyId() == ks.GetPrimaryKeyId() && k.GetStatus() == tinkpb.KeyStatusType_ENABLED {
   152  			return k.GetKeyData()
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  // validateEcdsaPrivKey validates the given ECDSAPrivateKey.
   159  // https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ecdsa_signer_key_manager.go#L139
   160  func validateEcdsaPrivKey(key *ecdsapb.EcdsaPrivateKey) error {
   161  	if err := keyset.ValidateKeyVersion(key.Version, uint32(ecdsaSignerKeyVersion)); err != nil {
   162  		return fmt.Errorf("ecdsa_signer_key_manager: invalid key: %w", err)
   163  	}
   164  	hash, curve, encoding := getECDSAParamNames(key.PublicKey.Params)
   165  	return signatureSubtle.ValidateECDSAParams(hash, curve, encoding)
   166  }
   167  
   168  // getECDSAParamNames returns the string representations of each parameter in
   169  // the given ECDSAParams.
   170  // https://github.com/google/tink/blob/4cc630dfc711555f6bbbad64f8c573b39b7af500/go/signature/proto.go#L26
   171  func getECDSAParamNames(params *ecdsapb.EcdsaParams) (string, string, string) {
   172  	hashName := commonpb.HashType_name[int32(params.HashType)]
   173  	curveName := commonpb.EllipticCurveType_name[int32(params.Curve)]
   174  	encodingName := ecdsapb.EcdsaSignatureEncoding_name[int32(params.Encoding)]
   175  	return hashName, curveName, encodingName
   176  }
   177  
   178  // validateEd25519PrivKey validates the given ED25519PrivateKey.
   179  // https://github.com/google/tink/blob/9753ffddd4d04aa56e0605ff4a0db46f2fb80529/go/signature/ed25519_signer_key_manager.go#L132
   180  func validateEd25519PrivKey(key *ed25519pb.Ed25519PrivateKey) error {
   181  	if err := keyset.ValidateKeyVersion(key.Version, uint32(ed25519SignerKeyVersion)); err != nil {
   182  		return fmt.Errorf("ed25519_signer_key_manager: invalid key: %w", err)
   183  	}
   184  	if len(key.KeyValue) != ed25519.SeedSize {
   185  		return fmt.Errorf("ed2219_signer_key_manager: invalid key length, got %d", len(key.KeyValue))
   186  	}
   187  	return nil
   188  }
   189  

View as plain text