Skip to content

Commit

Permalink
BCCSP KeyStore
Browse files Browse the repository at this point in the history
This change-set introduce the concept of KeyStore at the BCCSP level.
A KeyStore represents a storage system for cryptographic keys.
It allows to store and retrieve bccsp.Key objects. The key store can be
read only, in that case storing a key will return an error.
Now, to initialize a software-based BCCSP, a key store must be specified.
A file based keystore is provided.

In addition, all the dependencies from viper has been removed.
In order to do that, some assumptions has been made on default
security level. The organization of this paramenters will be better
addressed in a subsequent change-set.

This change-set comes in the context of:
https://jira.hyperledger.org/browse/FAB-354

Change-Id: I7e96eea7e5e89ecec86863ebc11b919d29c0019a
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
  • Loading branch information
adecaro committed Nov 23, 2016
1 parent 68aef4e commit 2013daa
Show file tree
Hide file tree
Showing 10 changed files with 505 additions and 388 deletions.
11 changes: 4 additions & 7 deletions core/crypto/bccsp/factory/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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) {
Expand Down
25 changes: 20 additions & 5 deletions core/crypto/bccsp/factory/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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_
}
34 changes: 34 additions & 0 deletions core/crypto/bccsp/keystore.go
Original file line number Diff line number Diff line change
@@ -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)
}
5 changes: 1 addition & 4 deletions core/crypto/bccsp/signer/signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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)
}
Expand Down
59 changes: 5 additions & 54 deletions core/crypto/bccsp/sw/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}

0 comments on commit 2013daa

Please sign in to comment.