github.com/trustbloc/kms-go@v1.1.2/kms/localkms/localkms.go (about)

     1  /*
     2   Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4   SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package localkms
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ecdsa"
    12  	"crypto/ed25519"
    13  	"encoding/json"
    14  	"errors"
    15  	"fmt"
    16  
    17  	"github.com/google/tink/go/aead"
    18  	"github.com/google/tink/go/keyset"
    19  	"github.com/trustbloc/bbs-signature-go/bbs12381g2pub"
    20  
    21  	kmsapi "github.com/trustbloc/kms-go/spi/kms"
    22  
    23  	"github.com/trustbloc/kms-go/spi/secretlock"
    24  
    25  	cryptoapi "github.com/trustbloc/kms-go/spi/crypto"
    26  
    27  	"github.com/trustbloc/kms-go/doc/util/jwkkid"
    28  	"github.com/trustbloc/kms-go/kms"
    29  	"github.com/trustbloc/kms-go/kms/localkms/internal/keywrapper"
    30  )
    31  
    32  const (
    33  	// Namespace is the store name used when creating a KMS store using kms.NewAriesProviderWrapper.
    34  	// The reason this is here in addition to kms.AriesWrapperStoreName is because
    35  	// the IndexedDB implementation refers to this. FOr the WASM unit tests, the aries-framework-go module import gets
    36  	// replaced with the local version and so in order for both to work correctly, for now we have the constant defined
    37  	// in both places.
    38  	Namespace = kms.AriesWrapperStoreName
    39  
    40  	ecdsaPrivateKeyTypeURL = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"
    41  )
    42  
    43  var errInvalidKeyType = errors.New("key type is not supported")
    44  
    45  // package localkms is the default KMS service implementation of pkg/kms.KeyManager. It uses Tink keys to support the
    46  // default Crypto implementation, pkg/crypto/tinkcrypto, and stores these keys in the format understood by Tink. It also
    47  // uses a secretLock service to protect private key material in the storage.
    48  
    49  // LocalKMS implements kms.KeyManager to provide key management capabilities using a local db.
    50  // It uses an underlying secret lock service (default local secretLock) to wrap (encrypt) keys
    51  // prior to storing them.
    52  type LocalKMS struct {
    53  	secretLock        secretlock.Service
    54  	primaryKeyURI     string
    55  	store             kmsapi.Store
    56  	primaryKeyEnvAEAD *aead.KMSEnvelopeAEAD
    57  }
    58  
    59  // New will create a new (local) KMS service.
    60  func New(primaryKeyURI string, p kmsapi.Provider) (*LocalKMS, error) {
    61  	secretLock := p.SecretLock()
    62  
    63  	kw, err := keywrapper.New(secretLock, primaryKeyURI)
    64  	if err != nil {
    65  		return nil, fmt.Errorf("new: failed to create new keywrapper: %w", err)
    66  	}
    67  
    68  	// create a KMSEnvelopeAEAD instance to wrap/unwrap keys managed by LocalKMS
    69  	keyEnvelopeAEAD := aead.NewKMSEnvelopeAEAD2(aead.AES256GCMKeyTemplate(), kw)
    70  
    71  	return &LocalKMS{
    72  			store:             p.StorageProvider(),
    73  			secretLock:        secretLock,
    74  			primaryKeyURI:     primaryKeyURI,
    75  			primaryKeyEnvAEAD: keyEnvelopeAEAD,
    76  		},
    77  		nil
    78  }
    79  
    80  // HealthCheck check kms.
    81  func (l *LocalKMS) HealthCheck() error {
    82  	return nil
    83  }
    84  
    85  // Create a new key/keyset/key handle for the type kt
    86  // Returns:
    87  //   - keyID of the handle
    88  //   - handle instance (to private key)
    89  //   - error if failure
    90  func (l *LocalKMS) Create(kt kmsapi.KeyType, opts ...kmsapi.KeyOpts) (string, interface{}, error) {
    91  	if kt == "" {
    92  		return "", nil, fmt.Errorf("failed to create new key, missing key type")
    93  	}
    94  
    95  	if kt == kmsapi.ECDSASecp256k1DER {
    96  		return "", nil, fmt.Errorf("create: Unable to create kms key: Secp256K1 is not supported by DER format")
    97  	}
    98  
    99  	keyTemplate, err := getKeyTemplate(kt, opts...)
   100  	if err != nil {
   101  		return "", nil, fmt.Errorf("create: failed to getKeyTemplate: %w", err)
   102  	}
   103  
   104  	kh, err := keyset.NewHandle(keyTemplate)
   105  	if err != nil {
   106  		return "", nil, fmt.Errorf("create: failed to create new keyset handle: %w", err)
   107  	}
   108  
   109  	keyID, err := l.storeKeySet(kh, kt)
   110  	if err != nil {
   111  		return "", nil, fmt.Errorf("create: failed to store keyset: %w", err)
   112  	}
   113  
   114  	return keyID, kh, nil
   115  }
   116  
   117  // Get key handle for the given keyID
   118  // Returns:
   119  //   - handle instance (to private key)
   120  //   - error if failure
   121  func (l *LocalKMS) Get(keyID string) (interface{}, error) {
   122  	return l.getKeySet(keyID)
   123  }
   124  
   125  // Rotate a key referenced by keyID and return a new handle of a keyset including old key and
   126  // new key with type kt. It also returns the updated keyID as the first return value
   127  // Returns:
   128  //   - new KeyID
   129  //   - handle instance (to private key)
   130  //   - error if failure
   131  func (l *LocalKMS) Rotate(kt kmsapi.KeyType, keyID string, opts ...kmsapi.KeyOpts) (string, interface{}, error) {
   132  	kh, err := l.getKeySet(keyID)
   133  	if err != nil {
   134  		return "", nil, fmt.Errorf("rotate: failed to getKeySet: %w", err)
   135  	}
   136  
   137  	keyTemplate, err := getKeyTemplate(kt, opts...)
   138  	if err != nil {
   139  		return "", nil, fmt.Errorf("rotate: failed to get GetKeyTemplate: %w", err)
   140  	}
   141  
   142  	km := keyset.NewManagerFromHandle(kh)
   143  
   144  	err = km.Rotate(keyTemplate)
   145  	if err != nil {
   146  		return "", nil, fmt.Errorf("rotate: failed to call Tink's keyManager rotate: %w", err)
   147  	}
   148  
   149  	updatedKH, err := km.Handle()
   150  	if err != nil {
   151  		return "", nil, fmt.Errorf("rotate: failed to get kms keyest handle: %w", err)
   152  	}
   153  
   154  	err = l.store.Delete(keyID)
   155  	if err != nil {
   156  		return "", nil, fmt.Errorf("rotate: failed to delete entry for kid '%s': %w", keyID, err)
   157  	}
   158  
   159  	newID, err := l.storeKeySet(updatedKH, kt)
   160  	if err != nil {
   161  		return "", nil, fmt.Errorf("rotate: failed to store keySet: %w", err)
   162  	}
   163  
   164  	return newID, updatedKH, nil
   165  }
   166  
   167  func (l *LocalKMS) storeKeySet(kh *keyset.Handle, kt kmsapi.KeyType) (string, error) {
   168  	var (
   169  		kid string
   170  		err error
   171  	)
   172  
   173  	switch kt {
   174  	case kmsapi.AES128GCMType, kmsapi.AES256GCMType, kmsapi.AES256GCMNoPrefixType, kmsapi.ChaCha20Poly1305Type,
   175  		kmsapi.XChaCha20Poly1305Type, kmsapi.HMACSHA256Tag256Type, kmsapi.CLMasterSecretType:
   176  		// symmetric keys will have random kid value (generated in the local storeWriter)
   177  	case kmsapi.CLCredDefType:
   178  		// ignoring custom KID generation for the asymmetric CL CredDef
   179  	default:
   180  		// asymmetric keys will use the public key's JWK thumbprint base64URL encoded as kid value
   181  		kid, err = l.generateKID(kh, kt)
   182  		if err != nil && !errors.Is(err, errInvalidKeyType) {
   183  			return "", fmt.Errorf("storeKeySet: failed to generate kid: %w", err)
   184  		}
   185  	}
   186  
   187  	buf := new(bytes.Buffer)
   188  	jsonKeysetWriter := keyset.NewJSONWriter(buf)
   189  
   190  	err = kh.Write(jsonKeysetWriter, l.primaryKeyEnvAEAD)
   191  	if err != nil {
   192  		return "", fmt.Errorf("storeKeySet: failed to write json key to buffer: %w", err)
   193  	}
   194  
   195  	// asymmetric keys are JWK thumbprints of the public key, base64URL encoded stored in kid.
   196  	// symmetric keys will have a randomly generated key ID (where kid is empty)
   197  	if kid != "" {
   198  		return writeToStore(l.store, buf, kmsapi.WithKeyID(kid))
   199  	}
   200  
   201  	return writeToStore(l.store, buf)
   202  }
   203  
   204  func writeToStore(store kmsapi.Store, buf *bytes.Buffer, opts ...kmsapi.PrivateKeyOpts) (string, error) {
   205  	w := newWriter(store, opts...)
   206  
   207  	// write buffer to localstorage
   208  	_, err := w.Write(buf.Bytes())
   209  	if err != nil {
   210  		return "", fmt.Errorf("writeToStore: failed to write buffer to store: %w", err)
   211  	}
   212  
   213  	return w.KeysetID, nil
   214  }
   215  
   216  func (l *LocalKMS) getKeySet(id string) (*keyset.Handle, error) {
   217  	localDBReader := newReader(l.store, id)
   218  
   219  	jsonKeysetReader := keyset.NewJSONReader(localDBReader)
   220  
   221  	// Read reads the encrypted keyset handle back from the io.reader implementation
   222  	// and decrypts it using primaryKeyEnvAEAD.
   223  	kh, err := keyset.Read(jsonKeysetReader, l.primaryKeyEnvAEAD)
   224  	if err != nil {
   225  		return nil, fmt.Errorf("getKeySet: failed to read json keyset from reader: %w", err)
   226  	}
   227  
   228  	return kh, nil
   229  }
   230  
   231  // ExportPubKeyBytes will fetch a key referenced by id then gets its public key in raw bytes and returns it.
   232  // The key must be an asymmetric key.
   233  // Returns:
   234  //   - marshalled public key []byte
   235  //   - error if it fails to export the public key bytes
   236  func (l *LocalKMS) ExportPubKeyBytes(id string) ([]byte, kmsapi.KeyType, error) {
   237  	kh, err := l.getKeySet(id)
   238  	if err != nil {
   239  		return nil, "", fmt.Errorf("exportPubKeyBytes: failed to get keyset handle: %w", err)
   240  	}
   241  
   242  	marshalledKey, kt, err := l.exportPubKeyBytes(kh)
   243  	if err != nil {
   244  		return nil, "", fmt.Errorf("exportPubKeyBytes: failed to export marshalled key: %w", err)
   245  	}
   246  
   247  	// Ignore KID for CL CredDef keys
   248  	if kt == kmsapi.CLCredDefType {
   249  		return marshalledKey, kt, nil
   250  	}
   251  
   252  	mUpdatedKey, err := setKIDForCompositeKey(marshalledKey, id)
   253  
   254  	return mUpdatedKey, kt, err
   255  }
   256  
   257  func setKIDForCompositeKey(marshalledKey []byte, kid string) ([]byte, error) {
   258  	pubKey := &cryptoapi.PublicKey{}
   259  
   260  	err := json.Unmarshal(marshalledKey, pubKey)
   261  	if err != nil { // if unmarshalling to VerificationMethod fails, it's not a composite key, return original bytes
   262  		return marshalledKey, nil //nolint:nilerr
   263  	}
   264  
   265  	pubKey.KID = kid
   266  
   267  	return json.Marshal(pubKey)
   268  }
   269  
   270  func (l *LocalKMS) exportPubKeyBytes(kh *keyset.Handle) ([]byte, kmsapi.KeyType, error) {
   271  	// kh must be a private asymmetric key in order to extract its public key
   272  	pubKH, err := kh.Public()
   273  	if err != nil {
   274  		return nil, "", fmt.Errorf("exportPubKeyBytes: failed to get public keyset handle: %w", err)
   275  	}
   276  
   277  	buf := new(bytes.Buffer)
   278  	pubKeyWriter := NewWriter(buf)
   279  
   280  	err = pubKH.WriteWithNoSecrets(pubKeyWriter)
   281  	if err != nil {
   282  		return nil, "", fmt.Errorf("exportPubKeyBytes: failed to create keyset with no secrets (public "+
   283  			"key material): %w", err)
   284  	}
   285  
   286  	return buf.Bytes(), pubKeyWriter.KeyType, nil
   287  }
   288  
   289  // CreateAndExportPubKeyBytes will create a key of type kt and export its public key in raw bytes and returns it.
   290  // The key must be an asymmetric key.
   291  // Returns:
   292  //   - keyID of the new handle created.
   293  //   - marshalled public key []byte
   294  //   - error if it fails to export the public key bytes
   295  func (l *LocalKMS) CreateAndExportPubKeyBytes(kt kmsapi.KeyType, opts ...kmsapi.KeyOpts) (string, []byte, error) {
   296  	kid, _, err := l.Create(kt, opts...)
   297  	if err != nil {
   298  		return "", nil, fmt.Errorf("createAndExportPubKeyBytes: failed to create new key: %w", err)
   299  	}
   300  
   301  	pubKeyBytes, _, err := l.ExportPubKeyBytes(kid)
   302  	if err != nil {
   303  		return "", nil, fmt.Errorf("createAndExportPubKeyBytes: failed to export new public key bytes: %w", err)
   304  	}
   305  
   306  	return kid, pubKeyBytes, nil
   307  }
   308  
   309  // PubKeyBytesToHandle will create and return a key handle for pubKey of type kt
   310  // it returns an error if it failed creating the key handle
   311  // Note: The key handle created is not stored in the KMS, it's only useful to execute the crypto primitive
   312  // associated with it.
   313  func (l *LocalKMS) PubKeyBytesToHandle(pubKey []byte, kt kmsapi.KeyType, opts ...kmsapi.KeyOpts) (interface{}, error) {
   314  	return PublicKeyBytesToHandle(pubKey, kt, opts...)
   315  }
   316  
   317  // ImportPrivateKey will import privKey into the KMS storage for the given keyType then returns the new key id and
   318  // the newly persisted Handle.
   319  // 'privKey' possible types are: *ecdsa.PrivateKey and ed25519.PrivateKey
   320  // 'keyType' possible types are signing key types only (ECDSA keys or Ed25519)
   321  // 'opts' allows setting the keysetID of the imported key using WithKeyID() option. If the ID is already used,
   322  // then an error is returned.
   323  // Returns:
   324  //   - keyID of the handle
   325  //   - handle instance (to private key)
   326  //   - error if import failure (key empty, invalid, doesn't match keyType, unsupported keyType or storing key failed)
   327  func (l *LocalKMS) ImportPrivateKey(privKey interface{}, kt kmsapi.KeyType,
   328  	opts ...kmsapi.PrivateKeyOpts) (string, interface{}, error) {
   329  	switch pk := privKey.(type) {
   330  	case *ecdsa.PrivateKey:
   331  		return l.importECDSAKey(pk, kt, opts...)
   332  	case ed25519.PrivateKey:
   333  		return l.importEd25519Key(pk, kt, opts...)
   334  	case *bbs12381g2pub.PrivateKey:
   335  		return l.importBBSKey(pk, kt, opts...)
   336  	default:
   337  		return "", nil, fmt.Errorf("import private key does not support this key type or key is public")
   338  	}
   339  }
   340  
   341  func (l *LocalKMS) generateKID(kh *keyset.Handle, kt kmsapi.KeyType) (string, error) {
   342  	keyBytes, _, err := l.exportPubKeyBytes(kh)
   343  	if err != nil {
   344  		return "", fmt.Errorf("generateKID: failed to export public key: %w", err)
   345  	}
   346  
   347  	return jwkkid.CreateKID(keyBytes, kt)
   348  }