diff --git a/core/crypto/bccsp/factory/factory.go b/core/crypto/bccsp/factory/factory.go index 69f81cddcd4..0245917008c 100644 --- a/core/crypto/bccsp/factory/factory.go +++ b/core/crypto/bccsp/factory/factory.go @@ -20,8 +20,10 @@ import ( "fmt" "sync" + "os" + "github.com/hyperledger/fabric/core/crypto/bccsp" - "github.com/spf13/viper" + "github.com/hyperledger/fabric/core/crypto/bccsp/sw" ) var ( @@ -104,12 +106,7 @@ func initFactoriesMap() error { } func createDefaultBCCSP() (bccsp.BCCSP, error) { - defaultBCCSPFactoryName := viper.GetString("bccsp.default") - if defaultBCCSPFactoryName == "" { - defaultBCCSPFactoryName = SoftwareBasedFactoryName - } - - return getBCCSPInternal(&DefaultOpts{defaultBCCSPFactoryName, false}) + return sw.NewDefaultSecurityLevel(os.TempDir()) } func getBCCSPInternal(opts Opts) (bccsp.BCCSP, error) { diff --git a/core/crypto/bccsp/factory/factory_test.go b/core/crypto/bccsp/factory/factory_test.go index c3ccae270ad..d6b3aac7c25 100644 --- a/core/crypto/bccsp/factory/factory_test.go +++ b/core/crypto/bccsp/factory/factory_test.go @@ -15,7 +15,12 @@ limitations under the License. */ package factory -import "testing" +import ( + "os" + "testing" + + "github.com/hyperledger/fabric/core/crypto/bccsp/sw" +) func TestGetDefault(t *testing.T) { bccsp, err := GetDefault() @@ -28,12 +33,17 @@ func TestGetDefault(t *testing.T) { } func TestGetBCCPEphemeral(t *testing.T) { - bccsp1, err := GetBCCSP(&SwOpts{EphemeralFlag: true}) + ks := &sw.FileBasedKeyStore{} + if err := ks.Init(nil, os.TempDir(), false); err != nil { + t.Fatalf("Failed initializing key store [%s]", err) + } + + bccsp1, err := GetBCCSP(&SwOpts{Ephemeral_: true, SecLevel: 256, HashFamily: "SHA2", KeyStore: ks}) if err != nil { t.Fatalf("Failed getting ephemeral software-based BCCSP [%s]", err) } - bccsp2, err := GetBCCSP(&SwOpts{EphemeralFlag: true}) + bccsp2, err := GetBCCSP(&SwOpts{Ephemeral_: true, SecLevel: 256, HashFamily: "SHA2", KeyStore: ks}) if err != nil { t.Fatalf("Failed getting ephemeral software-based BCCSP [%s]", err) } @@ -44,12 +54,17 @@ func TestGetBCCPEphemeral(t *testing.T) { } func TestGetBCCP2Ephemeral(t *testing.T) { - bccsp1, err := GetBCCSP(&SwOpts{EphemeralFlag: false}) + ks := &sw.FileBasedKeyStore{} + if err := ks.Init(nil, os.TempDir(), false); err != nil { + t.Fatalf("Failed initializing key store [%s]", err) + } + + bccsp1, err := GetBCCSP(&SwOpts{Ephemeral_: false, SecLevel: 256, HashFamily: "SHA2", KeyStore: ks}) if err != nil { t.Fatalf("Failed getting non-ephemeral software-based BCCSP [%s]", err) } - bccsp2, err := GetBCCSP(&SwOpts{EphemeralFlag: false}) + bccsp2, err := GetBCCSP(&SwOpts{Ephemeral_: false, SecLevel: 256, HashFamily: "SHA2", KeyStore: ks}) if err != nil { t.Fatalf("Failed getting non-ephemeral software-based BCCSP [%s]", err) } diff --git a/core/crypto/bccsp/factory/sw_factory.go b/core/crypto/bccsp/factory/swfactory.go similarity index 83% rename from core/crypto/bccsp/factory/sw_factory.go rename to core/crypto/bccsp/factory/swfactory.go index 7855b2174d5..0d56588c34c 100644 --- a/core/crypto/bccsp/factory/sw_factory.go +++ b/core/crypto/bccsp/factory/swfactory.go @@ -52,20 +52,28 @@ func (f *SWFactory) Get(opts Opts) (bccsp.BCCSP, error) { return nil, fmt.Errorf("Invalid Provider Name [%s]. Opts must refer to [%s].", opts.FactoryName(), f.Name()) } + swOpts, ok := opts.(*SwOpts) + if !ok { + return nil, errors.New("Invalid opts. They must be of type SwOpts.") + } + if !opts.Ephemeral() { f.initOnce.Do(func() { - f.bccsp, f.err = sw.NewDefaultSecurityLevel() + f.bccsp, f.err = sw.New(swOpts.SecLevel, swOpts.HashFamily, swOpts.KeyStore) return }) return f.bccsp, f.err } - return sw.NewDefaultSecurityLevel() + return sw.New(swOpts.SecLevel, swOpts.HashFamily, swOpts.KeyStore) } // SwOpts contains options for the SWFactory type SwOpts struct { - EphemeralFlag bool + Ephemeral_ bool + SecLevel int + HashFamily string + KeyStore bccsp.KeyStore } // FactoryName returns the name of the provider @@ -75,5 +83,5 @@ func (o *SwOpts) FactoryName() string { // Ephemeral returns true if the CSP has to be ephemeral, false otherwise func (o *SwOpts) Ephemeral() bool { - return o.EphemeralFlag + return o.Ephemeral_ } diff --git a/core/crypto/bccsp/keystore.go b/core/crypto/bccsp/keystore.go new file mode 100644 index 00000000000..bb1ca6c8c24 --- /dev/null +++ b/core/crypto/bccsp/keystore.go @@ -0,0 +1,34 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package bccsp + +// KeyStore represents a storage system for cryptographic keys. +// It allows to store and retrieve bccsp.Key objects. +// The KeyStore can be read only, in that case StoreKey will return +// an error. +type KeyStore interface { + + // ReadOnly returns true if this KeyStore is read only, false otherwise. + // If ReadOnly is true then StoreKey will fail. + ReadOnly() bool + + // GetKey returns a key object whose SKI is the one passed. + GetKey(ski []byte) (k Key, err error) + + // StoreKey stores the key k in this KeyStore. + // If this KeyStore is read only then the method will fail. + StoreKey(k Key) (err error) +} diff --git a/core/crypto/bccsp/signer/signer_test.go b/core/crypto/bccsp/signer/signer_test.go index 0424056a245..3bbfb72ff63 100644 --- a/core/crypto/bccsp/signer/signer_test.go +++ b/core/crypto/bccsp/signer/signer_test.go @@ -22,7 +22,6 @@ import ( "github.com/hyperledger/fabric/core/crypto/bccsp" "github.com/hyperledger/fabric/core/crypto/bccsp/sw" - "github.com/spf13/viper" ) var ( @@ -31,10 +30,8 @@ var ( func getBCCSP(t *testing.T) bccsp.BCCSP { if swBCCSPInstance == nil { - viper.Set("security.bccsp.default.keyStorePath", os.TempDir()) - var err error - swBCCSPInstance, err = sw.NewDefaultSecurityLevel() + swBCCSPInstance, err = sw.NewDefaultSecurityLevel(os.TempDir()) if err != nil { t.Fatalf("Failed initializing key store [%s]", err) } diff --git a/core/crypto/bccsp/sw/conf.go b/core/crypto/bccsp/sw/conf.go index d044a398b8e..2d4eaff95d2 100644 --- a/core/crypto/bccsp/sw/conf.go +++ b/core/crypto/bccsp/sw/conf.go @@ -16,57 +16,24 @@ limitations under the License. package sw import ( - "errors" - "path/filepath" - - "os" - "crypto/elliptic" "crypto/sha256" "crypto/sha512" "fmt" "hash" - "github.com/spf13/viper" "golang.org/x/crypto/sha3" ) type config struct { - keystorePath string + keyStorePath string securityLevel int hashFamily string - configurationPathProperty string - ellipticCurve elliptic.Curve - hashFunction func() hash.Hash - aesBitLength int - rsaBitLength int -} - -func (conf *config) init(securityLevel int, hashFamily string) error { - // Set security level - err := conf.setSecurityLevel(securityLevel, hashFamily) - if err != nil { - return fmt.Errorf("Failed initliazing security level [%s]", err) - } - // Set ks path - conf.configurationPathProperty = "security.bccsp.default.keyStorePath" - - // Check mandatory fields - var rootPath string - if err := conf.checkProperty(conf.configurationPathProperty); err != nil { - logger.Warning("'security.bccsp.default.keyStorePath' not set. Using the default directory [%s] for temporary files", os.TempDir()) - rootPath = os.TempDir() - } else { - rootPath = viper.GetString(conf.configurationPathProperty) - } - logger.Infof("Root Path [%s]", rootPath) - // Set configuration path - rootPath = filepath.Join(rootPath, "crypto") - - conf.keystorePath = filepath.Join(rootPath, "ks") - - return nil + ellipticCurve elliptic.Curve + hashFunction func() hash.Hash + aesBitLength int + rsaBitLength int } func (conf *config) setSecurityLevel(securityLevel int, hashFamily string) (err error) { @@ -116,19 +83,3 @@ func (conf *config) setSecurityLevelSHA3(level int) (err error) { } return } - -func (conf *config) checkProperty(property string) error { - res := viper.GetString(property) - if res == "" { - return errors.New("Property not specified in configuration file. Please check that property is set: " + property) - } - return nil -} - -func (conf *config) getKeyStorePath() string { - return conf.keystorePath -} - -func (conf *config) getPathForAlias(alias, suffix string) string { - return filepath.Join(conf.getKeyStorePath(), alias+"_"+suffix) -} diff --git a/core/crypto/bccsp/sw/fileks.go b/core/crypto/bccsp/sw/fileks.go new file mode 100644 index 00000000000..288b7223cd5 --- /dev/null +++ b/core/crypto/bccsp/sw/fileks.go @@ -0,0 +1,396 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package sw + +import ( + "io/ioutil" + "os" + "sync" + + "github.com/hyperledger/fabric/core/crypto/utils" + + "errors" + "strings" + + "crypto/ecdsa" + "crypto/rsa" + "encoding/hex" + "fmt" + "path/filepath" + + "github.com/hyperledger/fabric/core/crypto/bccsp" + "github.com/hyperledger/fabric/core/crypto/primitives" +) + +// FileBasedKeyStore is a folder-based KeyStore. +// Each key is stored in a separated file whose name contains the key's SKI +// and flags to identity the key's type. All the keys are stored in +// a folder whose path is provided at initialization time. +// The KeyStore can be initialized with a password, this password +// is used to encrypt and decrypt the files storing the keys. +// A KeyStore can be read only to avoid the overwriting of keys. +type FileBasedKeyStore struct { + path string + + readOnly bool + isOpen bool + + pwd []byte + + // Sync + m sync.Mutex +} + +// Init initializes this KeyStore with a password, a path to a folder +// where the keys are stored and a read only flag. +// Each key is stored in a separated file whose name contains the key's SKI +// and flags to identity the key's type. +// If the KeyStore is initialized with a password, this password +// is used to encrypt and decrypt the files storing the keys. +// The pwd can be nil for non-encrypted KeyStores. If an encrypted +// key-store is initialized without a password, then retrieving keys from the +// KeyStore will fail. +// A KeyStore can be read only to avoid the overwriting of keys. +func (ks *FileBasedKeyStore) Init(pwd []byte, path string, readOnly bool) error { + // Validate inputs + // pwd can be nil + + if len(path) == 0 { + return errors.New("An invalid KeyStore path provided. Path cannot be an empty string.") + } + + ks.m.Lock() + defer ks.m.Unlock() + + if ks.isOpen { + return errors.New("KeyStore already initilized.") + } + + ks.path = path + ks.pwd = utils.Clone(pwd) + + err := ks.createKeyStoreIfNotExists() + if err != nil { + return err + } + + err = ks.openKeyStore() + if err != nil { + return err + } + + ks.readOnly = readOnly + + return nil +} + +// ReadOnly returns true if this KeyStore is read only, false otherwise. +// If ReadOnly is true then StoreKey will fail. +func (ks *FileBasedKeyStore) ReadOnly() bool { + return ks.readOnly +} + +// GetKey returns a key object whose SKI is the one passed. +func (ks *FileBasedKeyStore) GetKey(ski []byte) (k bccsp.Key, err error) { + // Validate arguments + if len(ski) == 0 { + return nil, errors.New("Invalid SKI. Cannot be of zero length.") + } + + suffix := ks.getSuffix(hex.EncodeToString(ski)) + + switch suffix { + case "key": + // Load the key + key, err := ks.loadKey(hex.EncodeToString(ski)) + if err != nil { + return nil, fmt.Errorf("Failed loading key [%x] [%s]", ski, err) + } + + return &aesPrivateKey{key, false}, nil + case "sk": + // Load the private key + key, err := ks.loadPrivateKey(hex.EncodeToString(ski)) + if err != nil { + return nil, fmt.Errorf("Failed loading key [%x] [%s]", ski, err) + } + + switch key.(type) { + case *ecdsa.PrivateKey: + return &ecdsaPrivateKey{key.(*ecdsa.PrivateKey)}, nil + case *rsa.PrivateKey: + return &rsaPrivateKey{key.(*rsa.PrivateKey)}, nil + default: + return nil, errors.New("Key type not recognized") + } + default: + return nil, errors.New("Key not recognized") + } +} + +// StoreKey stores the key k in this KeyStore. +// If this KeyStore is read only then the method will fail. +func (ks *FileBasedKeyStore) StoreKey(k bccsp.Key) (err error) { + if ks.readOnly { + return errors.New("Read only KeyStore.") + } + + if k == nil { + return errors.New("Invalid key. It must be different from nil.") + } + switch k.(type) { + case *ecdsaPrivateKey: + kk := k.(*ecdsaPrivateKey) + + err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.k) + if err != nil { + return fmt.Errorf("Failed storing ECDSA private key [%s]", err) + } + + case *ecdsaPublicKey: + kk := k.(*ecdsaPublicKey) + + err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.k) + if err != nil { + return fmt.Errorf("Failed storing ECDSA public key [%s]", err) + } + + case *rsaPrivateKey: + kk := k.(*rsaPrivateKey) + + err = ks.storePrivateKey(hex.EncodeToString(k.SKI()), kk.k) + if err != nil { + return fmt.Errorf("Failed storing RSA private key [%s]", err) + } + + case *rsaPublicKey: + kk := k.(*rsaPublicKey) + + err = ks.storePublicKey(hex.EncodeToString(k.SKI()), kk.k) + if err != nil { + return fmt.Errorf("Failed storing RSA public key [%s]", err) + } + + case *aesPrivateKey: + kk := k.(*aesPrivateKey) + + err = ks.storeKey(hex.EncodeToString(k.SKI()), kk.k) + if err != nil { + return fmt.Errorf("Failed storing AES key [%s]", err) + } + + default: + return fmt.Errorf("Key type not reconigned [%s]", k) + } + + return +} + +func (ks *FileBasedKeyStore) getSuffix(alias string) string { + files, _ := ioutil.ReadDir(ks.path) + for _, f := range files { + if strings.HasPrefix(f.Name(), alias) { + if strings.HasSuffix(f.Name(), "sk") { + return "sk" + } + if strings.HasSuffix(f.Name(), "pk") { + return "pk" + } + if strings.HasSuffix(f.Name(), "key") { + return "key" + } + break + } + } + return "" +} + +func (ks *FileBasedKeyStore) storePrivateKey(alias string, privateKey interface{}) error { + if ks.readOnly { + return errors.New("Read only KeyStore.") + } + + rawKey, err := primitives.PrivateKeyToPEM(privateKey, ks.pwd) + if err != nil { + logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err) + return err + } + + err = ioutil.WriteFile(ks.getPathForAlias(alias, "sk"), rawKey, 0700) + if err != nil { + logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) + return err + } + + return nil +} + +func (ks *FileBasedKeyStore) storePublicKey(alias string, publicKey interface{}) error { + if ks.readOnly { + return errors.New("Read only KeyStore.") + } + + rawKey, err := primitives.PublicKeyToPEM(publicKey, ks.pwd) + if err != nil { + logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err) + return err + } + + err = ioutil.WriteFile(ks.getPathForAlias(alias, "pk"), rawKey, 0700) + if err != nil { + logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) + return err + } + + return nil +} + +func (ks *FileBasedKeyStore) storeKey(alias string, key []byte) error { + if ks.readOnly { + return errors.New("Read only KeyStore.") + } + + pem, err := primitives.AEStoEncryptedPEM(key, ks.pwd) + if err != nil { + logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err) + return err + } + + err = ioutil.WriteFile(ks.getPathForAlias(alias, "key"), pem, 0700) + if err != nil { + logger.Errorf("Failed storing key [%s]: [%s]", alias, err) + return err + } + + return nil +} + +func (ks *FileBasedKeyStore) loadPrivateKey(alias string) (interface{}, error) { + path := ks.getPathForAlias(alias, "sk") + logger.Debugf("Loading private key [%s] at [%s]...", alias, path) + + raw, err := ioutil.ReadFile(path) + if err != nil { + logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error()) + + return nil, err + } + + privateKey, err := primitives.PEMtoPrivateKey(raw, ks.pwd) + if err != nil { + logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) + + return nil, err + } + + return privateKey, nil +} + +func (ks *FileBasedKeyStore) loadPublicKey(alias string) (interface{}, error) { + path := ks.getPathForAlias(alias, "pk") + logger.Debugf("Loading public key [%s] at [%s]...", alias, path) + + raw, err := ioutil.ReadFile(path) + if err != nil { + logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error()) + + return nil, err + } + + privateKey, err := primitives.PEMtoPublicKey(raw, ks.pwd) + if err != nil { + logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) + + return nil, err + } + + return privateKey, nil +} + +func (ks *FileBasedKeyStore) loadKey(alias string) ([]byte, error) { + path := ks.getPathForAlias(alias, "key") + logger.Debugf("Loading key [%s] at [%s]...", alias, path) + + pem, err := ioutil.ReadFile(path) + if err != nil { + logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error()) + + return nil, err + } + + key, err := primitives.PEMtoAES(pem, ks.pwd) + if err != nil { + logger.Errorf("Failed parsing key [%s]: [%s]", alias, err) + + return nil, err + } + + return key, nil +} + +func (ks *FileBasedKeyStore) close() error { + ks.isOpen = false + logger.Debug("Closing keystore...done!") + return nil +} + +func (ks *FileBasedKeyStore) createKeyStoreIfNotExists() error { + // Check keystore directory + ksPath := ks.path + missing, err := utils.DirMissingOrEmpty(ksPath) + logger.Infof("KeyStore path [%s] missing [%t]: [%s]", ksPath, missing, utils.ErrToString(err)) + + if missing { + err := ks.createKeyStore() + if err != nil { + logger.Errorf("Failed creating KeyStore At [%s]: [%s]", ksPath, err.Error()) + return nil + } + } + + return nil +} + +func (ks *FileBasedKeyStore) createKeyStore() error { + // Create keystore directory root if it doesn't exist yet + ksPath := ks.path + logger.Debugf("Creating KeyStore at [%s]...", ksPath) + + os.MkdirAll(ksPath, 0755) + + logger.Debugf("KeyStore created at [%s].", ksPath) + return nil +} + +func (ks *FileBasedKeyStore) deleteKeyStore() error { + logger.Debugf("Removing KeyStore at [%s].", ks.path) + + return os.RemoveAll(ks.path) +} + +func (ks *FileBasedKeyStore) openKeyStore() error { + if ks.isOpen { + return nil + } + + logger.Debugf("KeyStore opened at [%s]...done", ks.path) + + return nil +} + +func (ks *FileBasedKeyStore) getPathForAlias(alias, suffix string) string { + return filepath.Join(ks.path, alias+"_"+suffix) +} diff --git a/core/crypto/bccsp/sw/impl.go b/core/crypto/bccsp/sw/impl.go index 0aaafb34e94..451b3f02db3 100644 --- a/core/crypto/bccsp/sw/impl.go +++ b/core/crypto/bccsp/sw/impl.go @@ -19,7 +19,6 @@ import ( "crypto/ecdsa" "crypto/rand" "encoding/asn1" - "encoding/hex" "errors" "fmt" "math/big" @@ -43,25 +42,32 @@ var ( ) // NewDefaultSecurityLevel returns a new instance of the software-based BCCSP -// at security level 256 and hash family SHA2 -func NewDefaultSecurityLevel() (bccsp.BCCSP, error) { - return New(256, "SHA2") +// at security level 256, hash family SHA2 and using FolderBasedKeyStore as keystore. +func NewDefaultSecurityLevel(keyStorePath string) (bccsp.BCCSP, error) { + ks := &FileBasedKeyStore{} + if err := ks.Init(nil, keyStorePath, false); err != nil { + return nil, fmt.Errorf("Failed initializing key store [%s]", err) + } + + return New(256, "SHA2", ks) } // New returns a new instance of the software-based BCCSP -// set at the passed security level and hash family. -func New(securityLevel int, hashFamily string) (bccsp.BCCSP, error) { +// set at the passed security level, hash family and keystore. +func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { + // Init config conf := &config{} - err := conf.init(securityLevel, hashFamily) + err := conf.setSecurityLevel(securityLevel, hashFamily) if err != nil { return nil, fmt.Errorf("Failed initializing configuration [%s]", err) } - ks := &keyStore{} - if err := ks.init(nil, conf); err != nil { - return nil, fmt.Errorf("Failed initializing key store [%s]", err) + // Check keystore + if keyStore == nil { + return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil.") } - return &impl{conf, ks}, nil + + return &impl{conf, keyStore}, nil } // SoftwareBasedBCCSP is the software-based implementation of the BCCSP. @@ -70,7 +76,7 @@ func New(securityLevel int, hashFamily string) (bccsp.BCCSP, error) { // It can be configured via viper. type impl struct { conf *config - ks *keyStore + ks bccsp.KeyStore } // KeyGen generates a key using opts. @@ -93,7 +99,7 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePrivateKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -112,7 +118,7 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storeKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing AES key [%s]", err) } @@ -131,7 +137,7 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePrivateKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing AES key [%s]", err) } @@ -203,7 +209,7 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePrivateKey(hex.EncodeToString(reRandomizedKey.SKI()), tempSK) + err = csp.ks.StoreKey(reRandomizedKey) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -234,7 +240,7 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storeKey(hex.EncodeToString(hmacedKey.SKI()), hmacedKey.k) + err = csp.ks.StoreKey(hmacedKey) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -253,7 +259,7 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storeKey(hex.EncodeToString(hmacedKey.SKI()), hmacedKey.k) + err = csp.ks.StoreKey(hmacedKey) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -300,7 +306,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storeKey(hex.EncodeToString(aesK.SKI()), aesK.k) + err = csp.ks.StoreKey(aesK) if err != nil { return nil, fmt.Errorf("Failed storing AES key [%s]", err) } @@ -323,7 +329,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storeKey(hex.EncodeToString(aesK.SKI()), aesK.k) + err = csp.ks.StoreKey(aesK) if err != nil { return nil, fmt.Errorf("Failed storing AES key [%s]", err) } @@ -356,7 +362,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePublicKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -389,7 +395,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePrivateKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -408,7 +414,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePublicKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -427,7 +433,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // If the key is not Ephemeral, store it. if !opts.Ephemeral() { // Store the key - err = csp.ks.storePublicKey(hex.EncodeToString(k.SKI()), lowLevelKey) + err = csp.ks.StoreKey(k) if err != nil { return nil, fmt.Errorf("Failed storing ECDSA key [%s]", err) } @@ -460,40 +466,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K // GetKey returns the key this CSP associates to // the Subject Key Identifier ski. func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { - // Validate arguments - if len(ski) == 0 { - return nil, errors.New("Invalid SKI. Cannot be of zero length.") - } - - suffix := csp.ks.getSuffix(hex.EncodeToString(ski)) - - switch suffix { - case "key": - // Load the key - key, err := csp.ks.loadKey(hex.EncodeToString(ski)) - if err != nil { - return nil, fmt.Errorf("Failed loading key [%x] [%s]", ski, err) - } - - return &aesPrivateKey{key, false}, nil - case "sk": - // Load the private key - key, err := csp.ks.loadPrivateKey(hex.EncodeToString(ski)) - if err != nil { - return nil, fmt.Errorf("Failed loading key [%x] [%s]", ski, err) - } - - switch key.(type) { - case *ecdsa.PrivateKey: - return &ecdsaPrivateKey{key.(*ecdsa.PrivateKey)}, nil - case *rsa.PrivateKey: - return &rsaPrivateKey{key.(*rsa.PrivateKey)}, nil - default: - return nil, errors.New("Key type not recognized") - } - default: - return nil, errors.New("Key not recognized") - } + return csp.ks.GetKey(ski) } // Hash hashes messages msg using options opts. diff --git a/core/crypto/bccsp/sw/impl_test.go b/core/crypto/bccsp/sw/impl_test.go index 02b000baf2f..78708ca8bde 100644 --- a/core/crypto/bccsp/sw/impl_test.go +++ b/core/crypto/bccsp/sw/impl_test.go @@ -38,7 +38,6 @@ import ( "github.com/hyperledger/fabric/core/crypto/bccsp" "github.com/hyperledger/fabric/core/crypto/bccsp/signer" "github.com/hyperledger/fabric/core/crypto/primitives" - "github.com/spf13/viper" ) var ( @@ -47,12 +46,10 @@ var ( func getBCCSP(t *testing.T) bccsp.BCCSP { if swBCCSPInstance == nil { - viper.Set("security.bccsp.default.keyStorePath", os.TempDir()) - var err error - swBCCSPInstance, err = NewDefaultSecurityLevel() + swBCCSPInstance, err = NewDefaultSecurityLevel(os.TempDir()) if err != nil { - t.Fatalf("Failed initializing key store [%s]", err) + t.Fatalf("Failed initializing KeyStore [%s]", err) } } diff --git a/core/crypto/bccsp/sw/ks.go b/core/crypto/bccsp/sw/ks.go deleted file mode 100644 index 03e2cae4b03..00000000000 --- a/core/crypto/bccsp/sw/ks.go +++ /dev/null @@ -1,251 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package sw - -import ( - "io/ioutil" - "os" - "sync" - - "github.com/hyperledger/fabric/core/crypto/utils" - - "errors" - "strings" - - "github.com/hyperledger/fabric/core/crypto/primitives" -) - -type keyStore struct { - conf *config - - isOpen bool - - pwd []byte - - // Sync - m sync.Mutex -} - -func (ks *keyStore) init(pwd []byte, conf *config) error { - // Validate inputs - // pwd can be nil - - if conf == nil { - return errors.New("Invalid config. Nil.") - } - - ks.m.Lock() - defer ks.m.Unlock() - - if ks.isOpen { - return errors.New("Keystore already Initilized.") - } - - ks.conf = conf - ks.pwd = utils.Clone(pwd) - - err := ks.createKeyStoreIfNotExists() - if err != nil { - return err - } - - err = ks.openKeyStore() - if err != nil { - return err - } - - return nil -} - -func (ks *keyStore) getSuffix(alias string) string { - files, _ := ioutil.ReadDir(ks.conf.getKeyStorePath()) - for _, f := range files { - if strings.HasPrefix(f.Name(), alias) { - if strings.HasSuffix(f.Name(), "sk") { - return "sk" - } - if strings.HasSuffix(f.Name(), "pk") { - return "pk" - } - if strings.HasSuffix(f.Name(), "key") { - return "key" - } - break - } - } - return "" -} - -func (ks *keyStore) storePrivateKey(alias string, privateKey interface{}) error { - rawKey, err := primitives.PrivateKeyToPEM(privateKey, ks.pwd) - if err != nil { - logger.Errorf("Failed converting private key to PEM [%s]: [%s]", alias, err) - return err - } - - err = ioutil.WriteFile(ks.conf.getPathForAlias(alias, "sk"), rawKey, 0700) - if err != nil { - logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) - return err - } - - return nil -} - -func (ks *keyStore) loadPrivateKey(alias string) (interface{}, error) { - path := ks.conf.getPathForAlias(alias, "sk") - logger.Debugf("Loading private key [%s] at [%s]...", alias, path) - - raw, err := ioutil.ReadFile(path) - if err != nil { - logger.Errorf("Failed loading private key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - privateKey, err := primitives.PEMtoPrivateKey(raw, ks.pwd) - if err != nil { - logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - return privateKey, nil -} - -func (ks *keyStore) storePublicKey(alias string, publicKey interface{}) error { - rawKey, err := primitives.PublicKeyToPEM(publicKey, ks.pwd) - if err != nil { - logger.Errorf("Failed converting public key to PEM [%s]: [%s]", alias, err) - return err - } - - err = ioutil.WriteFile(ks.conf.getPathForAlias(alias, "pk"), rawKey, 0700) - if err != nil { - logger.Errorf("Failed storing private key [%s]: [%s]", alias, err) - return err - } - - return nil -} - -func (ks *keyStore) loadPublicKey(alias string) (interface{}, error) { - path := ks.conf.getPathForAlias(alias, "pk") - logger.Debugf("Loading public key [%s] at [%s]...", alias, path) - - raw, err := ioutil.ReadFile(path) - if err != nil { - logger.Errorf("Failed loading public key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - privateKey, err := primitives.PEMtoPublicKey(raw, ks.pwd) - if err != nil { - logger.Errorf("Failed parsing private key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - return privateKey, nil -} - -func (ks *keyStore) storeKey(alias string, key []byte) error { - pem, err := primitives.AEStoEncryptedPEM(key, ks.pwd) - if err != nil { - logger.Errorf("Failed converting key to PEM [%s]: [%s]", alias, err) - return err - } - - err = ioutil.WriteFile(ks.conf.getPathForAlias(alias, "key"), pem, 0700) - if err != nil { - logger.Errorf("Failed storing key [%s]: [%s]", alias, err) - return err - } - - return nil -} - -func (ks *keyStore) loadKey(alias string) ([]byte, error) { - path := ks.conf.getPathForAlias(alias, "key") - logger.Debugf("Loading key [%s] at [%s]...", alias, path) - - pem, err := ioutil.ReadFile(path) - if err != nil { - logger.Errorf("Failed loading key [%s]: [%s].", alias, err.Error()) - - return nil, err - } - - key, err := primitives.PEMtoAES(pem, ks.pwd) - if err != nil { - logger.Errorf("Failed parsing key [%s]: [%s]", alias, err) - - return nil, err - } - - return key, nil -} - -func (ks *keyStore) close() error { - ks.isOpen = false - logger.Debug("Closing keystore...done!") - return nil -} - -func (ks *keyStore) createKeyStoreIfNotExists() error { - // Check keystore directory - ksPath := ks.conf.getKeyStorePath() - missing, err := utils.DirMissingOrEmpty(ksPath) - logger.Infof("Keystore path [%s] missing [%t]: [%s]", ksPath, missing, utils.ErrToString(err)) - - if missing { - err := ks.createKeyStore() - if err != nil { - logger.Errorf("Failed creating ks At [%s]: [%s]", ksPath, err.Error()) - return nil - } - } - - return nil -} - -func (ks *keyStore) createKeyStore() error { - // Create keystore directory root if it doesn't exist yet - ksPath := ks.conf.getKeyStorePath() - logger.Debugf("Creating Keystore at [%s]...", ksPath) - - os.MkdirAll(ksPath, 0755) - - logger.Debugf("Keystore created at [%s].", ksPath) - return nil -} - -func (ks *keyStore) deleteKeyStore() error { - logger.Debugf("Removing KeyStore at [%s].", ks.conf.getKeyStorePath()) - - return os.RemoveAll(ks.conf.getKeyStorePath()) -} - -func (ks *keyStore) openKeyStore() error { - if ks.isOpen { - return nil - } - - logger.Debugf("Keystore opened at [%s]...done", ks.conf.getKeyStorePath()) - - return nil -}