Hyperledger Fabric源码分析

Fabric源码分析-生成证书

2018-12-24  本文已影响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
│   ├── 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中。

上一篇 下一篇

猜你喜欢

热点阅读