一、介紹
在前面分析了MSP的基本的流程和源碼,但是還是有些疏漏,這裡補充一下,同時把相關的BCCSP的部分分析一下,充實整個的加密系統。在MSP中主要對配置管理和證書驗證進行一下分析;BCCSP則從整體流程和相關源碼進行一下分析。
二、MSP的補遺
1、配置管理
在前面的Peer節點的啟動裡,從主函數裡mainCmd.AddCommand(node.Cmd()),而在node.Cmd()中會有:
var nodeCmd = &cobra.Command{
Use: nodeFuncName,
Short: fmt.Sprint(nodeCmdDes),
Long: fmt.Sprint(nodeCmdDes),
PersistentPreRun: common.InitCmd,
}
在PersistentPreRun(即common.Initcmd)中調用InitCrypto(mspMgrConfigDir, mspID, mspType)。
其流程為:調用mainCmd.Execute(),從這裡開始其實已經是第三方的指令庫cobra,會逐次調用ExecuteC–>cmd.execute,在這個函數裡調用PersistentPreRun(common.InitCmd)。其又會調用InitCrypto這個函數:
看一下這個函數:
//fabric\peer\common\common.go
// InitCrypto initializes crypto for this peer
func InitCrypto(mspMgrConfigDir, localMSPID, localMSPType string) error {
var err error
// Check whether msp folder exists
fi, err := os.Stat(mspMgrConfigDir)
if os.IsNotExist(err) || !fi.IsDir() {
// No need to try to load MSP from folder which is not available
return errors.Errorf("cannot init crypto, folder \"%s\" does not exist", mspMgrConfigDir)
}
// Check whether localMSPID exists
if localMSPID == "" {
return errors.New("the local MSP must have an ID")
}
// Init the BCCSP
SetBCCSPKeystorePath()
var bccspConfig *factory.FactoryOpts
err = viperutil.EnhancedExactUnmarshalKey("peer.BCCSP", &bccspConfig)
if err != nil {
return errors.WithMessage(err, "could not parse YAML config")
}
err = mspmgmt.LoadLocalMspWithType(mspMgrConfigDir, bccspConfig, localMSPID, localMSPType)
if err != nil {
return errors.WithMessage(err, fmt.Sprintf("error when setting up MSP of type %s from directory %s", localMSPType, mspMgrConfigDir))
}
return nil
}
這個函數其實就是開始了加密的初始化,這其中肯定會包括相關的配置:
// LoadLocalMspWithType loads the local MSP with the specified type from the specified directory
func LoadLocalMspWithType(dir string, bccspConfig *factory.FactoryOpts, mspID, mspType string) error {
if mspID == "" {
return errors.New("the local MSP must have an ID")
}
conf, err := msp.GetLocalMspConfigWithType(dir, bccspConfig, mspID, mspType)
if err != nil {
return err
}
return GetLocalMSP().Setup(conf)
}
// GetLocalMspConfigWithType returns a local MSP
// configuration for the MSP in the specified
// directory, with the specified ID and type
func GetLocalMspConfigWithType(dir string, bccspConfig *factory.FactoryOpts, ID, mspType string) (*msp.MSPConfig, error) {
switch mspType {
case ProviderTypeToString(FABRIC):
return GetLocalMspConfig(dir, bccspConfig, ID)
case ProviderTypeToString(IDEMIX):
return GetIdemixMspConfig(dir, ID)
default:
return nil, errors.Errorf("unknown MSP type '%s'", mspType)
}
}
最後都會調用:
func GetLocalMspConfig(dir string, bccspConfig *factory.FactoryOpts, ID string) (*msp.MSPConfig, error) {
//簽名者身份證書檔案路徑
signcertDir := filepath.Join(dir, signcerts)
//私鑰存儲檔案路徑
keystoreDir := filepath.Join(dir, keystore)
//基于私鑰檔案位置來建立BCCSP配置對象
bccspConfig = SetupBCCSPKeystoreConfig(bccspConfig, keystoreDir)
//由建立的BCCSP對象來初始化BCCSP工廠元件
err := factory.InitFactories(bccspConfig)
if err != nil {
return nil, errors.WithMessage(err, "could not initialize BCCSP Factories")
}
//從指定的路徑讀取簽名身份證書檔案清單
signcert, err := getPemMaterialFromDir(signcertDir)
if err != nil || len(signcert) == 0 {
return nil, errors.Wrapf(err, "could not load a valid signer certificate from directory %s", signcertDir)
}
/* FIXME: for now we're making the following assumptions
1) there is exactly one signing cert
2) BCCSP's KeyStore has the private key that matches SKI of
signing cert
*/
//基于隻有一個身份證書建構簽名者身份ID資訊
sigid := &msp.SigningIdentityInfo{PublicSigner: signcert[0], PrivateSigner: nil}
//建構MSP配置對象
return getMspConfig(dir, ID, sigid)
}
這個函數在前面已經分析過了。看一下最後一個函數:
func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.MSPConfig, error) {
//CA憑證路徑
cacertDir := filepath.Join(dir, cacerts)
//Administration證書路徑
admincertDir := filepath.Join(dir, admincerts)
//中間CA憑證路徑
intermediatecertsDir := filepath.Join(dir, intermediatecerts)
//CRL可撤銷證書路徑
crlsDir := filepath.Join(dir, crlsfolder)
//配置檔案路徑
configile := filepath.Join(dir, configfilename)
//TLS認證CA憑證路徑
tlscacertDir := filepath.Join(dir, tlscacerts)
//TLS中間CA憑證路徑
tlsintermediatecertsDir := filepath.Join(dir, tlsintermediatecerts)
cacerts, err := getPemMaterialFromDir(cacertDir)
if err != nil || len(cacerts) == 0 {
return nil, errors.WithMessage(err, fmt.Sprintf("could not load a valid ca certificate from directory %s", cacertDir))
}
admincert, err := getPemMaterialFromDir(admincertDir)
if err != nil && !os.IsNotExist(err) {
return nil, errors.WithMessage(err, fmt.Sprintf("could not load a valid admin certificate from directory %s", admincertDir))
}
intermediatecerts, err := getPemMaterialFromDir(intermediatecertsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("Intermediate certs folder not found at [%s]. Skipping. [%s]", intermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading intermediate ca certs at [%s]", intermediatecertsDir))
}
//根據指定的路徑來讀取身份證書上所有的簽名者身份證書檔案清單Signcert(格式可能随版本變化 )
tlsCACerts, err := getPemMaterialFromDir(tlscacertDir)
tlsIntermediateCerts := [][]byte{}
if os.IsNotExist(err) {
mspLogger.Debugf("TLS CA certs folder not found at [%s]. Skipping and ignoring TLS intermediate CA folder. [%s]", tlsintermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading TLS ca certs at [%s]", tlsintermediatecertsDir))
} else if len(tlsCACerts) != 0 {
tlsIntermediateCerts, err = getPemMaterialFromDir(tlsintermediatecertsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("TLS intermediate certs folder not found at [%s]. Skipping. [%s]", tlsintermediatecertsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading TLS intermediate ca certs at [%s]", tlsintermediatecertsDir))
}
} else {
mspLogger.Debugf("TLS CA certs folder at [%s] is empty. Skipping.", tlsintermediatecertsDir)
}
crls, err := getPemMaterialFromDir(crlsDir)
if os.IsNotExist(err) {
mspLogger.Debugf("crls folder not found at [%s]. Skipping. [%s]", crlsDir, err)
} else if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("failed loading crls at [%s]", crlsDir))
}
// Load configuration file
// if the configuration file is there then load it
// otherwise skip it
var ouis []*msp.FabricOUIdentifier
var nodeOUs *msp.FabricNodeOUs
_, err = os.Stat(configFile)
if err == nil {
// load the file, if there is a failure in loading it then
// return an error
raw, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, errors.Wrapf(err, "failed loading configuration file at [%s]", configFile)
}
configuration := Configuration{}
err = yaml.Unmarshal(raw, &configuration)
if err != nil {
return nil, errors.Wrapf(err, "failed unmarshalling configuration file at [%s]", configFile)
}
// Prepare OrganizationalUnitIdentifiers =OUS
if len(configuration.OrganizationalUnitIdentifiers) > 0 {
for _, ouID := range configuration.OrganizationalUnitIdentifiers {
f := filepath.Join(dir, ouID.Certificate)
raw, err = readFile(f)
if err != nil {
return nil, errors.Wrapf(err, "failed loading OrganizationalUnit certificate at [%s]", f)
}
oui := &msp.FabricOUIdentifier{
Certificate: raw,
OrganizationalUnitIdentifier: ouID.OrganizationalUnitIdentifier,
}
ouis = append(ouis, oui)
}
}
// Prepare NodeOUs
if configuration.NodeOUs != nil && configuration.NodeOUs.Enable {
mspLogger.Debug("Loading NodeOUs")
nodeOUs = &msp.FabricNodeOUs{
Enable: true,
}
if configuration.NodeOUs.ClientOUIdentifier != nil && len(configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier) != 0 {
nodeOUs.ClientOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier}
}
if configuration.NodeOUs.PeerOUIdentifier != nil && len(configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier) != 0 {
nodeOUs.PeerOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier}
}
if configuration.NodeOUs.AdminOUIdentifier != nil && len(configuration.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier) != 0 {
nodeOUs.AdminOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.AdminOUIdentifier.OrganizationalUnitIdentifier}
}
if configuration.NodeOUs.OrdererOUIdentifier != nil && len(configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier) != 0 {
nodeOUs.OrdererOuIdentifier = &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier}
}
// Read certificates, if defined
// ClientOU
if nodeOUs.ClientOuIdentifier != nil {
nodeOUs.ClientOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.ClientOUIdentifier.Certificate, "ClientOU")
}
// PeerOU
if nodeOUs.PeerOuIdentifier != nil {
nodeOUs.PeerOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.PeerOUIdentifier.Certificate, "PeerOU")
}
// AdminOU
if nodeOUs.AdminOuIdentifier != nil {
nodeOUs.AdminOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.AdminOUIdentifier.Certificate, "AdminOU")
}
// OrdererOU
if nodeOUs.OrdererOuIdentifier != nil {
nodeOUs.OrdererOuIdentifier.Certificate = loadCertificateAt(dir, configuration.NodeOUs.OrdererOUIdentifier.Certificate, "OrdererOU")
}
}
} else {
mspLogger.Debugf("MSP configuration file not found at [%s]: [%s]", configFile, err)
}
// Set FabricCryptoConfig密碼配置對象
cryptoConfig := &msp.FabricCryptoConfig{
SignatureHashFamily: bccsp.SHA2,
IdentityIdentifierHashFunction: bccsp.SHA256,
}
// Compose FabricMSPConfig
fmspconf := &msp.FabricMSPConfig{
Admins: admincert,
RootCerts: cacerts,
IntermediateCerts: intermediatecerts,
SigningIdentity: sigid,
Name: ID,
OrganizationalUnitIdentifiers: ouis,
RevocationList: crls,
CryptoConfig: cryptoConfig,
TlsRootCerts: tlsCACerts,
TlsIntermediateCerts: tlsIntermediateCerts,
FabricNodeOus: nodeOUs,
}
fmpsjs, _ := proto.Marshal(fmspconf)
mspconf := &msp.MSPConfig{Config: fmpsjs, Type: int32(FABRIC)}
return mspconf, nil
}
這裡其實重點要搞明白OU,節點組織單元對象:一個檔案 config.yaml 用來包含已經考慮過的 OU 的資訊;他們會在之後被定義為一組在被稱為 OrganizationalUnitIdentifiers 的yaml數組中的實體,也即 <Certificate, OrganizationalUnitIdentifier>,其中的 Certificate 代表着到證書機構的證書(root 的或者 intermediate 的)的相對路徑。這些證書是被認為是組織單元(organizational unit 也就是 OU)中的已證明成員說擁有的。而 OrganizationalUnitIdentifier 代表着理應在 X.509 證書中的 OU-field 中出現的實際字元串。
getMspConfig這個函數,首先得到基本的資訊如各種證書的路徑,并通過這些路徑來得到相關的對象(清單)。然後對MSP元件的節點組織單元對象進行處理,最後設定密碼配置對象,包括相關的簽名和生成ID的哈希函數(前者為SHA2,後者為SHA256)。
2、身份證書的驗證
身份證書的驗證在前面MSP源碼分析newBccspMsp中看到過驗證的初始化函數,theMsp.internalValidateIdentityOusFunc = theMsp.validateIdentityOUsV1類似這些代碼。看下面提供的驗證流程代碼:
//msp/mspimpl.go
func (msp *bccspmsp) Validate(id Identity) error {
mspLogger.Debugf("MSP %s validating identity", msp.name)
switch id := id.(type) {
// If this identity is of this specific type,
// this is how I can validate it given the
// root of trust this MSP has
case *identity:
return msp.validateIdentity(id)
default:
return errors.New("identity type not recognized")
}
}
//msp/mspimplvalidate.go
func (msp *bccspmsp) validateIdentity(id *identity) error {
//獲得身份驗證的證書的驗證鍊,也就是建立所有從根證書池認證簽發路徑上的證書所組成的有序證書鍊
validationChain, err := msp.getCertificationChainForBCCSPIdentity(id)
if err != nil {
return errors.WithMessage(err, "could not obtain certification chain")
}
//驗證是不是屬于CRL,證書撤銷清單中的項,進而判斷其有效性
err = msp.validateIdentityAgainstChain(id, validationChain)
if err != nil {
return errors.WithMessage(err, "could not validate identity against certification chain")
}
//驗證身份證書的組織單元 和MSP元件包含的組織單元是否有交集
err = msp.internalValidateIdentityOusFunc(id)
if err != nil {
return errors.WithMessage(err, "could not validate identity's OUs")
}
return nil
}
下來分别看一看validateIdentity中調用的三個函數:
// getCertificationChainForBCCSPIdentity returns the certification chain of the passed bccsp identity within this msp
func (msp *bccspmsp) getCertificationChainForBCCSPIdentity(id *identity) ([]*x509.Certificate, error) {
if id == nil {
return nil, errors.New("Invalid bccsp identity. Must be different from nil.")
}
// we expect to have a valid VerifyOptions instance
if msp.opts == nil {
return nil, errors.New("Invalid msp instance")
}
// CAs cannot be directly used as identities..
if id.cert.IsCA {
return nil, errors.New("An X509 certificate with Basic Constraint: " +
"Certificate Authority equals true cannot be used as an identity")
}
return msp.getValidationChain(id.cert, false)
}
func (msp *bccspmsp) getValidationChain(cert *x509.Certificate, isIntermediateChain bool) ([]*x509.Certificate, error) {
//獲驗證書驗證選項
validationChain, err := msp.getUniqueValidationChain(cert, msp.getValidityOptsForCert(cert))
if err != nil {
return nil, errors.WithMessage(err, "failed getting validation chain")
}
// we expect a chain of length at least 2
//長度至少為2,因為一定不會用根證書去驗證
if len(validationChain) < 2 {
return nil, errors.Errorf("expected a chain of length at least 2, got %d", len(validationChain))
}
// check that the parent is a leaf of the certification tree
// if validating an intermediate chain, the first certificate will the parent
parentPosition := 1
if isIntermediateChain {
parentPosition = 0
}
//檢查父證書是否是證書樹的一個葉子節點
//true表示為中間節點證書,false表示是葉子節點證書,MSP的簽名必須為false,即葉子節點,否則報錯
if msp.certificationTreeInternalNodesMap[string(validationChain[parentPosition].Raw)] {
return nil, errors.Errorf("invalid validation chain. Parent certificate should be a leaf of the certification tree [%v]", cert.Raw)
}
return validationChain, nil
}
func (msp *bccspmsp) getUniqueValidationChain(cert *x509.Certificate, opts x509.VerifyOptions) ([]*x509.Certificate, error) {
// ask golang to validate the cert for us based on the options that we've built at setup time
if msp.opts == nil {
return nil, errors.New("the supplied identity has no verify options")
}
validationChains, err := cert.Verify(opts)
if err != nil {
return nil, errors.WithMessage(err, "the supplied identity is not valid")
}
// we only support a single validation chain;
// if there's more than one then there might
// be unclarity about who owns the identity
if len(validationChains) != 1 {
return nil, errors.Errorf("this MSP only supports a single validation chain, got %d", len(validationChains))
}
return validationChains[0], nil
}
第一個函數主要是用來擷取身份證書鍊,也就是從根CA到中間CA到應用CA的所有證書。它最後又調用了getValidationChain這個函數,它才是真正獲驗證書鍊的函數。在這個函數裡,首先調用getUniqueValidationChain來得到證書鍊,certificationTreeInternalNodesMap表示由中間證書和根證書組成的樹形結構,而中間證書都是葉子節點,這也是前面說必須為葉子節點簽名才可以。
下面來看第二個函數:
func (msp *bccspmsp) validateIdentityAgainstChain(id *identity, validationChain []*x509.Certificate) error {
return msp.validateCertAgainstChain(id.cert, validationChain)
}
func (msp *bccspmsp) validateCertAgainstChain(cert *x509.Certificate, validationChain []*x509.Certificate) error {
// here we know that the identity is valid; now we have to check whether it has been revoked
// identify the SKI of the CA that signed this cert
SKI, err := getSubjectKeyIdentifierFromCert(validationChain[1])
if err != nil {
return errors.WithMessage(err, "could not obtain Subject Key Identifier for signer cert")
}
// check whether one of the CRLs we have has this cert's
// SKI as its AuthorityKeyIdentifier
for _, crl := range msp.CRL {
aki, err := getAuthorityKeyIdentifierFromCrl(crl)
if err != nil {
return errors.WithMessage(err, "could not obtain Authority Key Identifier for crl")
}
// check if the SKI of the cert that signed us matches the AKI of any of the CRLs
if bytes.Equal(aki, SKI) {
// we have a CRL, check whether the serial number is revoked
for _, rc := range crl.TBSCertList.RevokedCertificates {
if rc.SerialNumber.Cmp(cert.SerialNumber) == 0 {
// We have found a CRL whose AKI matches the SKI of
// the CA (root or intermediate) that signed the
// certificate that is under validation. As a
// precaution, we verify that said CA is also the
// signer of this CRL.
err = validationChain[1].CheckCRLSignature(crl)
if err != nil {
// the CA cert that signed the certificate
// that is under validation did not sign the
// candidate CRL - skip
mspLogger.Warningf("Invalid signature over the identified CRL, error %+v", err)
continue
}
// A CRL also includes a time of revocation so that
// the CA can say "this cert is to be revoked starting
// from this time"; however here we just assume that
// revocation applies instantaneously from the time
// the MSP config is committed and used so we will not
// make use of that field
return errors.New("The certificate has been revoked")
}
}
}
}
return nil
}
第二個函數主要調用validateCertAgainstChain函數來驗證證書是否存在于CRL可撤銷證書清單中。它首先擷取上級簽發的CA憑證的使用者密鑰辨別符SKI,周遊MSP元件所有的證書清單msp.CRL,擷取每個CRL的頒發機構密鑰辨別符AKI,然後基于位元組比較SKI 、AKI是否相同,如果二者比對,則繼續檢查CRL中撤銷證書的序列号rc.SerialNumber。如果該序列号與指定的身份證書的序列号cert.SerialNumber相同,則調用CheckCRLSignature方法繼續級簽發CA節點是否為該CRL的簽名者,如果确定仍然為同一個簽名者,則說明指定身份證書cert已經被撤銷。
再看第三個函數,在前面的newBccspMsp函數中,發現不同的MSP版本,提供了不同的internalValidateIdentityOusFunc,來看一下最新的:
func (msp *bccspmsp) validateIdentityOUsV143(id *identity) error {
// Run the same checks as per V1
err := msp.validateIdentityOUsV1(id)
if err != nil {
return err
}
// -- Check for OU enforcement
if !msp.ouEnforcement {
// No enforcement required
return nil
}
// Make sure that the identity has only one of the special OUs
// used to tell apart clients, peers and admins.
counter := 0
validOUs := make(map[string]*OUIdentifier)
if msp.clientOU != nil {
validOUs[msp.clientOU.OrganizationalUnitIdentifier] = msp.clientOU
}
if msp.peerOU != nil {
validOUs[msp.peerOU.OrganizationalUnitIdentifier] = msp.peerOU
}
if msp.adminOU != nil {
validOUs[msp.adminOU.OrganizationalUnitIdentifier] = msp.adminOU
}
if msp.ordererOU != nil {
validOUs[msp.ordererOU.OrganizationalUnitIdentifier] = msp.ordererOU
}
for _, OU := range id.GetOrganizationalUnits() {
// Is OU.OrganizationalUnitIdentifier one of the special OUs?
nodeOU := validOUs[OU.OrganizationalUnitIdentifier]
if nodeOU == nil {
continue
}
// Yes. Then, enforce the certifiers identifier in this is specified.
// If is not specified, it means that any certification path is fine.
if len(nodeOU.CertifiersIdentifier) != 0 && !bytes.Equal(nodeOU.CertifiersIdentifier, OU.CertifiersIdentifier) {
return errors.Errorf("certifiersIdentifier does not match: [%v], MSP: [%s]", id.GetOrganizationalUnits(), msp.name)
}
//保證證書隻能為用戶端、PEER、ORDER或者Admin中的一個。
counter++
if counter > 1 {
break
}
}
if counter != 1 {
return errors.Errorf("the identity must be a client, a peer, an orderer or an admin identity to be valid, not a combination of them. OUs: [%v], MSP: [%s]", id.GetOrganizationalUnits(), msp.name)
}
return nil
}
func (msp *bccspmsp) validateIdentityOUsV1(id *identity) error {
// Check that the identity's OUs are compatible with those recognized by this MSP,
// meaning that the intersection is not empty.
if len(msp.ouIdentifiers) > 0 {
found := false
//周遊組織單元辨別清單
for _, OU := range id.GetOrganizationalUnits() {
certificationIDs, exists := msp.ouIdentifiers[OU.OrganizationalUnitIdentifier]
if exists {
//周遊證書辨別符ID清單
for _, certificationID := range certificationIDs {
if bytes.Equal(certificationID, OU.CertifiersIdentifier) {
found = true
break
}
}
}
}
if !found {
if len(id.GetOrganizationalUnits()) == 0 {
return errors.New("the identity certificate does not contain an Organizational Unit (OU)")
}
return errors.Errorf("none of the identity's organizational units [%v] are in MSP %s", id.GetOrganizationalUnits(), msp.name)
}
}
return nil
}
其它的驗證還有包括類似諸如零知識證明等的方式,有興趣可以看一看源碼。
二、BCCSP
1、整體架構
BCCSP是整個Fabric中的基礎的子產品,所有的加密簽名部分基本都需要從這裡來支援。看一下他的基礎的類圖:

