本文基于 fabric v2.0.1,以 peer
节点启动为例讲述 localmsp
、bccsp
初始化过程。
一、BCCSP
BCCSP
是 Blockchain Cryptographic Service Provider 的简称,是常用区块链密码学算法的抽象表示。包含 Hash
、加解密
、签名
、验签
等。
在 Fabric 中提供两种实现方式,一种为 SW (Software)
即纯 Golang
实现(标准库或第三方库),另一种 PKCS11
基于现有 pkcs11 c
库来实现。本文主要关注 SW
实现。
1.1 接口
定义于 bccsp/bccsp.go
// BCCSP is the blockchain cryptographic service provider that offers
// the implementation of cryptographic standards and algorithms.
type BCCSP interface {
// KeyGen generates a key using opts.
KeyGen(opts KeyGenOpts) (k Key, err error)
// KeyDeriv derives a key from k using opts.
// The opts argument should be appropriate for the primitive used.
KeyDeriv(k Key, opts KeyDerivOpts) (dk Key, err error)
// KeyImport imports a key from its raw representation using opts.
// The opts argument should be appropriate for the primitive used.
KeyImport(raw interface{}, opts KeyImportOpts) (k Key, err error)
// GetKey returns the key this CSP associates to
// the Subject Key Identifier ski.
GetKey(ski []byte) (k Key, err error)
// Hash hashes messages msg using options opts.
// If opts is nil, the default hash function will be used.
Hash(msg []byte, opts HashOpts) (hash []byte, err error)
// GetHash returns and instance of hash.Hash using options opts.
// If opts is nil, the default hash function will be returned.
GetHash(opts HashOpts) (h hash.Hash, err error)
// Sign signs digest using key k.
// The opts argument should be appropriate for the algorithm used.
//
// Note that when a signature of a hash of a larger message is needed,
// the caller is responsible for hashing the larger message and passing
// the hash (as digest).
Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error)
// Verify verifies signature against key k and digest
// The opts argument should be appropriate for the algorithm used.
Verify(k Key, signature, digest []byte, opts SignerOpts) (valid bool, err error)
// Encrypt encrypts plaintext using key k.
// The opts argument should be appropriate for the algorithm used.
Encrypt(k Key, plaintext []byte, opts EncrypterOpts) (ciphertext []byte, err error)
// Decrypt decrypts ciphertext using key k.
// The opts argument should be appropriate for the algorithm used.
Decrypt(k Key, ciphertext []byte, opts DecrypterOpts) (plaintext []byte, err error)
}
1.2 实现
SW
实现位于 sw/impl.go
// CSP provides a generic implementation of the BCCSP interface based
// on wrappers. It can be customized by providing implementations for the
// following algorithm-based wrappers: KeyGenerator, KeyDeriver, KeyImporter,
// Encryptor, Decryptor, Signer, Verifier, Hasher. Each wrapper is bound to a
// goland type representing either an option or a key.
type CSP struct {
ks bccsp.KeyStore
KeyGenerators map[reflect.Type]KeyGenerator
KeyDerivers map[reflect.Type]KeyDeriver
KeyImporters map[reflect.Type]KeyImporter
Encryptors map[reflect.Type]Encryptor
Decryptors map[reflect.Type]Decryptor
Signers map[reflect.Type]Signer
Verifiers map[reflect.Type]Verifier
Hashers map[reflect.Type]Hasher
}
具体密码学算法实现通过 AddWrapper 方法注入,Fabric 内置支持注册如下:
代码位于 sw/new.go
// NewWithParams returns a new instance of the software-based BCCSP
// set at the passed security level, hash family and KeyStore.
func NewWithParams(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) {
// Init config
conf := &config{}
err := conf.setSecurityLevel(securityLevel, hashFamily)
if err != nil {
return nil, errors.Wrapf(err, "Failed initializing configuration at [%v,%v]", securityLevel, hashFamily)
}
swbccsp, err := New(keyStore)
if err != nil {
return nil, err
}
// Notice that errors are ignored here because some test will fail if one
// of the following call fails.
// Set the Encryptors
swbccsp.AddWrapper(reflect.TypeOf(&aesPrivateKey{}), &aescbcpkcs7Encryptor{})
// Set the Decryptors
swbccsp.AddWrapper(reflect.TypeOf(&aesPrivateKey{}), &aescbcpkcs7Decryptor{})
// Set the Signers
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaSigner{})
// Set the Verifiers
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaPrivateKeyVerifier{})
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPublicKey{}), &ecdsaPublicKeyKeyVerifier{})
// Set the Hashers
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.SHAOpts{}), &hasher{hash: conf.hashFunction})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.SHA256Opts{}), &hasher{hash: sha256.New})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.SHA384Opts{}), &hasher{hash: sha512.New384})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.SHA3_256Opts{}), &hasher{hash: sha3.New256})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.SHA3_384Opts{}), &hasher{hash: sha3.New384})
// Set the key generators
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAKeyGenOpts{}), &ecdsaKeyGenerator{curve: conf.ellipticCurve})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAP256KeyGenOpts{}), &ecdsaKeyGenerator{curve: elliptic.P256()})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAP384KeyGenOpts{}), &ecdsaKeyGenerator{curve: elliptic.P384()})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AESKeyGenOpts{}), &aesKeyGenerator{length: conf.aesBitLength})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES256KeyGenOpts{}), &aesKeyGenerator{length: 32})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES192KeyGenOpts{}), &aesKeyGenerator{length: 24})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES128KeyGenOpts{}), &aesKeyGenerator{length: 16})
// Set the key deriver
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaPrivateKeyKeyDeriver{})
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPublicKey{}), &ecdsaPublicKeyKeyDeriver{})
swbccsp.AddWrapper(reflect.TypeOf(&aesPrivateKey{}), &aesPrivateKeyKeyDeriver{conf: conf})
// Set the key importers
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.AES256ImportKeyOpts{}), &aes256ImportKeyOptsKeyImporter{})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.HMACImportKeyOpts{}), &hmacImportKeyOptsKeyImporter{})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAPKIXPublicKeyImportOpts{}), &ecdsaPKIXPublicKeyImportOptsKeyImporter{})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAPrivateKeyImportOpts{}), &ecdsaPrivateKeyImportOptsKeyImporter{})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.ECDSAGoPublicKeyImportOpts{}), &ecdsaGoPublicKeyImportOptsKeyImporter{})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.X509PublicKeyImportOpts{}), &x509PublicKeyImportOptsKeyImporter{bccsp: swbccsp})
return swbccsp, nil
}
二、MSP
MSP
即 Membership Service Provider,Fabric 使用 PKI
体系来组织管理整个网络内的身份、组织、权限等。更多见 MSP详解(一)-MSP基础。
同样,Fabric 也为 MSP
提供两种实现:FABRIC
、IDEMIX
,Fabric 2.0只能使用标准实现 FABRIC
,详情见 node/start.go。本文只关注 FABRIC
实现即基于 bccsp
的实现。
2.1 接口定义
接口定义于 msp/msp.go
// MSP is the minimal Membership Service Provider Interface to be implemented
// to accommodate peer functionality
type MSP interface {
// IdentityDeserializer interface needs to be implemented by MSP
IdentityDeserializer
// Setup the MSP instance according to configuration information
Setup(config *msp.MSPConfig) error
// GetVersion returns the version of this MSP
GetVersion() MSPVersion
// GetType returns the provider type
GetType() ProviderType
// GetIdentifier returns the provider identifier
GetIdentifier() (string, error)
// GetSigningIdentity returns a signing identity corresponding to the provided identifier
GetSigningIdentity(identifier *IdentityIdentifier) (SigningIdentity, error)
// GetDefaultSigningIdentity returns the default signing identity
GetDefaultSigningIdentity() (SigningIdentity, error)
// GetTLSRootCerts returns the TLS root certificates for this MSP
GetTLSRootCerts() [][]byte
// GetTLSIntermediateCerts returns the TLS intermediate root certificates for this MSP
GetTLSIntermediateCerts() [][]byte
// Validate checks whether the supplied identity is valid
Validate(id Identity) error
// SatisfiesPrincipal checks whether the identity matches
// the description supplied in MSPPrincipal. The check may
// involve a byte-by-byte comparison (if the principal is
// a serialized identity) or may require MSP validation
SatisfiesPrincipal(id Identity, principal *msp.MSPPrincipal) error
}
2.2 实现
基于 bccsp
的最新版本为 MSPv1_4_3
,定义见 msp/mspimpl.go
// newBccspMsp returns an MSP instance backed up by a BCCSP
// crypto provider. It handles x.509 certificates and can
// generate identities and signing identities backed by
// certificates and keypairs
func newBccspMsp(version MSPVersion, defaultBCCSP bccsp.BCCSP) (MSP, error) {
mspLogger.Debugf("Creating BCCSP-based MSP instance")
theMsp := &bccspmsp{}
theMsp.version = version
theMsp.bccsp = defaultBCCSP
switch version {
case MSPv1_0: ...
case MSPv1_1: ...
case MSPv1_3: ...
case MSPv1_4_3:
theMsp.internalSetupFunc = theMsp.setupV142
theMsp.internalValidateIdentityOusFunc = theMsp.validateIdentityOUsV142
theMsp.internalSatisfiesPrincipalInternalFunc = theMsp.satisfiesPrincipalInternalV142
theMsp.internalSetupAdmin = theMsp.setupAdminsV142
default:
return nil, errors.Errorf("Invalid MSP version [%v]", version)
}
return theMsp, nil
}
通过 Setup 方法进行初始化:
// Setup sets up the internal data structures
// for this MSP, given an MSPConfig ref; it
// returns nil in case of success or an error otherwise
func (msp *bccspmsp) Setup(conf1 *m.MSPConfig) error {
if conf1 == nil {
return errors.New("Setup error: nil conf reference")
}
// given that it's an msp of type fabric, extract the MSPConfig instance
conf := &m.FabricMSPConfig{}
err := proto.Unmarshal(conf1.Config, conf)
if err != nil {
return errors.Wrap(err, "failed unmarshalling fabric msp config")
}
// set the name for this msp
msp.name = conf.Name
mspLogger.Debugf("Setting up MSP instance %s", msp.name)
// setup
return msp.internalSetupFunc(conf)
}
这里不作进一步展开, setup
过程主要是对各证书的处理。
三、初始化过程
以 peer node start
为例,了解 bccsp
, localmsp
初始化过程
3.1 配置
Note:MSP
标准实现 FABRIC
配置类型标识为 peer.localMspType: bccsp
peer:
# BCCSP (Blockchain crypto provider): Select which crypto implementation or
# library to use
BCCSP:
Default: SW
# Settings for the SW crypto provider (i.e. when DEFAULT: SW)
SW:
# TODO: The default Hash and Security level needs refactoring to be
# fully configurable. Changing these defaults requires coordination
# SHA2 is hardcoded in several places, not only BCCSP
Hash: SHA2
Security: 256
# Location of Key Store
FileKeyStore:
# If "", defaults to 'mspConfigPath'/keystore
KeyStore:
# Path on the file system where peer will find MSP local configurations
mspConfigPath: msp
# Identifier of the local MSP
# ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!----
# Deployers need to change the value of the localMspId string.
# In particular, the name of the local MSP ID of a peer needs
# to match the name of one of the MSPs in each of the channel
# that this peer is a member of. Otherwise this peer's messages
# will not be identified as valid by other nodes.
localMspId: SampleOrg
# Type for the local MSP - by default it's of type bccsp
localMspType: bccsp
3.2 初始化过程
调用入口位于 cobra Command
的 PersistentPreRun
钩子定义 node/node.go
初始化入口 InitCmd
func InitCmd(cmd *cobra.Command, args []string) {
...
// Init the MSP
var mspMgrConfigDir = config.GetPath("peer.mspConfigPath")
var mspID = viper.GetString("peer.localMspId")
var mspType = viper.GetString("peer.localMspType")
if mspType == "" {
mspType = msp.ProviderTypeToString(msp.FABRIC)
}
err = InitCrypto(mspMgrConfigDir, mspID, mspType)
if err != nil { // Handle errors reading the config file
mainLogger.Errorf("Cannot run peer because %s", err.Error())
os.Exit(1)
}
}
详细调用栈如下:
InitCmd in github.com/hyperledger/fabric/internal/peer/common/common.go
InitCrypto in github.com/hyperledger/fabric/internal/peer/common/common.go
LoadLocalMspWithType in github.com/hyperledger/fabric/msp/mgmt/mgmt.go
GetLocalMspConfigWithType in github.com/hyperledger/fabric/msp/configbuilder.go
GetLocalMspConfig in github.com/hyperledger/fabric/msp/configbuilder.go
// 初始化 bccsp
InitFactories in github.com/hyperledger/fabric/bccsp/factory/nopkcs11.go
initBCCSP in github.com/hyperledger/fabric/bccsp/factory/factory.go
*SWFactory.Get in github.com/hyperledger/fabric/bccsp/factory/swfactory.go
NewWithParams in github.com/hyperledger/fabric/bccsp/sw/new.go
New in github.com/hyperledger/fabric/bccsp/sw/impl.go
AddWrapper (26 usages) in github.com/hyperledger/fabric/bccsp/sw/impl.go
getPemMaterialFromDir in github.com/hyperledger/fabric/msp/configbuilder.go
getMspConfig in github.com/hyperledger/fabric/msp/configbuilder.go
GetDefault in github.com/hyperledger/fabric/bccsp/factory/factory.go
GetLocalMSP in github.com/hyperledger/fabric/msp/mgmt/mgmt.go
loadLocaMSP in github.com/hyperledger/fabric/msp/mgmt/mgmt.go
New in github.com/hyperledger/fabric/msp/factory.go
newBccspMsp in github.com/hyperledger/fabric/msp/mspimpl.go
New in github.com/hyperledger/fabric/msp/cache/cache.go
*bccspmsp.Setup in github.com/hyperledger/fabric/msp/mspimpl.go
*bccspmsp.setupV142 in github.com/hyperledger/fabric/msp/mspimpl.go
*bccspmsp.preSetupV142 in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupCrypto in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupCAs in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupCRLs in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.finalizeSetupCAs in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupSigningIdentity in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupTLSCAs in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupOUs in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupNodeOUsV142 in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.setupAdmins in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.postSetupV142 in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.postSetupV1 in github.com/hyperledger/fabric/msp/mspimplsetup.go
*bccspmsp.hasOURole (2 usages) in github.com/hyperledger/fabric/msp/mspimpl.go
顺序图如下: