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

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  //nolint
     8  package wallet
     9  
    10  import (
    11  	"encoding/json"
    12  	"errors"
    13  	"fmt"
    14  	"net/http"
    15  
    16  	"github.com/hyperledger/aries-framework-go/pkg/crypto/webkms"
    17  
    18  	"github.com/hyperledger/aries-framework-go/component/storage/edv"
    19  
    20  	"github.com/hyperledger/aries-framework-go/pkg/crypto"
    21  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto"
    22  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/packer"
    23  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
    24  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    25  	"github.com/hyperledger/aries-framework-go/spi/storage"
    26  )
    27  
    28  // storageProvider all wallet content storage provider operations.
    29  // if profile has EDV settings then call to OpenStore will return EDV store instance by creating new EDV provider.
    30  // Otherwise default provider will be used to open store.
    31  // (Refer #2745 for more details)
    32  type storageProvider struct {
    33  	profile         *profile
    34  	defaultProvider storage.Provider
    35  }
    36  
    37  func newWalletStorageProvider(profile *profile, provider storage.Provider) *storageProvider {
    38  	return &storageProvider{profile: profile, defaultProvider: provider}
    39  }
    40  
    41  // OpenStore opens and returns store and sets store config to provider.
    42  // if wallet profile has EDV settings then auth provided will be used to initialize edv storage provider.
    43  func (s *storageProvider) OpenStore(keyMgr kms.KeyManager, opts *unlockOpts, config storage.StoreConfiguration) (storage.Store, error) {
    44  	var provider storage.Provider
    45  	var err error
    46  
    47  	if s.profile.EDVConf != nil {
    48  		provider, err = createEDVStorageProvider(keyMgr, s.profile, opts)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  	} else {
    53  		provider = s.defaultProvider
    54  	}
    55  
    56  	store, err := provider.OpenStore(s.profile.ID)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("failed to open store : %w", err)
    59  	}
    60  
    61  	err = provider.SetStoreConfig(s.profile.ID, config)
    62  	if err != nil {
    63  		e := store.Close()
    64  		if e != nil {
    65  			logger.Warnf("failed to close store: %s", e)
    66  		}
    67  
    68  		return nil, fmt.Errorf("failed to set store config: %w", err)
    69  	}
    70  
    71  	return store, nil
    72  }
    73  
    74  // TODO (#2815): find a way to allow EDV to be used without importing the edv package, since it causes the main Aries
    75  //               module to depend on edv
    76  func createEDVStorageProvider(keyMgr kms.KeyManager, profile *profile, opts *unlockOpts) (storage.Provider, error) {
    77  	if profile.EDVConf.EncryptionKeyID == "" || profile.EDVConf.MACKeyID == "" {
    78  		return nil, errors.New("invalid EDV configuration found in wallet profile, key IDs for encryption and MAC operations are missing") //nolint: lll
    79  	}
    80  
    81  	var err error
    82  
    83  	// get crypto
    84  	var cryptoImpl crypto.Crypto
    85  	if profile.KeyServerURL != "" {
    86  		cryptoImpl = webkms.New(profile.KeyServerURL, http.DefaultClient, opts.webkmsOpts...)
    87  	} else {
    88  		cryptoImpl, err = tinkcrypto.New()
    89  		if err != nil {
    90  			return nil, fmt.Errorf("failed to create crypto: %w", err)
    91  		}
    92  	}
    93  
    94  	// get jwe encrypter
    95  	jweEncrypter, err := getJWSEncrypter(profile.EDVConf.EncryptionKeyID, keyMgr, cryptoImpl)
    96  	if err != nil {
    97  		return nil, fmt.Errorf("failed to create JWE encrypter: %w", err)
    98  	}
    99  
   100  	// get jwe decrypter
   101  	jweDecrypter := jose.NewJWEDecrypt(nil, cryptoImpl, keyMgr)
   102  
   103  	// get MAC crypto
   104  	macCrypto, err := getMacCrypto(profile.EDVConf.MACKeyID, keyMgr, cryptoImpl)
   105  	if err != nil {
   106  		return nil, fmt.Errorf("failed to create mac crypto: %w", err)
   107  	}
   108  
   109  	var edvOpts []edv.RESTProviderOption
   110  	if opts != nil {
   111  		edvOpts = append(edvOpts, opts.edvOpts...)
   112  	}
   113  
   114  	// create EDV provider
   115  	return edv.NewRESTProvider(profile.EDVConf.ServerURL, profile.EDVConf.VaultID,
   116  		edv.NewEncryptedFormatter(jweEncrypter, jweDecrypter, macCrypto, edv.WithDeterministicDocumentIDs()),
   117  		edvOpts...), nil
   118  }
   119  
   120  // getJWSEncrypter creates and returns jwe encrypter based on key manager & crypto provided
   121  func getJWSEncrypter(kid string, keyMgr kms.KeyManager, cryptoImpl crypto.Crypto) (*jose.JWEEncrypt, error) {
   122  	pubKeyBytes, _, err := keyMgr.ExportPubKeyBytes(kid)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	ecPubKey := new(crypto.PublicKey)
   128  
   129  	ecPubKey.KID = kid
   130  
   131  	err = json.Unmarshal(pubKeyBytes, ecPubKey)
   132  	if err != nil {
   133  		return nil, fmt.Errorf("failed to unmarshal JWE public key bytes to an EC public key: %w", err)
   134  	}
   135  
   136  	return jose.NewJWEEncrypt(jose.A256GCM, packer.EnvelopeEncodingTypeV2, "", "", nil,
   137  		[]*crypto.PublicKey{ecPubKey}, cryptoImpl)
   138  }
   139  
   140  // getMacCrypto creates and returns MAC crypto based on key manager & crypto provided
   141  func getMacCrypto(kid string, keyMgr kms.KeyManager, cryptoImpl crypto.Crypto) (*edv.MACCrypto, error) {
   142  	keyHandle, err := keyMgr.Get(kid)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	return edv.NewMACCrypto(keyHandle, cryptoImpl), nil
   148  }