From ab83a2e4623c0a7be02d468810d6aeb51f432f38 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Mon, 24 Apr 2017 11:31:32 -0400 Subject: [PATCH] [FAB-864] Vendor BCCSP from fabric to fabric-ca Pickup https://gerrit.hyperledger.org/r/#/c/8103 Change-Id: I24feed05683137ac47365486899c979b379bf156 Signed-off-by: Volodymyr Paprotski --- .../fabric/bccsp/factory/factory.go | 71 +----- .../fabric/bccsp/factory/nopkcs11.go | 85 +++++++ .../hyperledger/fabric/bccsp/factory/opts.go | 6 - .../fabric/bccsp/factory/pkcs11.go | 98 ++++++++ .../fabric/bccsp/factory/pkcs11factory.go | 30 +-- .../fabric/bccsp/factory/swfactory.go | 8 +- .../hyperledger/fabric/bccsp/hashopts.go | 17 ++ .../hyperledger/fabric/bccsp/opts.go | 5 + .../hyperledger/fabric/bccsp/pkcs11/conf.go | 27 ++ .../hyperledger/fabric/bccsp/pkcs11/ecdsa.go | 9 +- .../hyperledger/fabric/bccsp/pkcs11/impl.go | 144 ++++++++--- .../hyperledger/fabric/bccsp/pkcs11/pkcs11.go | 161 ++++++------ .../hyperledger/fabric/bccsp/sw/impl.go | 4 +- .../hyperledger/fabric/bccsp/utils/io.go | 2 +- .../hyperledger/fabric/bccsp/utils/keys.go | 111 ++++++-- .../fabric/common/flogging/logging.go | 237 ++++++++++++++++++ vendor/vendor.json | 12 +- 17 files changed, 785 insertions(+), 242 deletions(-) create mode 100644 vendor/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go create mode 100644 vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go create mode 100644 vendor/github.com/hyperledger/fabric/common/flogging/logging.go diff --git a/vendor/github.com/hyperledger/fabric/bccsp/factory/factory.go b/vendor/github.com/hyperledger/fabric/bccsp/factory/factory.go index 8ea27b33b..4b6ef5a7a 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/factory/factory.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/factory/factory.go @@ -20,7 +20,7 @@ import ( "sync" "github.com/hyperledger/fabric/bccsp" - "github.com/op/go-logging" + "github.com/hyperledger/fabric/common/flogging" ) var ( @@ -41,7 +41,7 @@ var ( // Factories' Initialization Error factoriesInitError error - logger = logging.MustGetLogger("BCCSP_FACTORY") + logger = flogging.MustGetLogger("bccsp") ) // BCCSPFactory is used to get instances of the BCCSP interface. @@ -77,73 +77,6 @@ func GetBCCSP(name string) (bccsp.BCCSP, error) { return bccspMap[name], nil } -// GetBCCSPFromOpts returns a BCCSP created according to the options passed in input. -func GetBCCSPFromOpts(config *FactoryOpts) (bccsp.BCCSP, error) { - var f BCCSPFactory - switch config.ProviderName { - case "SW": - f = &SWFactory{} - case "PKCS11": - f = &PKCS11Factory{} - } - - csp, err := f.Get(config) - if err != nil { - return nil, fmt.Errorf("Could not initialize BCCSP %s [%s]", f.Name(), err) - } - return csp, nil -} - -// InitFactories must be called before using factory interfaces -// It is acceptable to call with config = nil, in which case -// some defaults will get used -// Error is returned only if defaultBCCSP cannot be found -func InitFactories(config *FactoryOpts) error { - factoriesInitOnce.Do(func() { - // Take some precautions on default opts - if config == nil { - config = &DefaultOpts - } - - if config.ProviderName == "" { - config.ProviderName = "SW" - } - - if config.SwOpts == nil { - config.SwOpts = DefaultOpts.SwOpts - } - - // Initialize factories map - bccspMap = make(map[string]bccsp.BCCSP) - - // Software-Based BCCSP - if config.SwOpts != nil { - f := &SWFactory{} - err := initBCCSP(f, config) - if err != nil { - factoriesInitError = fmt.Errorf("[%s]", err) - } - } - - // PKCS11-Based BCCSP - if config.Pkcs11Opts != nil { - f := &PKCS11Factory{} - err := initBCCSP(f, config) - if err != nil { - factoriesInitError = fmt.Errorf("%s\n[%s]", factoriesInitError, err) - } - } - - var ok bool - defaultBCCSP, ok = bccspMap[config.ProviderName] - if !ok { - factoriesInitError = fmt.Errorf("%s\nCould not find default `%s` BCCSP", factoriesInitError, config.ProviderName) - } - }) - - return factoriesInitError -} - func initBCCSP(f BCCSPFactory, config *FactoryOpts) error { csp, err := f.Get(config) if err != nil { diff --git a/vendor/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go b/vendor/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go new file mode 100644 index 000000000..409373c1f --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go @@ -0,0 +1,85 @@ +// +build nopkcs11 + +/* +Copyright IBM Corp. 2017 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 factory + +import ( + "fmt" + + "github.com/hyperledger/fabric/bccsp" +) + +type FactoryOpts struct { + ProviderName string `mapstructure:"default" json:"default" yaml:"Default"` + SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SwOpts"` +} + +// InitFactories must be called before using factory interfaces +// It is acceptable to call with config = nil, in which case +// some defaults will get used +// Error is returned only if defaultBCCSP cannot be found +func InitFactories(config *FactoryOpts) error { + factoriesInitOnce.Do(func() { + // Take some precautions on default opts + if config == nil { + config = &DefaultOpts + } + + if config.ProviderName == "" { + config.ProviderName = "SW" + } + + if config.SwOpts == nil { + config.SwOpts = DefaultOpts.SwOpts + } + + // Initialize factories map + bccspMap = make(map[string]bccsp.BCCSP) + + // Software-Based BCCSP + if config.SwOpts != nil { + f := &SWFactory{} + err := initBCCSP(f, config) + if err != nil { + factoriesInitError = fmt.Errorf("[%s]", err) + } + } + + var ok bool + defaultBCCSP, ok = bccspMap[config.ProviderName] + if !ok { + factoriesInitError = fmt.Errorf("%s\nCould not find default `%s` BCCSP", factoriesInitError, config.ProviderName) + } + }) + + return factoriesInitError +} + +// GetBCCSPFromOpts returns a BCCSP created according to the options passed in input. +func GetBCCSPFromOpts(config *FactoryOpts) (bccsp.BCCSP, error) { + var f BCCSPFactory + switch config.ProviderName { + case "SW": + f = &SWFactory{} + } + + csp, err := f.Get(config) + if err != nil { + return nil, fmt.Errorf("Could not initialize BCCSP %s [%s]", f.Name(), err) + } + return csp, nil +} diff --git a/vendor/github.com/hyperledger/fabric/bccsp/factory/opts.go b/vendor/github.com/hyperledger/fabric/bccsp/factory/opts.go index e03e3b3de..42a021b57 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/factory/opts.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/factory/opts.go @@ -16,12 +16,6 @@ limitations under the License. package factory // DefaultOpts offers a default implementation for Opts -type FactoryOpts struct { - ProviderName string `mapstructure:"default" json:"default"` - SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty"` - Pkcs11Opts *PKCS11Opts `mapstructure:"PKCS11,omitempty" json:"PKCS11,omitempty"` -} - var DefaultOpts = FactoryOpts{ ProviderName: "SW", SwOpts: &SwOpts{ diff --git a/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go b/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go new file mode 100644 index 000000000..cafdd3a6f --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11.go @@ -0,0 +1,98 @@ +// +build !nopkcs11 + +/* +Copyright IBM Corp. 2017 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 factory + +import ( + "fmt" + + "github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric/bccsp/pkcs11" +) + +type FactoryOpts struct { + ProviderName string `mapstructure:"default" json:"default" yaml:"Default"` + SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SwOpts"` + Pkcs11Opts *pkcs11.PKCS11Opts `mapstructure:"PKCS11,omitempty" json:"PKCS11,omitempty" yaml:"PKCS11"` +} + +// InitFactories must be called before using factory interfaces +// It is acceptable to call with config = nil, in which case +// some defaults will get used +// Error is returned only if defaultBCCSP cannot be found +func InitFactories(config *FactoryOpts) error { + factoriesInitOnce.Do(func() { + // Take some precautions on default opts + if config == nil { + config = &DefaultOpts + } + + if config.ProviderName == "" { + config.ProviderName = "SW" + } + + if config.SwOpts == nil { + config.SwOpts = DefaultOpts.SwOpts + } + + // Initialize factories map + bccspMap = make(map[string]bccsp.BCCSP) + + // Software-Based BCCSP + if config.SwOpts != nil { + f := &SWFactory{} + err := initBCCSP(f, config) + if err != nil { + factoriesInitError = fmt.Errorf("[%s]", err) + } + } + + // PKCS11-Based BCCSP + if config.Pkcs11Opts != nil { + f := &PKCS11Factory{} + err := initBCCSP(f, config) + if err != nil { + factoriesInitError = fmt.Errorf("%s\n[%s]", factoriesInitError, err) + } + } + + var ok bool + defaultBCCSP, ok = bccspMap[config.ProviderName] + if !ok { + factoriesInitError = fmt.Errorf("%s\nCould not find default `%s` BCCSP", factoriesInitError, config.ProviderName) + } + }) + + return factoriesInitError +} + +// GetBCCSPFromOpts returns a BCCSP created according to the options passed in input. +func GetBCCSPFromOpts(config *FactoryOpts) (bccsp.BCCSP, error) { + var f BCCSPFactory + switch config.ProviderName { + case "SW": + f = &SWFactory{} + case "PKCS11": + f = &PKCS11Factory{} + } + + csp, err := f.Get(config) + if err != nil { + return nil, fmt.Errorf("Could not initialize BCCSP %s [%s]", f.Name(), err) + } + return csp, nil +} diff --git a/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go b/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go index 099723c54..10a7bb17d 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/factory/pkcs11factory.go @@ -1,3 +1,5 @@ +// +build !nopkcs11 + /* Copyright IBM Corp. 2016 All Rights Reserved. @@ -40,7 +42,7 @@ func (f *PKCS11Factory) Name() string { // Get returns an instance of BCCSP using Opts. func (f *PKCS11Factory) Get(config *FactoryOpts) (bccsp.BCCSP, error) { // Validate arguments - if config == nil || config.SwOpts == nil { + if config == nil || config.Pkcs11Opts == nil { return nil, errors.New("Invalid config. It must not be nil.") } @@ -60,29 +62,5 @@ func (f *PKCS11Factory) Get(config *FactoryOpts) (bccsp.BCCSP, error) { // Default to DummyKeystore ks = sw.NewDummyKeyStore() } - err := pkcs11.InitPKCS11(p11Opts.Library, p11Opts.Pin, p11Opts.Label) - if err != nil { - return nil, fmt.Errorf("Failed initializing PKCS11 library %s %s [%s]", - p11Opts.Library, p11Opts.Label, err) - } - return pkcs11.New(p11Opts.SecLevel, p11Opts.HashFamily, ks) -} - -// PKCS11Opts contains options for the P11Factory -type PKCS11Opts struct { - // Default algorithms when not specified (Deprecated?) - SecLevel int `mapstructure:"security" json:"security"` - HashFamily string `mapstructure:"hash" json:"hash"` - - // Keystore options - Ephemeral bool `mapstructure:"tempkeys,omitempty" json:"tempkeys,omitempty"` - FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty"` - DummyKeystore *DummyKeystoreOpts `mapstructure:"dummykeystore,omitempty" json:"dummykeystore,omitempty"` - - // PKCS11 options - Library string `mapstructure:"library" json:"library"` - Label string `mapstructure:"label" json:"label"` - Pin string `mapstructure:"pin" json:"pin"` - Sensitive bool `mapstructure:"sensitivekeys,omitempty" json:"sensitivekeys,omitempty"` - SoftVerify bool `mapstructure:"softwareverify,omitempty" json:"softwareverify,omitempty"` + return pkcs11.New(*p11Opts, ks) } diff --git a/vendor/github.com/hyperledger/fabric/bccsp/factory/swfactory.go b/vendor/github.com/hyperledger/fabric/bccsp/factory/swfactory.go index c95f0be0f..50ef4556c 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/factory/swfactory.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/factory/swfactory.go @@ -65,18 +65,18 @@ func (f *SWFactory) Get(config *FactoryOpts) (bccsp.BCCSP, error) { // SwOpts contains options for the SWFactory type SwOpts struct { // Default algorithms when not specified (Deprecated?) - SecLevel int `mapstructure:"security" json:"security"` - HashFamily string `mapstructure:"hash" json:"hash"` + SecLevel int `mapstructure:"security" json:"security" yaml:"Security"` + HashFamily string `mapstructure:"hash" json:"hash" yaml:"Hash"` // Keystore Options Ephemeral bool `mapstructure:"tempkeys,omitempty" json:"tempkeys,omitempty"` - FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty"` + FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty" yaml:"FileKeyStore"` DummyKeystore *DummyKeystoreOpts `mapstructure:"dummykeystore,omitempty" json:"dummykeystore,omitempty"` } // Pluggable Keystores, could add JKS, P12, etc.. type FileKeystoreOpts struct { - KeyStorePath string `mapstructure:"keystore"` + KeyStorePath string `mapstructure:"keystore" yaml:"KeyStore"` } type DummyKeystoreOpts struct{} diff --git a/vendor/github.com/hyperledger/fabric/bccsp/hashopts.go b/vendor/github.com/hyperledger/fabric/bccsp/hashopts.go index 4113417d9..a405f762e 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/hashopts.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/hashopts.go @@ -16,6 +16,8 @@ limitations under the License. package bccsp +import "fmt" + // SHA256Opts contains options relating to SHA-256. type SHA256Opts struct { } @@ -51,3 +53,18 @@ type SHA3_384Opts struct { func (opts *SHA3_384Opts) Algorithm() string { return SHA3_384 } + +// GetHashOpt returns the HashOpts corresponding to the passed hash function +func GetHashOpt(hashFunction string) (HashOpts, error) { + switch hashFunction { + case SHA256: + return &SHA256Opts{}, nil + case SHA384: + return &SHA384Opts{}, nil + case SHA3_256: + return &SHA3_256Opts{}, nil + case SHA3_384: + return &SHA3_384Opts{}, nil + } + return nil, fmt.Errorf("hash function not recognized [%s]", hashFunction) +} diff --git a/vendor/github.com/hyperledger/fabric/bccsp/opts.go b/vendor/github.com/hyperledger/fabric/bccsp/opts.go index 66d182096..834c1c3c0 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/opts.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/opts.go @@ -66,6 +66,11 @@ const ( // an error will be returned. SHA = "SHA" + // SHA2 is an identifier for SHA2 hash family + SHA2 = "SHA2" + // SHA3 is an identifier for SHA3 hash family + SHA3 = "SHA3" + // SHA256 SHA256 = "SHA256" // SHA384 diff --git a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go index 556a97e8c..156f7a057 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/conf.go @@ -83,3 +83,30 @@ func (conf *config) setSecurityLevelSHA3(level int) (err error) { } return } + +// PKCS11Opts contains options for the P11Factory +type PKCS11Opts struct { + // Default algorithms when not specified (Deprecated?) + SecLevel int `mapstructure:"security" json:"security"` + HashFamily string `mapstructure:"hash" json:"hash"` + + // Keystore options + Ephemeral bool `mapstructure:"tempkeys,omitempty" json:"tempkeys,omitempty"` + FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty"` + DummyKeystore *DummyKeystoreOpts `mapstructure:"dummykeystore,omitempty" json:"dummykeystore,omitempty"` + + // PKCS11 options + Library string `mapstructure:"library" json:"library"` + Label string `mapstructure:"label" json:"label"` + Pin string `mapstructure:"pin" json:"pin"` + Sensitive bool `mapstructure:"sensitivekeys,omitempty" json:"sensitivekeys,omitempty"` + SoftVerify bool `mapstructure:"softwareverify,omitempty" json:"softwareverify,omitempty"` +} + +// Since currently only ECDSA operations go to PKCS11, need a keystore still +// Pluggable Keystores, could add JKS, P12, etc.. +type FileKeystoreOpts struct { + KeyStorePath string `mapstructure:"keystore" json:"keystore" yaml:"KeyStore"` +} + +type DummyKeystoreOpts struct{} diff --git a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go index e78295242..d6b0bc4cd 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/ecdsa.go @@ -16,6 +16,7 @@ limitations under the License. package pkcs11 import ( + "crypto/ecdsa" "crypto/elliptic" "encoding/asn1" "errors" @@ -73,7 +74,7 @@ func unmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) { } func (csp *impl) signECDSA(k ecdsaPrivateKey, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { - r, s, err := signECDSA(k.ski, digest) + r, s, err := csp.signP11ECDSA(k.ski, digest) if err != nil { return nil, err } @@ -111,5 +112,9 @@ func (csp *impl) verifyECDSA(k ecdsaPublicKey, signature, digest []byte, opts bc return false, fmt.Errorf("Invalid S. Must be smaller than half the order [%s][%s].", s, halfOrder) } - return verifyECDSA(k.ski, digest, r, s, k.pub.Curve.Params().BitSize/8) + if csp.softVerify { + return ecdsa.Verify(k.pub, digest, r, s), nil + } else { + return csp.verifyP11ECDSA(k.ski, digest, r, s, k.pub.Curve.Params().BitSize/8) + } } diff --git a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go index 0f29c8f58..28ed635c9 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/impl.go @@ -28,40 +28,27 @@ import ( "fmt" "hash" "math/big" + "os" "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/utils" - "github.com/op/go-logging" + "github.com/hyperledger/fabric/common/flogging" + "github.com/miekg/pkcs11" + "golang.org/x/crypto/sha3" ) var ( - logger = logging.MustGetLogger("PKCS11_BCCSP") + logger = flogging.MustGetLogger("bccsp_p11") + sessionCacheSize = 10 ) -// NewDefaultSecurityLevel returns a new instance of the software-based BCCSP -// 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) -} - -// NewDefaultSecurityLevel returns a new instance of the software-based BCCSP -// at security level 256, hash family SHA2 and using the passed KeyStore. -func NewDefaultSecurityLevelWithKeystore(keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { - return New(256, "SHA2", keyStore) -} - // New returns a new instance of the software-based BCCSP // set at the passed security level, hash family and KeyStore. -func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { +func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { // Init config conf := &config{} - err := conf.setSecurityLevel(securityLevel, hashFamily) + err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily) if err != nil { return nil, fmt.Errorf("Failed initializing configuration [%s]", err) } @@ -71,13 +58,32 @@ func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.B return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil.") } - return &impl{conf, keyStore}, nil + lib := opts.Library + pin := opts.Pin + label := opts.Label + ctx, slot, session, err := loadLib(lib, pin, label) + if err != nil { + return nil, fmt.Errorf("Failed initializing PKCS11 library %s %s [%s]", + lib, label, err) + } + + sessions := make(chan pkcs11.SessionHandle, sessionCacheSize) + csp := &impl{conf, keyStore, ctx, sessions, slot, lib, opts.Sensitive, opts.SoftVerify} + csp.returnSession(*session) + return csp, nil } -// SoftwareBasedBCCSP is the software-based implementation of the BCCSP. type impl struct { conf *config ks bccsp.KeyStore + + ctx *pkcs11.Ctx + sessions chan pkcs11.SessionHandle + slot uint + + lib string + noPrivImport bool + softVerify bool } // KeyGen generates a key using opts. @@ -92,7 +98,7 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { // Parse algorithm switch opts.(type) { case *bccsp.ECDSAKeyGenOpts: - ski, pub, err := generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) + ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) if err != nil { return nil, fmt.Errorf("Failed generating ECDSA key [%s]", err) } @@ -100,7 +106,7 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { pkcs11Stored = true case *bccsp.ECDSAP256KeyGenOpts: - ski, pub, err := generateECKey(oidNamedCurveP256, opts.Ephemeral()) + ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) if err != nil { return nil, fmt.Errorf("Failed generating ECDSA P256 key [%s]", err) } @@ -109,7 +115,7 @@ func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { pkcs11Stored = true case *bccsp.ECDSAP384KeyGenOpts: - ski, pub, err := generateECKey(oidNamedCurveP384, opts.Ephemeral()) + ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) if err != nil { return nil, fmt.Errorf("Failed generating ECDSA P384 key [%s]", err) } @@ -269,7 +275,7 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e return nil, errors.New("Do not know OID for this Curve.") } - ski, err := importECKey(oid, nil, ecPt, opts.Ephemeral(), isPublicKey) + ski, err := csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) if err != nil { return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) } @@ -295,7 +301,7 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e case *bccsp.ECDSAReRandKeyOpts: reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) pubKey := ecdsaK.pub.pub - secret := getSecretValue(ecdsaK.ski) + secret := csp.getSecretValue(ecdsaK.ski) if secret == nil { return nil, errors.New("Could not obtain EC Private Key") } @@ -334,7 +340,7 @@ func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, e return nil, errors.New("Do not know OID for this Curve.") } - ski, err := importECKey(oid, tempSK.D.Bytes(), ecPt, opts.Ephemeral(), isPrivateKey) + ski, err := csp.importECKey(oid, tempSK.D.Bytes(), ecPt, opts.Ephemeral(), privateKeyFlag) if err != nil { return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) } @@ -488,15 +494,33 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K return nil, errors.New("Do not know OID for this Curve.") } - ski, err := importECKey(oid, nil, ecPt, opts.Ephemeral(), isPublicKey) - if err != nil { - return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) + var ski []byte + if csp.noPrivImport { + // opencryptoki does not support public ec key imports. This is a sufficient + // workaround for now to use soft verify + hash := sha256.Sum256(ecPt) + ski = hash[:] + } else { + // Warn about potential future problems + if !csp.softVerify { + logger.Debugf("opencryptoki workaround warning: Importing public EC Key does not store out to pkcs11 store,\n" + + "so verify with this key will fail, unless key is already present in store. Enable 'softwareverify'\n" + + "in pkcs11 options, if suspect this issue.") + } + ski, err = csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) + } } k = &ecdsaPublicKey{ski, ecdsaPK} return k, nil case *bccsp.ECDSAPrivateKeyImportOpts: + if csp.noPrivImport { + return nil, errors.New("[ECDSADERPrivateKeyImportOpts] PKCS11 options 'sensitivekeys' is set to true. Cannot import.") + } + der, ok := raw.([]byte) if !ok { return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") @@ -522,7 +546,7 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K return nil, errors.New("Do not know OID for this Curve.") } - ski, err := importECKey(oid, ecdsaSK.D.Bytes(), ecPt, opts.Ephemeral(), isPrivateKey) + ski, err := csp.importECKey(oid, ecdsaSK.D.Bytes(), ecPt, opts.Ephemeral(), privateKeyFlag) if err != nil { return nil, fmt.Errorf("Failed getting importing EC Private Key [%s]", err) } @@ -542,9 +566,23 @@ func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.K return nil, errors.New("Do not know OID for this Curve.") } - ski, err := importECKey(oid, nil, ecPt, opts.Ephemeral(), isPublicKey) - if err != nil { - return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) + var ski []byte + if csp.noPrivImport { + // opencryptoki does not support public ec key imports. This is a sufficient + // workaround for now to use soft verify + hash := sha256.Sum256(ecPt) + ski = hash[:] + } else { + // Warn about potential future problems + if !csp.softVerify { + logger.Debugf("opencryptoki workaround warning: Importing public EC Key does not store out to pkcs11 store,\n" + + "so verify with this key will fail, unless key is already present in store. Enable 'softwareverify'\n" + + "in pkcs11 options, if suspect this issue.") + } + ski, err = csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) + if err != nil { + return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) + } } k = &ecdsaPublicKey{ski, lowLevelKey} @@ -594,7 +632,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) { - pubKey, isPriv, err := getECKey(ski) + pubKey, isPriv, err := csp.getECKey(ski) if err == nil { if isPriv { return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil @@ -680,7 +718,8 @@ func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signat return k.(*rsaPrivateKey).privKey.Sign(rand.Reader, digest, opts) default: - return nil, fmt.Errorf("Key type not recognized [%s]", k) + //return nil, fmt.Errorf("Key type not recognized [%s]", k) + panic(fmt.Errorf("Key type not recognized - [%+v] [%#v] [%T] [%T]", k, k, k, k)) } } @@ -783,3 +822,32 @@ func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpt return nil, fmt.Errorf("Key type not recognized [%s]", k) } } + +// THIS IS ONLY USED FOR TESTING +// This is a convenience function. Useful to self-configure, for tests where usual configuration is not +// available +func FindPKCS11Lib() (lib, pin, label string) { + //FIXME: Till we workout the configuration piece, look for the libraries in the familiar places + lib = os.Getenv("PKCS11_LIB") + if lib == "" { + pin = "98765432" + label = "ForFabric" + possibilities := []string{ + "/usr/lib/softhsm/libsofthsm2.so", //Debian + "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu + "/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu + "/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so", //Power + "/usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so", //MacOS + } + for _, path := range possibilities { + if _, err := os.Stat(path); !os.IsNotExist(err) { + lib = path + break + } + } + } else { + pin = os.Getenv("PKCS11_PIN") + label = os.Getenv("PKCS11_LABEL") + } + return lib, pin, label +} diff --git a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go index d650fbf60..927778dc5 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/pkcs11/pkcs11.go @@ -30,35 +30,22 @@ import ( "github.com/op/go-logging" ) -var ( - ctx *pkcs11.Ctx - sessions = make(chan pkcs11.SessionHandle, 2000) - slot uint - probablySoftHSM = false //Only needed for KeyImport -) - -func InitPKCS11(lib, pin, label string) error { - if strings.Contains(lib, "softhsm") { - probablySoftHSM = true - } - return loadLib(lib, pin, label) -} - -func loadLib(lib, pin, label string) error { +func loadLib(lib, pin, label string) (*pkcs11.Ctx, uint, *pkcs11.SessionHandle, error) { + var slot uint = 0 logger.Debugf("Loading pkcs11 library [%s]\n", lib) if lib == "" { - return fmt.Errorf("No PKCS11 library default") + return nil, slot, nil, fmt.Errorf("No PKCS11 library default") } - ctx = pkcs11.New(lib) + ctx := pkcs11.New(lib) if ctx == nil { - return fmt.Errorf("Instantiate failed [%s]", lib) + return nil, slot, nil, fmt.Errorf("Instantiate failed [%s]", lib) } ctx.Initialize() slots, err := ctx.GetSlotList(true) if err != nil { - return err + return nil, slot, nil, fmt.Errorf("Could not get Slot List [%s]", err) } found := false for _, s := range slots { @@ -66,6 +53,7 @@ func loadLib(lib, pin, label string) error { if err != nil { continue } + logger.Debugf("Looking for %s, found label %s\n", label, info.Label) if label == info.Label { found = true slot = s @@ -73,33 +61,47 @@ func loadLib(lib, pin, label string) error { } } if !found { - return fmt.Errorf("Could not find token with label %s", label) + return nil, slot, nil, fmt.Errorf("Could not find token with label %s", label) + } + + var session pkcs11.SessionHandle + for i := 0; i < 10; i++ { + session, err = ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) + if err != nil { + logger.Warningf("OpenSession failed, retrying [%s]\n", err) + } else { + break + } + } + if err != nil { + logger.Fatalf("OpenSession [%s]\n", err) } - session := getSession() - defer returnSession(session) + logger.Debugf("Created new pkcs11 session %+v on slot %d\n", session, slot) if pin == "" { - return fmt.Errorf("No PIN set\n") + return nil, slot, nil, fmt.Errorf("No PIN set\n") } err = ctx.Login(session, pkcs11.CKU_USER, pin) if err != nil { - return fmt.Errorf("Login failed [%s]\n", err) + if err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) { + return nil, slot, nil, fmt.Errorf("Login failed [%s]\n", err) + } } - return nil + return ctx, slot, &session, nil } -func getSession() (session pkcs11.SessionHandle) { +func (csp *impl) getSession() (session pkcs11.SessionHandle) { select { - case session = <-sessions: - logger.Debugf("Reusing existing pkcs11 session %x on slot %d\n", session, slot) + case session = <-csp.sessions: + logger.Debugf("Reusing existing pkcs11 session %+v on slot %d\n", session, csp.slot) default: - // create one + // cache is empty (or completely in use), create a new session var s pkcs11.SessionHandle var err error = nil for i := 0; i < 10; i++ { - s, err = ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) + s, err = csp.ctx.OpenSession(csp.slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) if err != nil { logger.Warningf("OpenSession failed, retrying [%s]\n", err) } else { @@ -107,32 +109,38 @@ func getSession() (session pkcs11.SessionHandle) { } } if err != nil { - logger.Fatalf("OpenSession [%s]\n", err) + panic(fmt.Errorf("OpenSession failed [%s]\n", err)) } - logger.Debugf("Created new pkcs11 session %x on slot %d\n", session, slot) + logger.Debugf("Created new pkcs11 session %+v on slot %d\n", s, csp.slot) session = s } return session } -func returnSession(session pkcs11.SessionHandle) { - sessions <- session +func (csp *impl) returnSession(session pkcs11.SessionHandle) { + select { + case csp.sessions <- session: + // returned session back to session cache + default: + // have plenty of sessions in cache, dropping + csp.ctx.CloseSession(session) + } } // Look for an EC key by SKI, stored in CKA_ID // This function can probably be addapted for both EC and RSA keys. -func getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err error) { - p11lib := ctx - session := getSession() - defer returnSession(session) +func (csp *impl) getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) isPriv = true - _, err = findKeyPairFromSKI(p11lib, session, ski, isPrivateKey) + _, err = findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag) if err != nil { isPriv = false logger.Debugf("Private key not found [%s] for SKI [%s], looking for Public key", err, hex.EncodeToString(ski)) } - publicKey, err := findKeyPairFromSKI(p11lib, session, ski, isPublicKey) + publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag) if err != nil { return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) } @@ -212,10 +220,10 @@ func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { return nil, false } -func generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pubKey *ecdsa.PublicKey, err error) { - p11lib := ctx - session := getSession() - defer returnSession(session) +func (csp *impl) generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pubKey *ecdsa.PublicKey, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) id := nextIDCtr() publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) @@ -232,7 +240,7 @@ func generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pub pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), - pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), pkcs11.NewAttribute(pkcs11.CKA_ID, publabel), pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), @@ -242,13 +250,13 @@ func generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pub pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), - pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), + pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), pkcs11.NewAttribute(pkcs11.CKA_ID, prvlabel), pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel), - pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, true), + pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, !csp.noPrivImport), } pub, prv, err := p11lib.GenerateKeyPair(session, @@ -298,12 +306,12 @@ func generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pub return ski, pubGoKey, nil } -func signECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) { - p11lib := ctx - session := getSession() - defer returnSession(session) +func (csp *impl) signP11ECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) - privateKey, err := findKeyPairFromSKI(p11lib, session, ski, isPrivateKey) + privateKey, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag) if err != nil { return nil, nil, fmt.Errorf("Private key not found [%s]\n", err) } @@ -328,14 +336,14 @@ func signECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) { return R, S, nil } -func verifyECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize int) (valid bool, err error) { - p11lib := ctx - session := getSession() - defer returnSession(session) +func (csp *impl) verifyP11ECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize int) (valid bool, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) logger.Debugf("Verify ECDSA\n") - publicKey, err := findKeyPairFromSKI(p11lib, session, ski, isPublicKey) + publicKey, err := findKeyPairFromSKI(p11lib, session, ski, publicKeyFlag) if err != nil { return false, fmt.Errorf("Public key not found [%s]\n", err) } @@ -364,10 +372,10 @@ func verifyECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize int) (valid boo return true, nil } -func importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bool, isPrivate bool) (ski []byte, err error) { - p11lib := ctx - session := getSession() - defer returnSession(session) +func (csp *impl) importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bool, keyType bool) (ski []byte, err error) { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) id := nextIDCtr() @@ -377,15 +385,15 @@ func importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bo } var keyTemplate []*pkcs11.Attribute - if isPrivate == isPublicKey { + if keyType == publicKeyFlag { logger.Debug("Importing Public EC Key") publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) hash := sha256.Sum256(ecPt) ski = hash[:] - ski[0] = 1 - if probablySoftHSM { + if strings.Contains(csp.lib, "softhsm") { + // Probably SoftHSM, some handcrafting necessary ecPt = append([]byte{0x04, byte(len(ecPt))}, ecPt...) } @@ -402,7 +410,7 @@ func importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bo pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false), } } else { // isPrivateKey - ski, err = importECKey(curve, nil, ecPt, ephemeral, isPublicKey) + ski, err = csp.importECKey(curve, nil, ecPt, ephemeral, publicKeyFlag) if err != nil { return nil, fmt.Errorf("Failed importing private EC Key [%s]\n", err) } @@ -438,13 +446,13 @@ func importECKey(curve asn1.ObjectIdentifier, privKey, ecPt []byte, ephemeral bo } const ( - isPrivateKey = true - isPublicKey = false + privateKeyFlag = true + publicKeyFlag = false ) -func findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, isPrivate bool) (*pkcs11.ObjectHandle, error) { +func findKeyPairFromSKI(mod *pkcs11.Ctx, session pkcs11.SessionHandle, ski []byte, keyType bool) (*pkcs11.ObjectHandle, error) { ktype := pkcs11.CKO_PUBLIC_KEY - if isPrivate == isPrivateKey { + if keyType == privateKeyFlag { ktype = pkcs11.CKO_PRIVATE_KEY } @@ -555,7 +563,7 @@ func ecPoint(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, key pkcs11.Object func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.ObjectHandle) { var cktype, ckclass uint - var ckaid, cklabel, privKey []byte + var ckaid, cklabel []byte if p11lib == nil { return @@ -566,13 +574,12 @@ func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.Obje pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, cktype), pkcs11.NewAttribute(pkcs11.CKA_ID, ckaid), pkcs11.NewAttribute(pkcs11.CKA_LABEL, cklabel), - pkcs11.NewAttribute(pkcs11.CKA_VALUE, privKey), } // certain errors are tolerated, if value is missing attr, err := p11lib.GetAttributeValue(session, obj, template) if err != nil { - logger.Warningf("P11: get(attrlist) [%s]\n", err) + logger.Debugf("P11: get(attrlist) [%s]\n", err) } for _, a := range attr { @@ -581,12 +588,12 @@ func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.Obje } } -func getSecretValue(ski []byte) []byte { - p11lib := ctx - session := getSession() - defer returnSession(session) +func (csp *impl) getSecretValue(ski []byte) []byte { + p11lib := csp.ctx + session := csp.getSession() + defer csp.returnSession(session) - keyHandle, err := findKeyPairFromSKI(p11lib, session, ski, isPrivateKey) + keyHandle, err := findKeyPairFromSKI(p11lib, session, ski, privateKeyFlag) var privKey []byte template := []*pkcs11.Attribute{ diff --git a/vendor/github.com/hyperledger/fabric/bccsp/sw/impl.go b/vendor/github.com/hyperledger/fabric/bccsp/sw/impl.go index 8871c81ff..46fb8432e 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/sw/impl.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/sw/impl.go @@ -36,12 +36,12 @@ import ( "github.com/hyperledger/fabric/bccsp" "github.com/hyperledger/fabric/bccsp/utils" - "github.com/op/go-logging" + "github.com/hyperledger/fabric/common/flogging" "golang.org/x/crypto/sha3" ) var ( - logger = logging.MustGetLogger("SW_BCCSP") + logger = flogging.MustGetLogger("bccsp_sw") ) // NewDefaultSecurityLevel returns a new instance of the software-based BCCSP diff --git a/vendor/github.com/hyperledger/fabric/bccsp/utils/io.go b/vendor/github.com/hyperledger/fabric/bccsp/utils/io.go index bf61ce195..95e0cee3f 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/utils/io.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/utils/io.go @@ -1,5 +1,5 @@ /* -Copyright IBM Corp. 2016 All Rights Reserved. +Copyright IBM Corp. 2017 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. diff --git a/vendor/github.com/hyperledger/fabric/bccsp/utils/keys.go b/vendor/github.com/hyperledger/fabric/bccsp/utils/keys.go index 1629c3de0..59bac0fdc 100644 --- a/vendor/github.com/hyperledger/fabric/bccsp/utils/keys.go +++ b/vendor/github.com/hyperledger/fabric/bccsp/utils/keys.go @@ -18,14 +18,53 @@ package utils import ( "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" + "encoding/asn1" "encoding/pem" "errors" "fmt" ) +// struct to hold info required for PKCS#8 +type pkcs8Info struct { + Version int + PrivateKeyAlgorithm []asn1.ObjectIdentifier + PrivateKey []byte +} + +type ecPrivateKey struct { + Version int + PrivateKey []byte + NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` + PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` +} + +var ( + oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} + oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} + oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} + oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +var oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} + +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { + switch curve { + case elliptic.P224(): + return oidNamedCurveP224, true + case elliptic.P256(): + return oidNamedCurveP256, true + case elliptic.P384(): + return oidNamedCurveP384, true + case elliptic.P521(): + return oidNamedCurveP521, true + } + return nil, false +} + // PrivateKeyToDER marshals a private key to der func PrivateKeyToDER(privateKey *ecdsa.PrivateKey) ([]byte, error) { if privateKey == nil { @@ -35,12 +74,17 @@ func PrivateKeyToDER(privateKey *ecdsa.PrivateKey) ([]byte, error) { return x509.MarshalECPrivateKey(privateKey) } -// PrivateKeyToPEM converts a private key to PEM +// PrivateKeyToPEM converts the private key to PEM format. +// EC private keys are converted to PKCS#8 format. +// RSA private keys are converted to PKCS#1 format. func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { // Validate inputs if len(pwd) != 0 { return PrivateKeyToEncryptedPEM(privateKey, pwd) } + if privateKey == nil { + return nil, errors.New("Invalid key. It must be different from nil.") + } switch k := privateKey.(type) { case *ecdsa.PrivateKey: @@ -48,23 +92,48 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") } - raw, err := x509.MarshalECPrivateKey(k) + // get the oid for the curve + oidNamedCurve, ok := oidFromNamedCurve(k.Curve) + if !ok { + return nil, errors.New("unknown elliptic curve") + } + + // based on https://golang.org/src/crypto/x509/sec1.go + privateKeyBytes := k.D.Bytes() + paddedPrivateKey := make([]byte, (k.Curve.Params().N.BitLen()+7)/8) + copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) + // omit NamedCurveOID for compatibility as it's optional + asn1Bytes, err := asn1.Marshal(ecPrivateKey{ + Version: 1, + PrivateKey: paddedPrivateKey, + PublicKey: asn1.BitString{Bytes: elliptic.Marshal(k.Curve, k.X, k.Y)}, + }) if err != nil { - return nil, err + return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) } + var pkcs8Key pkcs8Info + pkcs8Key.Version = 1 + pkcs8Key.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 2) + pkcs8Key.PrivateKeyAlgorithm[0] = oidPublicKeyECDSA + pkcs8Key.PrivateKeyAlgorithm[1] = oidNamedCurve + pkcs8Key.PrivateKey = asn1Bytes + + pkcs8Bytes, err := asn1.Marshal(pkcs8Key) + if err != nil { + return nil, fmt.Errorf("error marshaling EC key to asn1 [%s]", err) + } return pem.EncodeToMemory( &pem.Block{ - Type: "ECDSA PRIVATE KEY", - Bytes: raw, + Type: "PRIVATE KEY", + Bytes: pkcs8Bytes, }, ), nil case *rsa.PrivateKey: if k == nil { return nil, errors.New("Invalid rsa private key. It must be different from nil.") } - raw := x509.MarshalPKCS1PrivateKey(k) return pem.EncodeToMemory( @@ -80,12 +149,15 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) { // PrivateKeyToEncryptedPEM converts a private key to an encrypted PEM func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) { + if privateKey == nil { + return nil, errors.New("Invalid private key. It must be different from nil.") + } + switch k := privateKey.(type) { case *ecdsa.PrivateKey: if k == nil { return nil, errors.New("Invalid ecdsa private key. It must be different from nil.") } - raw, err := x509.MarshalECPrivateKey(k) if err != nil { @@ -94,7 +166,7 @@ func PrivateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error block, err := x509.EncryptPEMBlock( rand.Reader, - "ECDSA PRIVATE KEY", + "PRIVATE KEY", raw, pwd, x509.PEMCipherAES256) @@ -228,12 +300,15 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { return PublicKeyToEncryptedPEM(publicKey, pwd) } + if publicKey == nil { + return nil, errors.New("Invalid public key. It must be different from nil.") + } + switch k := publicKey.(type) { case *ecdsa.PublicKey: if k == nil { return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") } - PubASN1, err := x509.MarshalPKIXPublicKey(k) if err != nil { return nil, err @@ -241,7 +316,7 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { return pem.EncodeToMemory( &pem.Block{ - Type: "ECDSA PUBLIC KEY", + Type: "PUBLIC KEY", Bytes: PubASN1, }, ), nil @@ -249,7 +324,6 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { if k == nil { return nil, errors.New("Invalid rsa public key. It must be different from nil.") } - PubASN1, err := x509.MarshalPKIXPublicKey(k) if err != nil { return nil, err @@ -269,12 +343,15 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) { // PublicKeyToDER marshals a public key to the der format func PublicKeyToDER(publicKey interface{}) ([]byte, error) { + if publicKey == nil { + return nil, errors.New("Invalid public key. It must be different from nil.") + } + switch k := publicKey.(type) { case *ecdsa.PublicKey: if k == nil { return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") } - PubASN1, err := x509.MarshalPKIXPublicKey(k) if err != nil { return nil, err @@ -289,20 +366,26 @@ func PublicKeyToDER(publicKey interface{}) ([]byte, error) { // PublicKeyToEncryptedPEM converts a public key to encrypted pem func PublicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) { + if publicKey == nil { + return nil, errors.New("Invalid public key. It must be different from nil.") + } + if len(pwd) == 0 { + return nil, errors.New("Invalid password. It must be different from nil.") + } + switch k := publicKey.(type) { case *ecdsa.PublicKey: if k == nil { return nil, errors.New("Invalid ecdsa public key. It must be different from nil.") } raw, err := x509.MarshalPKIXPublicKey(k) - if err != nil { return nil, err } block, err := x509.EncryptPEMBlock( rand.Reader, - "ECDSA PUBLIC KEY", + "PUBLIC KEY", raw, pwd, x509.PEMCipherAES256) diff --git a/vendor/github.com/hyperledger/fabric/common/flogging/logging.go b/vendor/github.com/hyperledger/fabric/common/flogging/logging.go new file mode 100644 index 000000000..8c2204a60 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/common/flogging/logging.go @@ -0,0 +1,237 @@ +/* +Copyright IBM Corp. 2017 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 flogging + +import ( + "io" + "os" + "regexp" + "strings" + "sync" + + "github.com/op/go-logging" +) + +const ( + pkgLogID = "flogging" + defaultFormat = "%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}" + defaultLevel = logging.INFO +) + +var ( + logger *logging.Logger + + defaultOutput *os.File + + modules map[string]string // Holds the map of all modules and their respective log level + peerStartModules map[string]string + + lock sync.RWMutex + once sync.Once +) + +func init() { + logger = logging.MustGetLogger(pkgLogID) + Reset() +} + +// Reset sets to logging to the defaults defined in this package. +func Reset() { + modules = make(map[string]string) + lock = sync.RWMutex{} + + defaultOutput = os.Stderr + InitBackend(SetFormat(defaultFormat), defaultOutput) + InitFromSpec("") +} + +// SetFormat sets the logging format. +func SetFormat(formatSpec string) logging.Formatter { + if formatSpec == "" { + formatSpec = defaultFormat + } + return logging.MustStringFormatter(formatSpec) +} + +// InitBackend sets up the logging backend based on +// the provided logging formatter and I/O writer. +func InitBackend(formatter logging.Formatter, output io.Writer) { + backend := logging.NewLogBackend(output, "", 0) + backendFormatter := logging.NewBackendFormatter(backend, formatter) + logging.SetBackend(backendFormatter).SetLevel(defaultLevel, "") +} + +// DefaultLevel returns the fallback value for loggers to use if parsing fails. +func DefaultLevel() string { + return defaultLevel.String() +} + +// GetModuleLevel gets the current logging level for the specified module. +func GetModuleLevel(module string) string { + // logging.GetLevel() returns the logging level for the module, if defined. + // Otherwise, it returns the default logging level, as set by + // `flogging/logging.go`. + level := logging.GetLevel(module).String() + return level +} + +// SetModuleLevel sets the logging level for the modules that match the supplied +// regular expression. Can be used to dynamically change the log level for the +// module. +func SetModuleLevel(moduleRegExp string, level string) (string, error) { + // special case - `error` module, which is used to enable/disable callstacks + // in error messages, shouldn't use regular expressions + if moduleRegExp == "error" { + return setModuleLevel(moduleRegExp, level, false, false) + } + return setModuleLevel(moduleRegExp, level, true, false) +} + +func setModuleLevel(moduleRegExp string, level string, isRegExp bool, revert bool) (string, error) { + var re *regexp.Regexp + logLevel, err := logging.LogLevel(level) + if err != nil { + logger.Warningf("Invalid logging level '%s' - ignored", level) + } else { + if !isRegExp || revert { + logging.SetLevel(logLevel, moduleRegExp) + logger.Debugf("Module '%s' logger enabled for log level '%s'", moduleRegExp, level) + } else { + re, err = regexp.Compile(moduleRegExp) + if err != nil { + logger.Warningf("Invalid regular expression: %s", moduleRegExp) + return "", err + } + lock.Lock() + defer lock.Unlock() + for module := range modules { + if re.MatchString(module) { + logging.SetLevel(logging.Level(logLevel), module) + modules[module] = logLevel.String() + logger.Debugf("Module '%s' logger enabled for log level '%s'", module, logLevel) + } + } + } + } + return logLevel.String(), err +} + +// MustGetLogger is used in place of `logging.MustGetLogger` to allow us to +// store a map of all modules and submodules that have loggers in the system. +func MustGetLogger(module string) *logging.Logger { + l := logging.MustGetLogger(module) + lock.Lock() + defer lock.Unlock() + modules[module] = GetModuleLevel(module) + return l +} + +// InitFromSpec initializes the logging based on the supplied spec. It is +// exposed externally so that consumers of the flogging package may parse their +// own logging specification. The logging specification has the following form: +// [[,...]=][:[[,...]=]...] +func InitFromSpec(spec string) string { + levelAll := defaultLevel + var err error + + if spec != "" { + fields := strings.Split(spec, ":") + for _, field := range fields { + split := strings.Split(field, "=") + switch len(split) { + case 1: + if levelAll, err = logging.LogLevel(field); err != nil { + logger.Warningf("Logging level '%s' not recognized, defaulting to '%s': %s", field, defaultLevel, err) + levelAll = defaultLevel // need to reset cause original value was overwritten + } + case 2: + // [,...]= + levelSingle, err := logging.LogLevel(split[1]) + if err != nil { + logger.Warningf("Invalid logging level in '%s' ignored", field) + continue + } + + if split[0] == "" { + logger.Warningf("Invalid logging override specification '%s' ignored - no module specified", field) + } else { + modules := strings.Split(split[0], ",") + for _, module := range modules { + logger.Debugf("Setting logging level for module '%s' to '%s'", module, levelSingle) + logging.SetLevel(levelSingle, module) + } + } + default: + logger.Warningf("Invalid logging override '%s' ignored - missing ':'?", field) + } + } + } + + logging.SetLevel(levelAll, "") // set the logging level for all modules + + // iterate through modules to reload their level in the modules map based on + // the new default level + for k := range modules { + MustGetLogger(k) + } + // register flogging logger in the modules map + MustGetLogger(pkgLogID) + + return levelAll.String() +} + +// SetPeerStartupModulesMap saves the modules and their log levels. +// this function should only be called at the end of peer startup. +func SetPeerStartupModulesMap() { + lock.Lock() + defer lock.Unlock() + + once.Do(func() { + peerStartModules = make(map[string]string) + for k, v := range modules { + peerStartModules[k] = v + } + }) +} + +// GetPeerStartupLevel returns the peer startup level for the specified module. +// It will return an empty string if the input parameter is empty or the module +// is not found +func GetPeerStartupLevel(module string) string { + if module != "" { + if level, ok := peerStartModules[module]; ok { + return level + } + } + + return "" +} + +// RevertToPeerStartupLevels reverts the log levels for all modules to the level +// defined at the end of peer startup. +func RevertToPeerStartupLevels() error { + lock.RLock() + defer lock.RUnlock() + for key := range peerStartModules { + _, err := setModuleLevel(key, peerStartModules[key], false, true) + if err != nil { + return err + } + } + logger.Info("Log levels reverted to the levels defined at the end of peer startup") + return nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index b82a9508c..7b2bca636 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -465,10 +465,10 @@ "revisionTime": "2016-10-19T17:07:01Z" }, { - "checksumSHA1": "/RlYLEXYPFPm5giiXMQ0G48dO38=", + "checksumSHA1": "n+rDZNHLQEleZZY9JCr1y60LJkM=", "path": "github.com/hyperledger/fabric/bccsp", - "revision": "25dbdeeab8f3d4e431a5434bcee149ee30cf556e", - "revisionTime": "2017-03-01T22:45:42Z", + "revision": "935f608608903bfc171c7d631aedbb70156d62c0", + "revisionTime": "2017-04-24T13:40:27Z", "tree": true }, { @@ -495,6 +495,12 @@ "revision": "9a09ac07644b9f9076abd1d704cbc19f473f6e11", "revisionTime": "2017-02-27T00:00:38Z" }, + { + "checksumSHA1": "JcHPNgBRH9H+EP+GoeV18GZGd5g=", + "path": "github.com/hyperledger/fabric/common/flogging", + "revision": "935f608608903bfc171c7d631aedbb70156d62c0", + "revisionTime": "2017-04-24T13:40:27Z" + }, { "checksumSHA1": "40vJyUB4ezQSn/NSadsKEOrudMc=", "path": "github.com/inconshreveable/mousetrap",