github.com/hyperledger/aries-framework-go@v0.3.2/pkg/wallet/kmsclient.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package wallet
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ed25519"
    12  	"crypto/sha256"
    13  	"errors"
    14  	"fmt"
    15  	"net/http"
    16  	"strings"
    17  	"sync"
    18  
    19  	"github.com/bluele/gcache"
    20  	"github.com/btcsuite/btcutil/base58"
    21  	"github.com/google/tink/go/subtle/random"
    22  
    23  	"github.com/hyperledger/aries-framework-go/pkg/crypto"
    24  	"github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub"
    25  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk"
    26  	"github.com/hyperledger/aries-framework-go/pkg/internal/kmssigner"
    27  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    28  	"github.com/hyperledger/aries-framework-go/pkg/kms/localkms"
    29  	"github.com/hyperledger/aries-framework-go/pkg/kms/webkms"
    30  	"github.com/hyperledger/aries-framework-go/pkg/secretlock"
    31  	"github.com/hyperledger/aries-framework-go/pkg/secretlock/local"
    32  	"github.com/hyperledger/aries-framework-go/pkg/secretlock/local/masterlock/hkdf"
    33  )
    34  
    35  const (
    36  	// LocalKeyURIPrefix for locally stored keys.
    37  	localKeyURIPrefix = "local-lock://"
    38  
    39  	// number of sections in verification method.
    40  	vmSectionCount = 2
    41  )
    42  
    43  // supported key types for import key base58 (all constants defined in lower case).
    44  const (
    45  	Ed25519VerificationKey2018 = "ed25519verificationkey2018"
    46  	Bls12381G1Key2020          = "bls12381g1key2020"
    47  )
    48  
    49  // supported JWK curves for jwk private key import.
    50  // nolint: gochecknoglobals
    51  var jwkCurves = map[string]kms.KeyType{
    52  	"Ed25519":    kms.ED25519Type,
    53  	"P-256":      kms.ECDSAP256TypeIEEEP1363,
    54  	"P-384":      kms.ECDSAP384TypeIEEEP1363,
    55  	"BLS12381G2": kms.BLS12381G2Type,
    56  }
    57  
    58  // errors.
    59  var (
    60  	// ErrAlreadyUnlocked error when key manager is already created for a given user.
    61  	ErrAlreadyUnlocked = errors.New("wallet already unlocked")
    62  
    63  	// ErrWalletLocked when key manager operation is attempted without unlocking wallet.
    64  	ErrWalletLocked = errors.New("wallet locked")
    65  )
    66  
    67  // walletKMSInstance is key manager store singleton - access only via keyManager()
    68  //
    69  //nolint:gochecknoglobals
    70  var (
    71  	walletKMSInstance *walletKeyManager
    72  	kmsStoreOnce      sync.Once
    73  )
    74  
    75  func keyManager() *walletKeyManager {
    76  	kmsStoreOnce.Do(func() {
    77  		walletKMSInstance = &walletKeyManager{
    78  			gstore: gcache.New(0).Build(),
    79  		}
    80  	})
    81  
    82  	return walletKMSInstance
    83  }
    84  
    85  // walletKeyManager manages key manager instances in cache.
    86  // underlying gcache is threasafe, no need of locks.
    87  type walletKeyManager struct {
    88  	gstore gcache.Cache
    89  }
    90  
    91  func (k *walletKeyManager) createKeyManager(profileInfo *profile,
    92  	storeProvider kms.Store, opts *unlockOpts) (kms.KeyManager, error) {
    93  	if profileInfo.MasterLockCipher == "" && profileInfo.KeyServerURL == "" {
    94  		return nil, fmt.Errorf("invalid wallet profile")
    95  	}
    96  
    97  	var err error
    98  
    99  	var keyManager kms.KeyManager
   100  
   101  	// create key manager
   102  	if profileInfo.MasterLockCipher != "" {
   103  		// local kms
   104  		keyManager, err = createLocalKeyManager(profileInfo.User, opts.passphrase,
   105  			profileInfo.MasterLockCipher, opts.secretLockSvc, storeProvider)
   106  		if err != nil {
   107  			return nil, fmt.Errorf("failed to create local key manager: %w", err)
   108  		}
   109  	} else {
   110  		// remote kms
   111  		keyManager = createRemoteKeyManager(opts, profileInfo.KeyServerURL)
   112  	}
   113  
   114  	return keyManager, nil
   115  }
   116  
   117  // createMasterLock creates master lock from secret lock service provided.
   118  func createMasterLock(secretLockSvc secretlock.Service) (string, error) {
   119  	masterKeyContent := random.GetRandomBytes(uint32(32)) //nolint: gomnd
   120  
   121  	masterLockEnc, err := secretLockSvc.Encrypt(localKeyURIPrefix, &secretlock.EncryptRequest{
   122  		Plaintext: string(masterKeyContent),
   123  	})
   124  	if err != nil {
   125  		return "", fmt.Errorf("failed to create master lock from secret lock service provided: %w", err)
   126  	}
   127  
   128  	return masterLockEnc.Ciphertext, nil
   129  }
   130  
   131  type kmsProvider struct {
   132  	storageProvider kms.Store
   133  	secretLock      secretlock.Service
   134  }
   135  
   136  func (k *kmsProvider) StorageProvider() kms.Store {
   137  	return k.storageProvider
   138  }
   139  
   140  func (k *kmsProvider) SecretLock() secretlock.Service {
   141  	return k.secretLock
   142  }
   143  
   144  // createLocalKeyManager creates and returns local KMS instance.
   145  func createLocalKeyManager(user, passphrase, masterLockCipher string,
   146  	masterLocker secretlock.Service, storeProvider kms.Store) (*localkms.LocalKMS, error) {
   147  	var err error
   148  	if passphrase != "" {
   149  		masterLocker, err = getDefaultSecretLock(passphrase)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  	}
   154  
   155  	secretLockSvc, err := local.NewService(bytes.NewBufferString(masterLockCipher), masterLocker)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	return localkms.New(localKeyURIPrefix+user, &kmsProvider{
   161  		storageProvider: storeProvider,
   162  		secretLock:      secretLockSvc,
   163  	})
   164  }
   165  
   166  // getDefaultSecretLock returns hkdf secret lock service from passphrase.
   167  func getDefaultSecretLock(passphrase string) (secretlock.Service, error) {
   168  	return hkdf.NewMasterLock(passphrase, sha256.New, nil)
   169  }
   170  
   171  // createRemoteKeyManager creates and returns remote KMS instance.
   172  func createRemoteKeyManager(opts *unlockOpts, keyServerURL string) *webkms.RemoteKMS {
   173  	kmsOpts := opts.webkmsOpts
   174  
   175  	if opts.authToken != "" {
   176  		kmsOpts = append(kmsOpts, webkms.WithHeaders(func(req *http.Request) (*http.Header, error) {
   177  			req.Header.Set("authorization", fmt.Sprintf("Bearer %s", opts.authToken))
   178  
   179  			return &req.Header, nil
   180  		}))
   181  	}
   182  
   183  	return webkms.New(keyServerURL, http.DefaultClient, kmsOpts...)
   184  }
   185  
   186  func newKMSSigner(authToken string, c crypto.Crypto, opts *ProofOptions) (*kmssigner.KMSSigner, error) {
   187  	session, err := sessionManager().getSession(authToken)
   188  	if err != nil {
   189  		if errors.Is(err, ErrInvalidAuthToken) {
   190  			return nil, ErrWalletLocked
   191  		}
   192  
   193  		return nil, fmt.Errorf("failed to get session: %w", err)
   194  	}
   195  
   196  	keyManager := session.KeyManager
   197  
   198  	vmSplit := strings.Split(opts.VerificationMethod, "#")
   199  
   200  	if len(vmSplit) != vmSectionCount {
   201  		return nil, errors.New("invalid verification method format")
   202  	}
   203  
   204  	kid := vmSplit[vmSectionCount-1]
   205  
   206  	keyHandler, err := keyManager.Get(kid)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	_, kt, err := keyManager.ExportPubKeyBytes(kid)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  
   216  	return &kmssigner.KMSSigner{
   217  		KeyType:   kt,
   218  		KeyHandle: keyHandler,
   219  		Crypto:    c,
   220  		MultiMsg:  opts.ProofType == BbsBlsSignature2020,
   221  	}, nil
   222  }
   223  
   224  // importKeyJWK imports private key jwk found in key contents,
   225  // supported curve types - Ed25519, P-256, BLS12381G2.
   226  func importKeyJWK(auth string, key *keyContent) error {
   227  	session, err := sessionManager().getSession(auth)
   228  	if err != nil {
   229  		if errors.Is(err, ErrInvalidAuthToken) {
   230  			return ErrWalletLocked
   231  		}
   232  
   233  		return fmt.Errorf("failed to get session: %w", err)
   234  	}
   235  
   236  	keyManager := session.KeyManager
   237  
   238  	var j jwk.JWK
   239  	if e := j.UnmarshalJSON(key.PrivateKeyJwk); e != nil {
   240  		return fmt.Errorf("failed to unmarshal jwk : %w", e)
   241  	}
   242  
   243  	keyType, ok := jwkCurves[j.Crv]
   244  	if !ok {
   245  		return fmt.Errorf("unsupported Key type %s", j.Crv)
   246  	}
   247  
   248  	_, _, err = keyManager.ImportPrivateKey(j.Key, keyType, kms.WithKeyID(getKIDFromJWK(key.ID, &j)))
   249  	if err != nil {
   250  		return fmt.Errorf("failed to import jwk key : %w", err)
   251  	}
   252  
   253  	return nil
   254  }
   255  
   256  // importKeyBase58 imports private key base58 found in key contents,
   257  // supported types - Ed25519Signature2018, Bls12381G1Key2020.
   258  func importKeyBase58(auth string, key *keyContent) error {
   259  	session, err := sessionManager().getSession(auth)
   260  	if err != nil {
   261  		if errors.Is(err, ErrInvalidAuthToken) {
   262  			return ErrWalletLocked
   263  		}
   264  
   265  		return fmt.Errorf("failed to get session: %w", err)
   266  	}
   267  
   268  	keyManager := session.KeyManager
   269  
   270  	switch strings.ToLower(key.KeyType) {
   271  	case Ed25519VerificationKey2018:
   272  		edPriv := ed25519.PrivateKey(base58.Decode(key.PrivateKeyBase58))
   273  
   274  		_, _, err := keyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(getKID(key.ID)))
   275  		if err != nil {
   276  			return fmt.Errorf("failed to import Ed25519Signature2018 key : %w", err)
   277  		}
   278  	case Bls12381G1Key2020:
   279  		blsKey, err := bbs12381g2pub.UnmarshalPrivateKey(base58.Decode(key.PrivateKeyBase58))
   280  		if err != nil {
   281  			return fmt.Errorf("failed to unmarshal %s private key : %w", kms.BLS12381G2Type, err)
   282  		}
   283  
   284  		_, _, err = keyManager.ImportPrivateKey(blsKey, kms.BLS12381G2, kms.WithKeyID(getKID(key.ID)))
   285  		if err != nil {
   286  			return fmt.Errorf("failed to import Ed25519Signature2018 key : %w", err)
   287  		}
   288  	default:
   289  		return errors.New("only Ed25519VerificationKey2018 &  Bls12381G1Key2020 are supported in base58 format")
   290  	}
   291  
   292  	return nil
   293  }
   294  
   295  func getKID(id string) string {
   296  	cSplit := strings.Split(id, "#")
   297  
   298  	if len(cSplit) > 1 {
   299  		return cSplit[1]
   300  	}
   301  
   302  	return ""
   303  }
   304  
   305  func getKIDFromJWK(id string, j *jwk.JWK) string {
   306  	if j.KeyID != "" {
   307  		return j.KeyID
   308  	}
   309  
   310  	return getKID(id)
   311  }