fabric1.0之cryptogen讲解

一 工具定义

Cryptogen是hyperleder fabric提供的为网络实体生成加密材料(公私钥/证书等)的实用程序。简单来说就是一个生成认证证书(x509 certs)的工具。这些证书代表一个身份,并允许在网络实体间通信和交易时进行签名和身份认证。

cryptogen使用一个包含网络拓扑的crypto-config.yaml文件,为文件中定义的组织和属于这些组织的实体生成一组证书和密钥。每个组织都配置唯一的根证书(ca-cert),并包含了特定的实体(peer和orders),这就形成了一种典型的网络结构–每个成员都有所属杜CA。hyperleder fabric网络中的交易和通信都使用实体私钥签名,使用公钥验证。

二 产生这个工具的原因
Cryptogen 全名 crypto generate ,fabric设计它是为了方便生产证书,目录这一系列的操作,它脱胎于go sdk下cryto包。

三 如何使用这个工具

在fabric中输入make cryptogen 或者直接在fabric/common/tools/cryptogen/下执行go build,就会在build/bin文件下生成一个名叫cryptogen的二进制程序。

这个工具用来读取crypto-config.yaml文件的内容来产生组织,证书,秘钥。

比如命令为:
cryptogen generate --config=./crypto-config.yaml --output ./crypto-config
理解就是 用cryptogen二进制程序 找到配置文件crypto-config.yaml 处理输出文件名为crypto-config的结果

但是crypto-config中只定义了组织相关的配置,实际需要用的生成证书,以及公私钥的配置在Fabric/common/tools/cryptogen下。

四 工具源码分析

该文件下目录
在这里插入图片描述

在源码上设计者将这个工具概念分成了4个部分:

CA 电子证书

csp 内容安全策略

metadata 元数据

msp 管理服务提供商

CA文件包分析:

Generator.go

该代码定义1个结构体,5个方法

1结构体 CA

电子签名证书 由名称 公私钥 证书构成

2方法 NewCA (baseDir, org, name string) (*CA, error)
作用创建CA 返回CA实体和报错

3方法 (ca *CA) SignCertificate(baseDir, name string, sans []string, pub *ecdsa.PublicKey, ku x509.KeyUsage, eku []x509.ExtKeyUsage) (*x509.Certificate, error)
作用签名证书 返回证书文件和报错

4方法genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey, priv interface{}) (*x509.Certificate, error)
将签名证书椭圆算法处理

5方法 x509Template() x509.Certificate

6方法 subjectTemplate() pkix.Name

ca文件
Generator.go
package ca

import ( //大量运行go sdk里的包
“crypto” //特别是crypto
“crypto/ecdsa”
“crypto/rand”
“crypto/x509”
“crypto/x509/pkix”
“encoding/pem”
“math/big”
“os”
“time”
“path/filepath” //引用fabric中自己写的csp包
“github.com/hyperledger/fabric/common/tools/cryptogen/csp”
)

type CA struct { //定义CA结构体 名称 秘钥 证书
Name string
//SignKey *ecdsa.PrivateKey
//这里2属性都是go sdk中的东西
Signer crypto.Signer //这里是结构体接口 里面是公钥 私钥
SignCert *x509.Certificate //结构体 证书
}

