美文网首页Hyperledger Fabric源码分析
Fabric源码分析-生成证书

Fabric源码分析-生成证书

作者: 史圣杰 | 来源:发表于2018-12-24 22:20 被阅读0次

    Fabric网络中,每个Endopint都有自己的身份认证。Cryptogen用来根据配置生成各个组织,组织内节点和用户使用的相关证书。本节主要说明了cryptogen生成证书的过程。

    1.生成证书

    假设我们规划了三个组织,如下所示:

    机构名称 组织标识符 组织域名 节点数
    排序 Orderer jianshu.com x
    核心企业 Core core.jianshu.com 2
    供应商 Supplier supplier.jianshu.com 2
    金融机构 Bank bank.jianshu.com 2

    根据规划的组织,可以编写下面的配置文件,OrdererOrgs是排序组织的相关配置,PeerOrgs是记账组织的配置

    OrdererOrgs:
        - Name: Orderer
          Domain: jianshu.com
          Specs:
                - Hostname: orderer
    PeerOrgs:
        - Name: Core
          Domain: core.jianshu.com
          Template:
                Count: 2
          Users:
                Count: 2
        - Name: Supplier
          Domain: supplier.jianshu.com
          Template:
              Count: 2
          Users:
              Count: 2
        - Name: Bank
          Domain: bank.jianshu.com
          Template:
              Count: 2
          Users:
              Count: 2
    

    有了上面的配置文件,可以使用cryptogen生成证书:

    cryptogen generate --config=./crypto-config.yaml --output /var/hyperledger/crypto-config
    

    2.生成过程

    具体程序在common/tools/cryptogen/main.go文件中,generate()方法会执行下面的逻辑:

    1. 解析指定的配置文件,获取PeerOrgs和OrdererOrgs列表
    2. 遍历PeerOrgs和OrdererOrgs,分别为其生成证书

    2.1 结构

    组织结构
    按照我们的设计,排序有一个组织,记账有三个组织,因此生成的文件夹结构是与我们的设计相匹配的,并且以Domain作为组织的名称。

    .
    ├── ordererOrganizations
    │   └── jianshu.com
    └── peerOrganizations
        ├── bank.jianshu.com
        ├── core.jianshu.com
        └── supplier.jianshu.com
    

    组织内结构

    一个组织内部包含了自己的MSP配置,两个CA证书,每个peer节点和每个用户的证书。

    • ca下面是私钥和自签名证书
    • MSP配置放在msp文件夹下
    • peers下面是每个节点的证书
    • tlsca是用与通信的私钥和自签名证书
    • users是每个用户的证书
    ├── ca
    │   ├── b59d1f125..._sk
    │   └── ca.bank.jianshu.com-cert.pem
    ├── msp
    │   ├── admincerts
    │   ├── cacerts
    │   └── tlscacerts
    ├── peers
    │   ├── peer0.bank.jianshu.com
    │   └── peer1.bank.jianshu.com
    ├── tlsca
    │   ├── abb0feb..._sk
    │   └── tlsca.bank.jianshu.com-cert.pem
    └── users
        ├── Admin@bank.jianshu.com
        ├── User1@bank.jianshu.com
        └── User2@bank.jianshu.com
    

    2.2 生成流程

    我们一个组织Org为例,描述一下生成证书的过程:

    1. 使用NewCA生成一个私钥和签名对象,再根据私钥生成公钥,然后自签名公钥,生成自签名的证书,这个是Org的CA证书,保存在ca文件夹中。
    2. 使用NewCA再生成tls通信的CA证书,保存在tlsca文件夹中。
    3. 创建msp文件夹,cacerts里面的是上面生成的CA证书,tlscacerts是上面生成的tls的CA证书,admincerts中的内容是:生成私钥和公钥,使用CA证书进行签名。
    4. 为peer生成相关的证书。
    5. 为user生成相关的证书。

    peer

    peers文件夹下是每个peer节点的MSP,我们以bank.jianshu.com的peer0节点为例,先了解一下peer几点的msp结构,每个节点有两个文件夹msp用来进行身份认证,背书签名等,tls用来进行rpc通信加密。

    ├── msp
    │   ├── admincerts
    │   │   └── Admin@bank.jianshu.com-cert.pem
    │   ├── cacerts
    │   │   └── ca.bank.jianshu.com-cert.pem
    │   ├── keystore
    │   │   └── 6464900e9759c33e..._sk
    │   ├── signcerts
    │   │   └── peer0.bank.jianshu.com-cert.pem
    │   └── tlscacerts
    │       └── tlsca.bank.jianshu.com-cert.pem
    └── tls
        ├── ca.crt
        ├── server.crt
        └── server.key
    

    msp
    msp文件夹中,首先会生成一个私钥,保存在keystore里面,然后生成公钥,使用CA的证书对其签名,生成一个证书,保存在signcert中。
    之后,将组织的CA证书和tls的CA证书分别拷贝到cacerttlscacerts中,最后,将之前生产的节点证书signcerts拷贝到admincerts,后续生成User的Admin证书后会覆盖到admincerts
    接下来,生成tls的证书,首先也是生成一个私钥server.key,获取公钥,使用tls的CA证书对其签名,生成server.crt,最后,将tls的CA证书拷贝到ca.crt

    user

    user文件夹中的内容与peer的生产方式类似。user的类型为client,peer为server。

    ├── Admin@bank.jianshu.com
    │   ├── msp
    │   │   ├── admincerts
    │   │   │   └── Admin@bank.jianshu.com-cert.pem
    │   │   ├── cacerts
    │   │   │   └── ca.bank.jianshu.com-cert.pem
    │   │   ├── keystore
    │   │   │   └── 12b4c302bd2c5211debdf83c17b7b8cb774ac37a67cda618ebb206e8a859c38c_sk
    │   │   ├── signcerts
    │   │   │   └── Admin@bank.jianshu.com-cert.pem
    │   │   └── tlscacerts
    │   │       └── tlsca.bank.jianshu.com-cert.pem
    │   └── tls
    │       ├── ca.crt
    │       ├── client.crt
    │       └── client.key
    

    在生成User的相关证书之后,会将Admin的证书拷贝到Peer节点的admincerts中。

    3.程序解析

    3.1 BCCSP

    BCCSP是BlockChain Crypto Service Provider的缩写,是一个接口,定义了如下方法:

    type BCCSP interface {
        // 根据KeyGenOpts生成一个Key
        KeyGen(opts KeyGenOpts) (k Key, err error)
        // 从k和opts派生从dk
        KeyDeriv(k Key, opts KeyDerivOpts) (dk Key, err error)
        // 导入key
        KeyImport(raw interface{}, opts KeyImportOpts) (k Key, err error)
        // 返回当前CSP针对ski的key
        GetKey(ski []byte) (k Key, err error)
        // 计算msg的hash,HashOpts指定了算法
        Hash(msg []byte, opts HashOpts) (hash []byte, err error)
        // 返回hash对象
        GetHash(opts HashOpts) (h hash.Hash, err error)
        // 使用k对digest进行签名
        Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error)
        // 根据key和disget校验签名
        Verify(k Key, signature, digest []byte, opts SignerOpts) (valid bool, err error)
        // 使用key对明文加密
        Encrypt(k Key, plaintext []byte, opts EncrypterOpts) (ciphertext []byte, err error)
        // 使用key对密文解密
        Decrypt(k Key, ciphertext []byte, opts DecrypterOpts) (plaintext []byte, err error)
    }
    

    可以看到,BCCSP需要提供生成key,获取key,hash,签名,验签和加解密的工作。在源码中,有两种实现:sw和pkcs11,其中sw是软件加密的基础服务,pkcs11是硬件加密的基础服务。

    为了便于切换使用不同的Crypto ServiceProvider,fabric使用factory先获取BCCSPFactory,再使用BCCSPFactory获取BCCSP对象。在bccsp/factory/factory.go中,定了了factory方法,

    type BCCSPFactory interface {
        Name() string
        Get(opts *FactoryOpts) (bccsp.BCCSP, error)
    }
    

    BCCSPFactory会根据FactoryOpts获取BCCSP,FactoryOpts中定义了获取Factory时需要指定的名称,软件和硬件加密的选项,除此之外,还提供了插件机制,用来获取插件。

    type FactoryOpts struct {
        ProviderName string 
        SwOpts       *SwOpts            
        PluginOpts   *PluginOpts        
        Pkcs11Opts   *pkcs11.PKCS11Opts
    }
    

    软件和硬件对应这两种factory分别是SWFactory,PKCS11Factory,此外,还有插件的工厂PluginFactory,也可以用来获取BCCSP。

    下面是获取bccsp并进行hash的方法

    var opts = &factory.FactoryOpts{
        ProviderName:"SW",
        SwOpts:&factory.SwOpts{
            HashFamily: "SHA2",
            SecLevel:   256,
            Ephemeral:  true,
        },
    }
    bcc,_ := factory.GetBCCSPFromOpts(opts)
    hash,_ :=bcc.GetHash(&bccsp.SHA256Opts{})
    bs := hash.Sum([]byte("134"))
    

    对于PluginFactory,源代码在bccsp/factory/pluginfactory.go中,fabric使用了go语言的pligin机制,会从PluginOpts的Library中加载插件,获取New方法后,将PluginOpts的config作为参数,获取BCCSP并返回。
    具体的插件即可,可以参考https://www.imooc.com/article/48340?block_id=tuijian_wz

    对于SWFactory获取BCCSP的是 bccsp/sw/impl.go,里面维护了很多map,map会根据Opt的类型获取具体的实现,

    type impl struct {
        conf *config
        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
    }
    

    以keyGenerators为例,我们只需要传入不同的Opts,就可以获取到对应的Generator。

    keyGenerators[reflect.TypeOf(&bccsp.ECDSAKeyGenOpts{})] = &ecdsaKeyGenerator{curve: conf.ellipticCurve}
    keyGenerators[reflect.TypeOf(&bccsp.ECDSAP256KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P256()}
    keyGenerators[reflect.TypeOf(&bccsp.ECDSAP384KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P384()}
    

    3.2 获取私钥

    首先根据下面的参数获取BCCSP

    opts := &factory.FactoryOpts{
        ProviderName: "SW",
        SwOpts: &factory.SwOpts{
            HashFamily: "SHA2",
            SecLevel:   256,
    
            FileKeystore: &factory.FileKeystoreOpts{
                KeyStorePath: keystorePath,
            },
        },
    }
    

    有了BCCSP之后,可以通过ECDSAP256KeyGenOpts获取Generator,然后,就可以生成私钥了。

    csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: false})
    // impl中
    keyGenerators[reflect.TypeOf(&bccsp.ECDSAP256KeyGenOpts{})] = &ecdsaKeyGenerator{curve: elliptic.P256()}
    

    3.3 生成签名对象

    bccspCryptoSigner是BCCSP的签名对象,里面包含了公/私钥和BCCSP

    type bccspCryptoSigner struct {
        csp bccsp.BCCSP
        key bccsp.Key
        pk  interface{}
    }
    

    有了私钥之后,可以从中导出der格式的公钥,然后使用crypto转为x509的公钥,有了公/私钥和BCCSP里面的签名和验签方法,就可以用于签名了

    3.3 生成证书

    使用crypto的x509包下面的方法,设置相关的信息后,就可以生成证书了。具体代码在common/tools/cryptogen/ca/generator.go中。

    相关文章

      网友评论

        本文标题:Fabric源码分析-生成证书

        本文链接:https://www.haomeiwen.com/subject/yvrzkqtx.html