包圖:
2、啟動流程
BCCSP是整個Fabric中的基礎子產品之一加密子產品,整個系統運作需要的加密、解密、簽名及驗證、哈希以及相關的零知識證明以及後續的疊代演進,諸如支援國密或者其它加密算法的接口都在這個子產品之中。它主要提供了兩大類的加密方式即硬體加密方式(PKCS11,基于HSM硬體安全子產品)和SM類型的軟體加密服務(使用的GO本身提供的算法庫)。在提供的這兩類加密算法的基礎上,抽象出來了相關的對象工廠以及相關的加密函數接口。
在Fabric中很多地方都會啟動對BCCSP包的調用,這裡在分析MSP,是以就把其相關的factory和BCCSP包啟動看一下:
BCCSP工廠啟動和初始化的過程:
函數調用GetLocalMspConfig()->InitFactories()
func InitFactories(config *FactoryOpts) error {
factoriesInitOnce.Do(func() {
setFactories(config)
})
return factoriesInitError
}
func setFactories(config *FactoryOpts) error {
// Take some precautions on default opts
if config == nil {
config = GetDefaultOpts()
}
if config.ProviderName == "" {
config.ProviderName = "SW"
}
if config.SwOpts == nil {
config.SwOpts = GetDefaultOpts().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 = errors.Wrap(err, "Failed initializing SW.BCCSP")
}
}
// PKCS11-Based BCCSP
if config.Pkcs11Opts != nil {
f := &PKCS11Factory{}
err := initBCCSP(f, config)
if err != nil {
factoriesInitError = errors.Wrapf(err, "Failed initializing PKCS11.BCCSP %s", factoriesInitError)
}
}
// BCCSP Plugin
if config.PluginOpts != nil {
f := &PluginFactory{}
err := initBCCSP(f, config)
if err != nil {
factoriesInitError = errors.Wrapf(err, "Failed initializing PKCS11.BCCSP %s", factoriesInitError)
}
}
var ok bool
defaultBCCSP, ok = bccspMap[config.ProviderName]
if !ok {
factoriesInitError = errors.Errorf("%s\nCould not find default `%s` BCCSP", factoriesInitError, config.ProviderName)
}
return factoriesInitError
}
func initBCCSP(f BCCSPFactory, config *FactoryOpts) error {
//在此處其實是實作了三個工廠類即:pck11,plugin,sw
csp, err := f.Get(config)
if err != nil {
return errors.Errorf("Could not initialize BCCSP %s [%s]", f.Name(), err)
}
logger.Debugf("Initialize BCCSP [%s]", f.Name())
//csp的映射存儲,在以後就可以通過工廠Name來得到相應的BCCSP操作對象
bccspMap[f.Name()] = csp
return nil
}
BCCSP的啟動和初始化過程:
函數調用的順序:GetLocalMSP()->LoadLocalMsp()->New()->newBccspMsp():
unc newBccspMsp(version MSPVersion) (MSP, error) {
mspLogger.Debugf("Creating BCCSP-based MSP instance")
bccsp := factory.GetDefault()
......
return theMsp, nil
}
這個函數中前面提到好多次,這個函數一開始就建立相關的BCCSP對象執行個體。調用相關工廠類的預設建立函數。看一下他的實作:
func GetDefault() bccsp.BCCSP {
if defaultBCCSP == nil {
logger.Debug("Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.")
bootBCCSPInitOnce.Do(func() {
var err error
f := &SWFactory{}
bootBCCSP, err = f.Get(GetDefaultOpts())
if err != nil {
panic("BCCSP Internal error, failed initialization with GetDefaultOpts!")
}
})
return bootBCCSP
}
return defaultBCCSP
}
直接就跳到了BCCSP子產品的factory包下,在下面的源碼分析中将對其進行展開分析。
三、源碼
順着上面的初始啟動代碼分析相關的資料結構和相關的代碼:
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)
}
type BCCSPFactory interface {
// Name returns the name of this factory
Name() string
// Get returns an instance of BCCSP using opts.
Get(opts *FactoryOpts) (bccsp.BCCSP, error)
}
func (f *SWFactory) Get(config *FactoryOpts) (bccsp.BCCSP, error) {
// Validate arguments
if config == nil || config.SwOpts == nil {
return nil, errors.New("Invalid config. It must not be nil.")
}
swOpts := config.SwOpts
var ks bccsp.KeyStore
if swOpts.Ephemeral == true {
//虛拟存儲路徑--密鑰并不被加載和儲存
ks = sw.NewDummyKeyStore()
} else if swOpts.FileKeystore != nil {
//設定私鑰的路徑
fks, err := sw.NewFileBasedKeyStore(nil, swOpts.FileKeystore.KeyStorePath, false)
if err != nil {
return nil, errors.Wrapf(err, "Failed to initialize software key store")
}
ks = fks
} else if swOpts.InmemKeystore != nil {
//記憶體存儲密鑰
ks = sw.NewInMemoryKeyStore()
} else {
// Default to ephemeral key store
//預設為臨時存儲
ks = sw.NewDummyKeyStore()
}
return sw.NewWithParams(swOpts.SecLevel, swOpts.HashFamily, ks)
}
//預設是使用軟體的SW加密方式
func GetDefaultOpts() *FactoryOpts {
return &FactoryOpts{
ProviderName: "SW",
SwOpts: &SwOpts{
HashFamily: "SHA2",
SecLevel: 256,
Ephemeral: true,
},
}
}
看一看最後的NewWithParams:
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)
}
//生成一個CSP提供者,看下面的詳細代碼分析
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{})
swbccsp.AddWrapper(reflect.TypeOf(&rsaPrivateKey{}), &rsaSigner{})
// Set the Verifiers
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPrivateKey{}), &ecdsaPrivateKeyVerifier{})
swbccsp.AddWrapper(reflect.TypeOf(&ecdsaPublicKey{}), &ecdsaPublicKeyKeyVerifier{})
swbccsp.AddWrapper(reflect.TypeOf(&rsaPrivateKey{}), &rsaPrivateKeyVerifier{})
swbccsp.AddWrapper(reflect.TypeOf(&rsaPublicKey{}), &rsaPublicKeyKeyVerifier{})
// 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})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSAKeyGenOpts{}), &rsaKeyGenerator{length: conf.rsaBitLength})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSA1024KeyGenOpts{}), &rsaKeyGenerator{length: 1024})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSA2048KeyGenOpts{}), &rsaKeyGenerator{length: 2048})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSA3072KeyGenOpts{}), &rsaKeyGenerator{length: 3072})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.RSA4096KeyGenOpts{}), &rsaKeyGenerator{length: 4096})
// Set the key generators
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.RSAGoPublicKeyImportOpts{}), &rsaGoPublicKeyImportOptsKeyImporter{})
swbccsp.AddWrapper(reflect.TypeOf(&bccsp.X509PublicKeyImportOpts{}), &x509PublicKeyImportOptsKeyImporter{bccsp: swbccsp})
return swbccsp, nil
}
這個函數通過相關的參數配置來建立BCCSP。在這個函數裡出現了CSP這個加密提供者,看一下相關的代碼:
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
}
//在這個函數裡,設定上在CPS結構中相應的各種操作者的對象
func New(keyStore bccsp.KeyStore) (*CSP, error) {
if keyStore == nil {
return nil, errors.Errorf("Invalid bccsp.KeyStore instance. It must be different from nil.")
}
encryptors := make(map[reflect.Type]Encryptor)
decryptors := make(map[reflect.Type]Decryptor)
signers := make(map[reflect.Type]Signer)
verifiers := make(map[reflect.Type]Verifier)
hashers := make(map[reflect.Type]Hasher)
keyGenerators := make(map[reflect.Type]KeyGenerator)
keyDerivers := make(map[reflect.Type]KeyDeriver)
keyImporters := make(map[reflect.Type]KeyImporter)
csp := &CSP{keyStore,
keyGenerators, keyDerivers, keyImporters, encryptors,
decryptors, signers, verifiers, hashers}
return csp, nil
}
在New函數中建立了CSP結構中的相關操作集合,這些集合分别實作了一些相應的接口,比如:
// Encryptor is a BCCSP-like interface that provides encryption algorithms
type Encryptor interface {
// Encrypt encrypts plaintext using key k.
// The opts argument should be appropriate for the algorithm used.
Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error)
}
// Decryptor is a BCCSP-like interface that provides decryption algorithms
type Decryptor interface {
// Decrypt decrypts ciphertext using key k.
// The opts argument should be appropriate for the algorithm used.
Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error)
}
// Signer is a BCCSP-like interface that provides signing algorithms
type Signer interface {
// 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 bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error)
}
在CSP這個類中提供了AddWrapers這個增加打包器函數,用來綁定各種類型的資料結構。
// AddWrapper binds the passed type to the passed wrapper.
// Notice that that wrapper must be an instance of one of the following interfaces:
// KeyGenerator, KeyDeriver, KeyImporter, Encryptor, Decryptor, Signer, Verifier, Hasher.
func (csp *CSP) AddWrapper(t reflect.Type, w interface{}) error {
if t == nil {
return errors.Errorf("type cannot be nil")
}
if w == nil {
return errors.Errorf("wrapper cannot be nil")
}
switch dt := w.(type) {
case KeyGenerator:
csp.KeyGenerators[t] = dt
case KeyImporter:
csp.KeyImporters[t] = dt
case KeyDeriver:
csp.KeyDerivers[t] = dt
case Encryptor:
csp.Encryptors[t] = dt
case Decryptor:
csp.Decryptors[t] = dt
case Signer:
csp.Signers[t] = dt
case Verifier:
csp.Verifiers[t] = dt
case Hasher:
csp.Hashers[t] = dt
default:
return errors.Errorf("wrapper type not valid, must be on of: KeyGenerator, KeyDeriver, KeyImporter, Encryptor, Decryptor, Signer, Verifier, Hasher")
}
return nil
}
來分析一下這個AddlWrapper的作用,随便取一個增加函數代碼:
可以看出:
key(t) = reflect.TypeOf(&bccsp.ECDSAP256KeyGenOpts{})
value(dt) = ecdsaKeyGenerator{curve: elliptic.P256()}
前面是類型,後面是類型的執行個體對象,針對這個對象看一下定義:
type ecdsaKeyGenerator struct {
curve elliptic.Curve
}
func (kg *ecdsaKeyGenerator) KeyGen(opts bccsp.KeyGenOpts) (bccsp.Key, error) {
privKey, err := ecdsa.GenerateKey(kg.curve, rand.Reader)
if err != nil {
return nil, fmt.Errorf("Failed generating ECDSA key for [%v]: [%s]", kg.curve, err)
}
return &ecdsaPrivateKey{privKey}, nil
}
這樣,它就和CSP類中實作的相關接口對應上了,還是看這個接口,其在CSP中實作為:
func (csp *CSP) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
// Validate arguments
if opts == nil {
return nil, errors.New("Invalid Opts parameter. It must not be nil.")
}
//這裡得到上面的KV中的産生器
keyGenerator, found := csp.KeyGenerators[reflect.TypeOf(opts)]
if !found {
return nil, errors.Errorf("Unsupported 'KeyGenOpts' provided [%v]", opts)
}
//開始調用真正的ecdsaKeyGenerator.KeyGen()函數
k, err = keyGenerator.KeyGen(opts)
if err != nil {
return nil, errors.Wrapf(err, "Failed generating key with opts [%v]", opts)
}
// If the key is not Ephemeral, store it.
if !opts.Ephemeral() {
// Store the key
err = csp.ks.StoreKey(k)
if err != nil {
return nil, errors.Wrapf(err, "Failed storing key [%s]", opts.Algorithm())
}
}
return k, nil
}
BCCSP内部的加密算法,會開辟專門的一節來分析。這裡就不再展開了。
四、總結
通過上述分析可以看到,做為基礎子產品,其實BCCSP在整個Fabric是非常重要的,從另外一個角度來看,如果沒有密碼學做為基礎,區塊鍊的安全性肯定會極大的降低。密碼學其實就是整個BCCSP的核心,包括對稱的、非對稱的等等,這些都構成了整個Fabric安全應用的基石。