//NewCA 创建CA实例 并将签名密钥对保存在baseDir/名称
func NewCA(baseDir, org, name string) (*CA, error) {

var response error //用来记录错误
var ca *CA // 指向CA结构体

err := os.MkdirAll(baseDir, 0755) //在baseDir路径下创建文件目录
if err == nil { //目录创建成功
priv, signer, err := csp.GeneratePrivateKey(baseDir) //创建私钥priv,signer
response = err //记录报错
if err == nil { //私钥创建成功
// get public signing certificate
ecPubKey, err := csp.GetECPublicKey(priv) //通过私钥priv获取公钥ecpubkey
response = err //记录报错
if err == nil { //公钥创建成功
template := x509Template() //定义模板
//this is a CA
template.IsCA = true //模板属性isCA为true
//模板属性keyUsage
template.KeyUsage |= x509.KeyUsageDigitalSignature |
x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign |
x509.KeyUsageCRLSign
//模板属性extkeyusage
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}

        //set the organization for the subject
        subject := subjectTemplate()                //定义主题
        subject.Organization = []string{org}       //属性组织 = org
        subject.CommonName = name                  //属性通用名 = name

        template.Subject = subject              //模板主题=主题
        template.SubjectKeyId = priv.SKI()    //模板主题的keyID = 私钥的SKI

        x509Cert, err := genCertificateECDSA(baseDir, name, &template, &template,                //椭圆曲线处理各种  得出x509Cert
           ecPubKey, signer)
        response = err                                    //记录报错
        if err == nil {                                   //处理成功
           ca = &CA{                                      //CA赋值
              Name:     name,
              Signer:   signer,
              SignCert: x509Cert,
           }
        }
     }
  }

}
return ca, response //返回CA ,报错
}

// SignCertificate creates a signed certificate based on a built-in template
// and saves it in baseDir/name
func (ca *CA) SignCertificate(baseDir, name string, sans []string, pub *ecdsa.PublicKey,
ku x509.KeyUsage, eku []x509.ExtKeyUsage) (*x509.Certificate, error) {

template := x509Template() //x509定义模板
template.KeyUsage = ku
template.ExtKeyUsage = eku

//set the organization for the subject
subject := subjectTemplate() //定义模板主题
subject.CommonName = name

template.Subject = subject
template.DNSNames = sans

cert, err := genCertificateECDSA(baseDir, name, &template, ca.SignCert,
pub, ca.Signer) //椭圆处理得到Cert

if err != nil {
return nil, err
}

return cert, nil //返回cert
}

// default template for X509 subject
func subjectTemplate() pkix.Name { //主题模板
return pkix.Name{
Country: []string{“US”}, //国家
Locality: []string{“San Francisco”}, //位置
Province: []string{“California”}, //省
}
}

// default template for X509 certificates
func x509Template() x509.Certificate { //x509模板

//generate a serial number
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)

now := time.Now() //生产时间
//basic template to use
x509 := x509.Certificate{
SerialNumber: serialNumber,
NotBefore: now, //有效时间10年
NotAfter: now.Add(3650 * 24 * time.Hour), //~ten years
BasicConstraintsValid: true,
}
return x509

}

// generate a signed X509 certficate using ECDSA //签名证书椭圆处理
func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey,
priv interface{}) (*x509.Certificate, error) {

//create the x509 public cert
certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv)
if err != nil {
return nil, err
}

//write cert out to file
fileName := filepath.Join(baseDir, name+"-cert.pem")
certFile, err := os.Create(fileName)
if err != nil {
return nil, err
}
//pem encode the cert
err = pem.Encode(certFile, &pem.Block{Type: “CERTIFICATE”, Bytes: certBytes})
certFile.Close()
if err != nil {
return nil, err
}

x509Cert, err := x509.ParseCertificate(certBytes)
if err != nil {
return nil, err
}
return x509Cert, nil
}

csp文件下

Csp.go
该代码有2个方法定义
1 GeneratePrivateKey( keystorePath string) (bccsp.Key,crypto.Signer, error)
创建私钥

2 GetECPublicKey(priv bccsp.Key) (*ecdsa.PublicKey, error)
获取公钥

package csp

import (
“crypto”
“crypto/ecdsa”
“crypto/x509”

“github.com/hyperledger/fabric/bccsp” //用到fabric的bccsp的包
“github.com/hyperledger/fabric/bccsp/factory”
“github.com/hyperledger/fabric/bccsp/signer”
)

