github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric/bccsp/sw/fileks.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package sw
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/hex"
    12  	"errors"
    13  	"fmt"
    14  	"github.com/hellobchain/newcryptosm/ecdsa"
    15  	"io"
    16  	"io/ioutil"
    17  	"os"
    18  	"path/filepath"
    19  	"strings"
    20  	"sync"
    21  
    22  	"github.com/hellobchain/third_party/hyperledger/fabric/bccsp"
    23  )
    24  
    25  // NewFileBasedKeyStore instantiated a file-based key store at a given position.
    26  // The key store can be encrypted if a non-empty password is specified.
    27  // It can be also be set as read only. In this case, any store operation
    28  // will be forbidden
    29  func NewFileBasedKeyStore(pwd []byte, path string, readOnly bool) (bccsp.KeyStore, error) {
    30  	ks := &fileBasedKeyStore{}
    31  	return ks, ks.Init(pwd, path, readOnly)
    32  }
    33  
    34  // fileBasedKeyStore is a folder-based KeyStore.
    35  // Each key is stored in a separated file whose name contains the key's SKI
    36  // and flags to identity the key's type. All the keys are stored in
    37  // a folder whose path is provided at initialization time.
    38  // The KeyStore can be initialized with a password, this password
    39  // is used to encrypt and decrypt the files storing the keys.
    40  // A KeyStore can be read only to avoid the overwriting of keys.
    41  type fileBasedKeyStore struct {
    42  	path string
    43  
    44  	readOnly bool
    45  	isOpen   bool
    46  
    47  	pwd []byte
    48  
    49  	// Sync
    50  	m sync.Mutex
    51  }
    52  
    53  // Init initializes this KeyStore with a password, a path to a folder
    54  // where the keys are stored and a read only flag.
    55  // Each key is stored in a separated file whose name contains the key's SKI
    56  // and flags to identity the key's type.
    57  // If the KeyStore is initialized with a password, this password
    58  // is used to encrypt and decrypt the files storing the keys.
    59  // The pwd can be nil for non-encrypted KeyStores. If an encrypted
    60  // key-store is initialized without a password, then retrieving keys from the
    61  // KeyStore will fail.
    62  // A KeyStore can be read only to avoid the overwriting of keys.
    63  func (ks *fileBasedKeyStore) Init(pwd []byte, path string, readOnly bool) error {
    64  	// Validate inputs
    65  	// pwd can be nil
    66  
    67  	if len(path) == 0 {
    68  		return errors.New("an invalid KeyStore path provided. Path cannot be an empty string")
    69  	}
    70  
    71  	ks.m.Lock()
    72  	defer ks.m.Unlock()
    73  
    74  	if ks.isOpen {
    75  		return errors.New("keystore is already initialized")
    76  	}
    77  
    78  	ks.path = path
    79  
    80  	clone := make([]byte, len(pwd))
    81  	copy(clone, pwd)
    82  	ks.pwd = clone
    83  	ks.readOnly = readOnly
    84  
    85  	exists, err := dirExists(path)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	if !exists {
    90  		err = ks.createKeyStore()
    91  		if err != nil {
    92  			return err
    93  		}
    94  		return ks.openKeyStore()
    95  	}
    96  
    97  	empty, err := dirEmpty(path)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if empty {
   102  		err = ks.createKeyStore()
   103  		if err != nil {
   104  			return err
   105  		}
   106  	}
   107  
   108  	return ks.openKeyStore()
   109  }
   110  
   111  // ReadOnly returns true if this KeyStore is read only, false otherwise.
   112  // If ReadOnly is true then StoreKey will fail.
   113  func (ks *fileBasedKeyStore) ReadOnly() bool {
   114  	return ks.readOnly
   115  }
   116  
   117  // GetKey returns a key object whose SKI is the one passed.
   118  func (ks *fileBasedKeyStore) GetKey(ski []byte) (bccsp.Key, error) {
   119  	// Validate arguments
   120  	if len(ski) == 0 {
   121  		return nil, errors.New("invalid SKI. Cannot be of zero length")
   122  	}
   123  
   124  	suffix := ks.getSuffix(hex.EncodeToString(ski))
   125  
   126  	switch suffix {
   127  	case "key":
   128  		// Load the key
   129  		key, err := ks.loadKey(hex.EncodeToString(ski))
   130  		if err != nil {
   131  			return nil, fmt.Errorf("failed loading key [%x] [%s]", ski, err)
   132  		}
   133  
   134  		return &symmetryPrivateKey{key, false}, nil
   135  	case "sk":
   136  		// Load the private key
   137  		key, err := ks.loadPrivateKey(hex.EncodeToString(ski))
   138  		if err != nil {
   139  			return nil, fmt.Errorf("failed loading secret key [%x] [%s]", ski, err)
   140  		}
   141  
   142  		switch k := key.(type) {
   143  		case *ecdsa.PrivateKey:
   144  			return &ecdsaPrivateKey{k}, nil
   145  		default:
   146  			return nil, errors.New("secret key type not recognized")
   147  		}
   148  	case "pk":
   149  		// Load the public key
   150  		key, err := ks.loadPublicKey(hex.EncodeToString(ski))
   151  		if err != nil {
   152  			return nil, fmt.Errorf("failed loading public key [%x] [%s]", ski, err)
   153  		}
   154  
   155  		switch k := key.(type) {
   156  		case *ecdsa.PublicKey:
   157  			return &ecdsaPublicKey{k}, nil
   158  		default:
   159  			return nil, errors.New("public key type not recognized")
   160  		}
   161  	default:
   162  		return ks.searchKeystoreForSKI(ski)
   163  	}
   164  }
   165  
   166  // StoreKey stores the key k in this KeyStore.
   167  // If this KeyStore is read only then the method will fail.
   168  func (ks *fileBasedKeyStore) StoreKey(k bccsp.Key) (err error) {
   169  	if ks.readOnly {
   170  		return errors.New("read only KeyStore")
   171  	}
   172  
   173  	if k == nil {
   174  		return errors.New("invalid key. It must be different from nil")
   175  	}
   176  	switch kk := k.(type) {
   177  	case *ecdsaPrivateKey:
   178  		err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.privKey)
   179  		if err != nil {
   180  			return fmt.Errorf("failed storing ECDSA private key [%s]", err)
   181  		}
   182  
   183  	case *ecdsaPublicKey:
   184  		err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.pubKey)
   185  		if err != nil {
   186  			return fmt.Errorf("failed storing ECDSA public key [%s]", err)
   187  		}
   188  
   189  	case *symmetryPrivateKey:
   190  		err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.privKey)
   191  		if err != nil {
   192  			return fmt.Errorf("failed storing AES key [%s]", err)
   193  		}
   194  
   195  	default:
   196  		return fmt.Errorf("key type not reconigned [%s]", k)
   197  	}
   198  
   199  	return
   200  }
   201  
   202  func (ks *fileBasedKeyStore) searchKeystoreForSKI(ski []byte) (k bccsp.Key, err error) {
   203  	files, _ := ioutil.ReadDir(ks.path)
   204  	for _, f := range files {
   205  		if f.IsDir() {
   206  			continue
   207  		}
   208  
   209  		if f.Size() > (1 << 16) { // 64k, somewhat arbitrary limit, considering even large keys
   210  			continue
   211  		}
   212  
   213  		raw, err := ioutil.ReadFile(filepath.Join(ks.path, f.Name()))
   214  		if err != nil {
   215  			continue
   216  		}
   217  
   218  		key, err := pemToPrivateKey(raw, ks.pwd)
   219  		if err != nil {
   220  			continue
   221  		}
   222  
   223  		switch kk := key.(type) {
   224  		case *ecdsa.PrivateKey:
   225  			k = &ecdsaPrivateKey{kk}
   226  		default:
   227  			continue
   228  		}
   229  
   230  		if !bytes.Equal(k.SKI(), ski) {
   231  			continue
   232  		}
   233  
   234  		return k, nil
   235  	}
   236  	return nil, fmt.Errorf("key with SKI %x not found in %s", ski, ks.path)
   237  }
   238  
   239  func (ks *fileBasedKeyStore) getSuffix(alias string) string {
   240  	files, _ := ioutil.ReadDir(ks.path)
   241  	for _, f := range files {
   242  		if strings.HasPrefix(f.Name(), alias) {
   243  			if strings.HasSuffix(f.Name(), "sk") {
   244  				return "sk"
   245  			}
   246  			if strings.HasSuffix(f.Name(), "pk") {
   247  				return "pk"
   248  			}
   249  			if strings.HasSuffix(f.Name(), "key") {
   250  				return "key"
   251  			}
   252  			break
   253  		}
   254  	}
   255  	return ""
   256  }
   257  
   258  func (ks *fileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error {
   259  	rawKey, err := privateKeyToPEM(privateKey, ks.pwd)
   260  	if err != nil {
   261  		logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err)
   262  		return err
   263  	}
   264  
   265  	err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0o600)
   266  	if err != nil {
   267  		logger.Errorf("Failed storing private key [%s]: [%s]", alias, err)
   268  		return err
   269  	}
   270  
   271  	return nil
   272  }
   273  
   274  func (ks *fileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error {
   275  	rawKey, err := publicKeyToPEM(publicKey, ks.pwd)
   276  	if err != nil {
   277  		logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err)
   278  		return err
   279  	}
   280  
   281  	err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0o600)
   282  	if err != nil {
   283  		logger.Errorf("Failed storing private key [%s]: [%s]", alias, err)
   284  		return err
   285  	}
   286  
   287  	return nil
   288  }
   289  
   290  func (ks *fileBasedKeyStore) storeKey(alias string, key []byte) error {
   291  	pem, err := aesToEncryptedPEM(key, ks.pwd)
   292  	if err != nil {
   293  		logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err)
   294  		return err
   295  	}
   296  
   297  	err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0o600)
   298  	if err != nil {
   299  		logger.Errorf("Failed storing key [%s]: [%s]", alias, err)
   300  		return err
   301  	}
   302  
   303  	return nil
   304  }
   305  
   306  func (ks *fileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) {
   307  	path := ks.getPathForAlias(alias, "sk")
   308  	logger.Debugf("Loading private key [%s] at [%s]...", alias, path)
   309  
   310  	raw, err := ioutil.ReadFile(path)
   311  	if err != nil {
   312  		logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error())
   313  
   314  		return nil, err
   315  	}
   316  
   317  	privateKey, err := pemToPrivateKey(raw, ks.pwd)
   318  	if err != nil {
   319  		logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error())
   320  
   321  		return nil, err
   322  	}
   323  
   324  	return privateKey, nil
   325  }
   326  
   327  func (ks *fileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) {
   328  	path := ks.getPathForAlias(alias, "pk")
   329  	logger.Debugf("Loading public key [%s] at [%s]...", alias, path)
   330  
   331  	raw, err := ioutil.ReadFile(path)
   332  	if err != nil {
   333  		logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error())
   334  
   335  		return nil, err
   336  	}
   337  
   338  	privateKey, err := pemToPublicKey(raw, ks.pwd)
   339  	if err != nil {
   340  		logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error())
   341  
   342  		return nil, err
   343  	}
   344  
   345  	return privateKey, nil
   346  }
   347  
   348  func (ks *fileBasedKeyStore) loadKey(alias string) ([]byte, error) {
   349  	path := ks.getPathForAlias(alias, "key")
   350  	logger.Debugf("Loading key [%s] at [%s]...", alias, path)
   351  
   352  	pem, err := ioutil.ReadFile(path)
   353  	if err != nil {
   354  		logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error())
   355  
   356  		return nil, err
   357  	}
   358  
   359  	key, err := pemToAES(pem, ks.pwd)
   360  	if err != nil {
   361  		logger.Errorf("Failed parsing key [%s]: [%s]", alias, err)
   362  
   363  		return nil, err
   364  	}
   365  
   366  	return key, nil
   367  }
   368  
   369  func (ks *fileBasedKeyStore) createKeyStore() error {
   370  	// Create keystore directory root if it doesn't exist yet
   371  	ksPath := ks.path
   372  	logger.Debugf("Creating KeyStore at [%s]...", ksPath)
   373  
   374  	err := os.MkdirAll(ksPath, 0o755)
   375  	if err != nil {
   376  		return err
   377  	}
   378  
   379  	logger.Debugf("KeyStore created at [%s].", ksPath)
   380  	return nil
   381  }
   382  
   383  func (ks *fileBasedKeyStore) openKeyStore() error {
   384  	if ks.isOpen {
   385  		return nil
   386  	}
   387  	ks.isOpen = true
   388  	logger.Debugf("KeyStore opened at [%s]...done", ks.path)
   389  
   390  	return nil
   391  }
   392  
   393  func (ks *fileBasedKeyStore) getPathForAlias(alias, suffix string) string {
   394  	return filepath.Join(ks.path, alias+"_"+suffix)
   395  }
   396  
   397  func dirExists(path string) (bool, error) {
   398  	_, err := os.Stat(path)
   399  	if err == nil {
   400  		return true, nil
   401  	}
   402  	if os.IsNotExist(err) {
   403  		return false, nil
   404  	}
   405  	return false, err
   406  }
   407  
   408  func dirEmpty(path string) (bool, error) {
   409  	f, err := os.Open(path)
   410  	if err != nil {
   411  		return false, err
   412  	}
   413  	defer f.Close()
   414  
   415  	_, err = f.Readdir(1)
   416  	if err == io.EOF {
   417  		return true, nil
   418  	}
   419  	return false, err
   420  }