Fabric源码分析-生成证书

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中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容