// GeneratePrivateKey creates a private key and stores it in keystorePath
//在keystore路径下生成私钥和钥匙商店
func GeneratePrivateKey(keystorePath string) (bccsp.Key,
crypto.Signer, error) {

var err error //报错
var priv bccsp.Key //bccsp的钥匙
var s crypto.Signer

opts := &factory.FactoryOpts{
ProviderName: “SW”,
SwOpts: &factory.SwOpts{ //hash标准
HashFamily: “SHA2”,
SecLevel: 256,

FileKeystore: &factory.FileKeystoreOpts{
KeyStorePath: keystorePath,
},
},
}
csp, err := factory.GetBCCSPFromOpts(opts) //椭圆算法处理
if err == nil {
// generate a key //椭圆曲线数字签名算法
priv, err = csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: false})
if err == nil {
// create a crypto.Signer
s, err = signer.New(csp, priv)
}
}
return priv, s, err
}
//生成公钥
func GetECPublicKey(priv bccsp.Key) (*ecdsa.PublicKey, error) {

// get the public key
pubKey, err := priv.PublicKey() //bccsp钥匙中的公钥方法
if err != nil {
return nil, err
}
// marshal to bytes
pubKeyBytes, err := pubKey.Bytes() //获取公钥的字节
if err != nil {
return nil, err
}
// unmarshal using pkix //使用x509的公钥PKI处理公钥字节产生最终的公钥
ecPubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes)
if err != nil {
return nil, err
}
return ecPubKey.(*ecdsa.PublicKey), nil
}

metadata文件
Metadata.go
该代码一个方法
package metadata

import (
“fmt”
“runtime”
)

// package-scoped variables

// Package version
var Version string //版本

// package-scoped constants

// Program name
const ProgramName = “cryptogen” //常量

func GetVersionInfo() string { //获取版本信息
if Version == “” {
Version = “development build”
}

return fmt.Sprintf("%s:\n Version: %s\n Go version: %s\n OS/Arch: %s",
ProgramName, Version, runtime.Version(),
fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH))
}

Msp包
generator.go
GenerateLocalMSP ( baseDir , name string, sans []string, signCA *ca.CA, tlsCA *ca.CA) error
GenerateVerifyingMSP (baseDir string, signCA *ca.CA, tlsCA *ca.CA) error
createFolderStructure (rootDir string, local bool) error
x509Filename(signCA.Name)), signCA.SignCert) string
keyExport(keystore, output string, key bccsp.Key) error
pemExport(path, pemType string, bytes []byte ) error

package msp

