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()方法会执行下面的逻辑:
- 解析指定的配置文件,获取PeerOrgs和OrdererOrgs列表
- 遍历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为例,描述一下生成证书的过程:
- 使用
NewCA
生成一个私钥和签名对象,再根据私钥生成公钥,然后自签名公钥,生成自签名的证书,这个是Org的CA证书,保存在ca
文件夹中。 - 使用
NewCA
再生成tls通信的CA证书,保存在tlsca
文件夹中。 - 创建msp文件夹,
cacerts
里面的是上面生成的CA证书,tlscacerts
是上面生成的tls的CA证书,admincerts
中的内容是:生成私钥和公钥,使用CA证书进行签名。 - 为peer生成相关的证书。
- 为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证书分别拷贝到cacert
和tlscacerts
中,最后,将之前生产的节点证书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
中。
网友评论