github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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  	"crypto/ecdsa"
    12  	"encoding/hex"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	"io/ioutil"
    17  	"os"
    18  	"path/filepath"
    19  	"strings"
    20  	"sync"
    21  
    22  	"github.com/osdi23p228/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(ks.pwd, 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 &aesPrivateKey{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 *aesPrivateKey:
   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  
   204  	files, _ := ioutil.ReadDir(ks.path)
   205  	for _, f := range files {
   206  		if f.IsDir() {
   207  			continue
   208  		}
   209  
   210  		if f.Size() > (1 << 16) { //64k, somewhat arbitrary limit, considering even large keys
   211  			continue
   212  		}
   213  
   214  		raw, err := ioutil.ReadFile(filepath.Join(ks.path, f.Name()))
   215  		if err != nil {
   216  			continue
   217  		}
   218  
   219  		key, err := pemToPrivateKey(raw, ks.pwd)
   220  		if err != nil {
   221  			continue
   222  		}
   223  
   224  		switch kk := key.(type) {
   225  		case *ecdsa.PrivateKey:
   226  			k = &ecdsaPrivateKey{kk}
   227  		default:
   228  			continue
   229  		}
   230  
   231  		if !bytes.Equal(k.SKI(), ski) {
   232  			continue
   233  		}
   234  
   235  		return k, nil
   236  	}
   237  	return nil, fmt.Errorf("key with SKI %x not found in %s", ski, ks.path)
   238  }
   239  
   240  func (ks *fileBasedKeyStore) getSuffix(alias string) string {
   241  	files, _ := ioutil.ReadDir(ks.path)
   242  	for _, f := range files {
   243  		if strings.HasPrefix(f.Name(), alias) {
   244  			if strings.HasSuffix(f.Name(), "sk") {
   245  				return "sk"
   246  			}
   247  			if strings.HasSuffix(f.Name(), "pk") {
   248  				return "pk"
   249  			}
   250  			if strings.HasSuffix(f.Name(), "key") {
   251  				return "key"
   252  			}
   253  			break
   254  		}
   255  	}
   256  	return ""
   257  }
   258  
   259  func (ks *fileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error {
   260  	rawKey, err := privateKeyToPEM(privateKey, ks.pwd)
   261  	if err != nil {
   262  		logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err)
   263  		return err
   264  	}
   265  
   266  	err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0600)
   267  	if err != nil {
   268  		logger.Errorf("Failed storing private key [%s]: [%s]", alias, err)
   269  		return err
   270  	}
   271  
   272  	return nil
   273  }
   274  
   275  func (ks *fileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error {
   276  	rawKey, err := publicKeyToPEM(publicKey, ks.pwd)
   277  	if err != nil {
   278  		logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err)
   279  		return err
   280  	}
   281  
   282  	err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0600)
   283  	if err != nil {
   284  		logger.Errorf("Failed storing private key [%s]: [%s]", alias, err)
   285  		return err
   286  	}
   287  
   288  	return nil
   289  }
   290  
   291  func (ks *fileBasedKeyStore) storeKey(alias string, key []byte) error {
   292  	pem, err := aesToEncryptedPEM(key, ks.pwd)
   293  	if err != nil {
   294  		logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err)
   295  		return err
   296  	}
   297  
   298  	err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0600)
   299  	if err != nil {
   300  		logger.Errorf("Failed storing key [%s]: [%s]", alias, err)
   301  		return err
   302  	}
   303  
   304  	return nil
   305  }
   306  
   307  func (ks *fileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) {
   308  	path := ks.getPathForAlias(alias, "sk")
   309  	logger.Debugf("Loading private key [%s] at [%s]...", alias, path)
   310  
   311  	raw, err := ioutil.ReadFile(path)
   312  	if err != nil {
   313  		logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error())
   314  
   315  		return nil, err
   316  	}
   317  
   318  	privateKey, err := pemToPrivateKey(raw, ks.pwd)
   319  	if err != nil {
   320  		logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error())
   321  
   322  		return nil, err
   323  	}
   324  
   325  	return privateKey, nil
   326  }
   327  
   328  func (ks *fileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) {
   329  	path := ks.getPathForAlias(alias, "pk")
   330  	logger.Debugf("Loading public key [%s] at [%s]...", alias, path)
   331  
   332  	raw, err := ioutil.ReadFile(path)
   333  	if err != nil {
   334  		logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error())
   335  
   336  		return nil, err
   337  	}
   338  
   339  	privateKey, err := pemToPublicKey(raw, ks.pwd)
   340  	if err != nil {
   341  		logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error())
   342  
   343  		return nil, err
   344  	}
   345  
   346  	return privateKey, nil
   347  }
   348  
   349  func (ks *fileBasedKeyStore) loadKey(alias string) ([]byte, error) {
   350  	path := ks.getPathForAlias(alias, "key")
   351  	logger.Debugf("Loading key [%s] at [%s]...", alias, path)
   352  
   353  	pem, err := ioutil.ReadFile(path)
   354  	if err != nil {
   355  		logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error())
   356  
   357  		return nil, err
   358  	}
   359  
   360  	key, err := pemToAES(pem, ks.pwd)
   361  	if err != nil {
   362  		logger.Errorf("Failed parsing key [%s]: [%s]", alias, err)
   363  
   364  		return nil, err
   365  	}
   366  
   367  	return key, nil
   368  }
   369  
   370  func (ks *fileBasedKeyStore) createKeyStore() error {
   371  	// Create keystore directory root if it doesn't exist yet
   372  	ksPath := ks.path
   373  	logger.Debugf("Creating KeyStore at [%s]...", ksPath)
   374  
   375  	err := os.MkdirAll(ksPath, 0755)
   376  	if err != nil {
   377  		return err
   378  	}
   379  
   380  	logger.Debugf("KeyStore created at [%s].", ksPath)
   381  	return nil
   382  }
   383  
   384  func (ks *fileBasedKeyStore) openKeyStore() error {
   385  	if ks.isOpen {
   386  		return nil
   387  	}
   388  	ks.isOpen = true
   389  	logger.Debugf("KeyStore opened at [%s]...done", ks.path)
   390  
   391  	return nil
   392  }
   393  
   394  func (ks *fileBasedKeyStore) getPathForAlias(alias, suffix string) string {
   395  	return filepath.Join(ks.path, alias+"_"+suffix)
   396  }
   397  
   398  func dirExists(path string) (bool, error) {
   399  	_, err := os.Stat(path)
   400  	if err == nil {
   401  		return true, nil
   402  	}
   403  	if os.IsNotExist(err) {
   404  		return false, nil
   405  	}
   406  	return false, err
   407  }
   408  
   409  func dirEmpty(path string) (bool, error) {
   410  	f, err := os.Open(path)
   411  	if err != nil {
   412  		return false, err
   413  	}
   414  	defer f.Close()
   415  
   416  	_, err = f.Readdir(1)
   417  	if err == io.EOF {
   418  		return true, nil
   419  	}
   420  	return false, err
   421  }