import (
“crypto/x509” //用到bccsp包
“encoding/pem” //引用了CA CSP
“os”
“path/filepath”

“encoding/hex”

“github.com/hyperledger/fabric/bccsp”
“github.com/hyperledger/fabric/bccsp/factory”
“github.com/hyperledger/fabric/common/tools/cryptogen/ca”
“github.com/hyperledger/fabric/common/tools/cryptogen/csp”
)
//生成当地MSP
func GenerateLocalMSP(baseDir, name string, sans []string, signCA *ca.CA,
tlsCA *ca.CA) error {

// create folder structure
mspDir := filepath.Join(baseDir, “msp”) //该文件名
tlsDir := filepath.Join(baseDir, “tls”) //该文件名

err := createFolderStructure(mspDir, true) //创建文件夹结构
if err != nil {
return err
}

err = os.MkdirAll(tlsDir, 0755) // 创建目录
if err != nil {
return err
}

/*
Create the MSP identity artifacts
*/
// get keystore path
keystore := filepath.Join(mspDir, “keystore”)

// generate private key
priv, _, err := csp.GeneratePrivateKey(keystore) //生成私钥
if err != nil {
return err
}

// get public key
ecPubKey, err := csp.GetECPublicKey(priv) //通过私钥获取公钥
if err != nil {
return err
}
// generate X509 certificate using signing CA
cert, err := signCA.SignCertificate(filepath.Join(mspDir, “signcerts”),
name, []string{}, ecPubKey, x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
if err != nil {
return err
}

// write artifacts to MSP folders

// the signing CA certificate goes into cacerts
err = x509Export(filepath.Join(mspDir, “cacerts”, x509Filename(signCA.Name)), signCA.SignCert)
if err != nil {
return err
}
// the TLS CA certificate goes into tlscacerts
err = x509Export(filepath.Join(mspDir, “tlscacerts”, x509Filename(tlsCA.Name)), tlsCA.SignCert)
if err != nil {
return err
}

// the signing identity goes into admincerts.
// This means that the signing identity
// of this MSP is also an admin of this MSP
// NOTE: the admincerts folder is going to be
// cleared up anyway by copyAdminCert, but
// we leave a valid admin for now for the sake
// of unit tests
err = x509Export(filepath.Join(mspDir, “admincerts”, x509Filename(name)), cert)
if err != nil {
return err
}

/*
Generate the TLS artifacts in the TLS folder
*/

// generate private key
tlsPrivKey, _, err := csp.GeneratePrivateKey(tlsDir) //生成私钥
if err != nil {
return err
}
// get public key
tlsPubKey, err := csp.GetECPublicKey(tlsPrivKey) //获取公钥
if err != nil {
return err
}
// generate X509 certificate using TLS CA
_, err = tlsCA.SignCertificate(filepath.Join(tlsDir),
name, sans, tlsPubKey, x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
[]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
if err != nil {
return err
}
err = x509Export(filepath.Join(tlsDir, “ca.crt”), tlsCA.SignCert)
if err != nil {
return err
}

// rename the generated TLS X509 cert
err = os.Rename(filepath.Join(tlsDir, x509Filename(name)),
filepath.Join(tlsDir, “server.crt”))
if err != nil {
return err
}

err = keyExport(tlsDir, filepath.Join(tlsDir, “server.key”), tlsPrivKey)
if err != nil {
return err
}

return nil
}
//生成验证MSP
func GenerateVerifyingMSP(baseDir string, signCA *ca.CA, tlsCA *ca.CA) error {

// create folder structure and write artifacts to proper locations
err := createFolderStructure(baseDir, false)
if err == nil {
// the signing CA certificate goes into cacerts
err = x509Export(filepath.Join(baseDir, “cacerts”, x509Filename(signCA.Name)), signCA.SignCert)
if err != nil {
return err
}
// the TLS CA certificate goes into tlscacerts
err = x509Export(filepath.Join(baseDir, “tlscacerts”, x509Filename(tlsCA.Name)), tlsCA.SignCert)
if err != nil {
return err
}
}

// create a throwaway cert to act as an admin cert
// NOTE: the admincerts folder is going to be
// cleared up anyway by copyAdminCert, but
// we leave a valid admin for now for the sake
// of unit tests
factory.InitFactories(nil)
bcsp := factory.GetDefault()
priv, err := bcsp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true})
ecPubKey, err := csp.GetECPublicKey(priv)
if err != nil {
return err
}
_, err = signCA.SignCertificate(filepath.Join(baseDir, “admincerts”), signCA.Name,
[]string{""}, ecPubKey, x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
if err != nil {
return err
}

return nil
}
//创建文件夹结构
func createFolderStructure(rootDir string, local bool) error {

var folders []string
// create admincerts, cacerts, keystore and signcerts folders
folders = []string{
filepath.Join(rootDir, “admincerts”),
filepath.Join(rootDir, “cacerts”),
filepath.Join(rootDir, “tlscacerts”),
}
if local {
folders = append(folders, filepath.Join(rootDir, “keystore”),
filepath.Join(rootDir, “signcerts”))
}

for _, folder := range folders {
err := os.MkdirAll(folder, 0755)
if err != nil {
return err
}
}

return nil
}

func x509Filename(name string) string {
return name + “-cert.pem”
}

func x509Export(path string, cert *x509.Certificate) error {
return pemExport(path, “CERTIFICATE”, cert.Raw)
}
//密钥导出
func keyExport(keystore, output string, key bccsp.Key) error {
id := hex.EncodeToString(key.SKI())

return os.Rename(filepath.Join(keystore, id+"_sk"), output)
}
//
func pemExport(path, pemType string, bytes []byte) error {
//write pem out to file
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()

return pem.Encode(file, &pem.Block{Type: pemType, Bytes: bytes})
}

猜你喜欢

转载自blog.csdn.net/weixin_48990429/article/details/113978897