Hyperledger Fabrica 2.0 MSP & BCCSP

本文基於 fabric v2.0.1,以 peer 節點啓動爲例講述 localmspbccsp 初始化過程。

一、BCCSP


BCCSPBlockchain 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


MSPMembership Service Provider,Fabric 使用 PKI 體系來組織管理整個網絡內的身份、組織、權限等。更多見 MSP詳解(一)-MSP基礎

同樣,Fabric 也爲 MSP 提供兩種實現:FABRICIDEMIX ,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 配置


NoteMSP 標準實現 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 CommandPersistentPreRun 鉤子定義 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

順序圖如下:

peer/commonmsp/mgmtmsp/cachefabric/mspbccsp/factorybccsp/swLoadLocalMspWithTypeGetLocalMspConfigWithTypeGetLocalMspConfigInitFactoriesinitBCCSP*SWFactory.GetNewFileBasedKeyStoreNewWithParamsNew*CSP.AddWrapperloop[ add crypto algorithm ]opt[ First Call ]getMspConfigGetDefaultGetLocalMSPloadLocaMSPNewnewBccspMspNewopt[ localMsp is nil ]*cachedMSP.Setup*cachedMSP.cleanCache*bccspmsp.Setup*bccspmsp.setupV142*bccspmsp.preSetupV142error*bccspmsp.postSetupV142errorerrorpeer/commonmsp/mgmtmsp/cachefabric/mspbccsp/factorybccsp/sw
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章