上次讲到了TlsCA证书的生成。下面我们继续向下来,在回到
main.go 中的generatePeerOrg()方法,
err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, orgSpec.EnableNodeOUs) if err != nil { fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) os.Exit(1) }
GenerateVerifyingMSP()方法,把msp的目录,singCA,tlsCa org的描述参数,出入进去。
func GenerateVerifyingMSP(baseDir string, signCA *ca.CA, tlsCA *ca.CA, nodeOUs bool) 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)//导出为pem根式的签名证书 if err != nil { return err } // the TLS CA certificate goes into tlscacerts err = x509Export(filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)), tlsCA.SignCert)//导出为pem格式的tlsCA证书 if err != nil { return err } } // generate config.yaml if required if nodeOUs {//如果为真,那么久导出配置文件到基本目录 exportConfig(baseDir, "cacerts/"+x509Filename(signCA.Name), true) } // 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()//获得默认的算法csp priv, err := bcsp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true})//生成临时的私钥 ecPubKey, err := csp.GetECPublicKey(priv)//获得公钥 if err != nil { return err } //用这对临时的key签名admincerts的证书,这就是JDK为什么enroll的时候会在数据库中certs表中增加一个证书,应为签发的是临时证书。 _, err = signCA.SignCertificate(filepath.Join(baseDir, "admincerts"), signCA.Name, nil, nil, ecPubKey, x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{}) if err != nil { return err } return nil } 返回之后 如果没有错误,那么我们到处了ca证书,tls证书,生成了admin的临时证书,然后调用generateNodes()方法
generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs)//msp.PEER表明的类型
func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA, nodeType int, nodeOUs bool) { for _, node := range nodes {//循环所有的nodes nodeDir := filepath.Join(baseDir, node.CommonName)//产生路径 if _, err := os.Stat(nodeDir); os.IsNotExist(err) {/判断这个文件夹是否存在 err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA, nodeType, nodeOUs)//然后给每个组织生成admin临时证书 if err != nil { fmt.Printf("Error generating local MSP for %s:\n%v\n", node, err) os.Exit(1)//如果错误,退出 } } } }
然后生成用户的名称。
users := []NodeSpec{} for j := 1; j <= orgSpec.Users.Count; j++ { user := NodeSpec{ CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName), } users = append(users, user) }
//生成admin的用户
adminUser := NodeSpec{ CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), }
users = append(users, adminUser)//把admin用户添加到users中 generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)//生成的类型为msp.client
根据类型不同,最后生keyStore会区分是client 、还是server端,以及crt文件。
// copy the admin cert to the org's MSP admincerts err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)//把不同的组织的域名的admin复制到自己所属的目录。 if err != nil { fmt.Printf("Error copying admin cert for org %s:\n%v\n", orgName, err) os.Exit(1) }
我们来看一下copyAdminCert()方法
func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error { if _, err := os.Stat(filepath.Join(adminCertsDir, adminUserName+"-cert.pem")); err == nil {//copyadmin的cert.pem证书 return nil } // delete the contents of admincerts err := os.RemoveAll(adminCertsDir)//删除adminCertsDir下的所有的东西 if err != nil { return err } // recreate the admincerts directory err = os.MkdirAll(adminCertsDir, 0755)//创建目录 if err != nil { return err } err = copyFile(filepath.Join(usersDir, adminUserName, "msp", "signcerts", adminUserName+"-cert.pem"), filepath.Join(adminCertsDir, adminUserName+"-cert.pem"))//把msp目中G的签名证书中的admin的证书,赋值到adminCertDir的目录中。 if err != nil { return err } return nil }
再回到 generatePeerOrg()方法中 调用
for _, spec := range orgSpec.Specs {//循环所有的OrgSpec.Specs err = copyAdminCert(usersDir, filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)//复制peer的证书到msp中。 if err != nil { fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n", orgName, spec.CommonName, err) os.Exit(1) } }
要循环的内容如下:
# Specs: # - Hostname: foo # implicitly "foo.org1.example.com" # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above # SANS: # - "bar.{{.Domain}}" # - "altfoo.{{.Domain}}" # - "{{.Hostname}}.org6.net" # - 172.16.10.31 # - Hostname: bar # - Hostname: baz
此段内容做什么尚未搞清楚,等搞清楚我会详细的说明一下
到此 generatePeerOrg()方法讲完。我们再回到 generate()方法,我们继续看一个方法
for _, orgSpec := range config.OrdererOrgs {//然后循环所有的Order标签 err = renderOrgSpec(&orgSpec, "orderer")//生成配置文件 if err != nil { fmt.Printf("Error processing orderer configuration: %s", err) os.Exit(-1) } generateOrdererOrg(*outputDir, orgSpec)//然后生成OrderOrg证书 }
我们看一下 generateOrdererOrg()方法和 generatePeerOrg()方法的区别,为什么要写成两个
func generateOrdererOrg(baseDir string, orgSpec OrgSpec) { orgName := orgSpec.Domain // generate CAs orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)//目录不一样 caDir := filepath.Join(orgDir, "ca") tlsCADir := filepath.Join(orgDir, "tlsca") mspDir := filepath.Join(orgDir, "msp") orderersDir := filepath.Join(orgDir, "orderers") usersDir := filepath.Join(orgDir, "users") adminCertsDir := filepath.Join(mspDir, "admincerts") // generate signing CA signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)//一样生成证书 if err != nil { fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err) os.Exit(1) } // generate TLS CA tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)//一样生成TLS证书 if err != nil { fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err) os.Exit(1) } err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, false)//这里直接设置成了false.只是把证书主题中的OrganizationalUnit字段的值不一样。无其他作用 if err != nil { fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) os.Exit(1) } generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, false)//这里也是类似上面的作用 //这里只有添加admin用户的 adminUser := NodeSpec{ CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), } // generate an admin for the orderer org users := []NodeSpec{} // add an admin user users = append(users, adminUser)//把admin用户添加到user generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, false)//生成证书 // copy the admin cert to the org's MSP admincerts err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)//复制admin的证书 if err != nil { fmt.Printf("Error copying admin cert for org %s:\n%v\n", orgName, err) os.Exit(1) } // copy the admin cert to each of the org's orderers's MSP admincerts for _, spec := range orgSpec.Specs {//类似 generatePeerOrg中的方法,这里不做多做详解
err = copyAdminCert(usersDir, filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) if err != nil { fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n", orgName, spec.CommonName, err) os.Exit(1) } } }
到此 generate()方法解析完毕,对应的文档上的命令是:../bin/cryptogen generate --config=./crypto-config.yaml
================================================================================================下面讲解 ../bin/cryptogen extend --config=./crypto-config.yaml 命令,增加组织的配置文件
main方法中 extend()方法
func extend() { config, err := getConfig()//获得配置文件 类似generate()方法 if err != nil { fmt.Printf("Error reading config: %s", err) os.Exit(-1) } for _, orgSpec := range config.PeerOrgs {//循环所有的PeerOrgs,只不过这里设置了start参数。 err = renderOrgSpec(&orgSpec, "peer")//同generate()方法一样 if err != nil { fmt.Printf("Error processing peer configuration: %s", err) os.Exit(-1) } extendPeerOrg(orgSpec)//扩展组织 } for _, orgSpec := range config.OrdererOrgs {//循环OrderOrg err = renderOrgSpec(&orgSpec, "orderer") if err != nil { fmt.Printf("Error processing orderer configuration: %s", err) os.Exit(-1) } extendOrdererOrg(orgSpec)//货站Order } }
我们来看一下 extendPeerOrg()方法
func extendPeerOrg(orgSpec OrgSpec) { orgName := orgSpec.Domain orgDir := filepath.Join(*inputDir, "peerOrganizations", orgName) if _, err := os.Stat(orgDir); os.IsNotExist(err) { generatePeerOrg(*inputDir, orgSpec) return } peersDir := filepath.Join(orgDir, "peers") usersDir := filepath.Join(orgDir, "users") caDir := filepath.Join(orgDir, "ca") tlscaDir := filepath.Join(orgDir, "tlsca") signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName)//获得Ca证书 tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName)//获得TlsCa证书 generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs)//上面已经讲过了 adminUser := NodeSpec{//admin用户 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), } // copy the admin cert to each of the org's peer's MSP admincerts for _, spec := range orgSpec.Specs {// err := copyAdminCert(usersDir, filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) if err != nil { fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n", orgName, spec.CommonName, err) os.Exit(1) } } // TODO: add ability to specify usernames users := []NodeSpec{} for j := 1; j <= orgSpec.Users.Count; j++ { user := NodeSpec{ CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName), } users = append(users, user) } generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)//生成临时证书 类型为MSP.Client }
我们看一下getCa()方法
func getCA(caDir string, spec OrgSpec, name string) *ca.CA { _, signer, _ := csp.LoadPrivateKey(caDir)//根据证书额加载私钥,获得签名 cert, _ := ca.LoadCertificateECDSA(caDir)//获得ECDSA证书 return &ca.CA{//返回证书对象 Name: name, Signer: signer, SignCert: cert, Country: spec.CA.Country, Province: spec.CA.Province, Locality: spec.CA.Locality, OrganizationalUnit: spec.CA.OrganizationalUnit, StreetAddress: spec.CA.StreetAddress, PostalCode: spec.CA.PostalCode, } }
然后看一下LoadPrivateKey()方法
func LoadPrivateKey(keystorePath string) (bccsp.Key, crypto.Signer, error) { var err error var priv bccsp.Key var s crypto.Signer opts := &factory.FactoryOpts{//初始化算法工厂的参数 ProviderName: "SW", SwOpts: &factory.SwOpts{ HashFamily: "SHA2", SecLevel: 256, FileKeystore: &factory.FileKeystoreOpts{ KeyStorePath: keystorePath, }, }, } csp, err := factory.GetBCCSPFromOpts(opts)//获得csp if err != nil { return nil, nil, err } walkFunc := func(path string, info os.FileInfo, err error) error { if strings.HasSuffix(path, "_sk") { rawKey, err := ioutil.ReadFile(path) if err != nil { return err }//读取keyStore的文件 block, _ := pem.Decode(rawKey)//pem格式解密 priv, err = csp.KeyImport(block.Bytes, &bccsp.ECDSAPrivateKeyImportOpts{Temporary: true})//导入key,设置为临时的 if err != nil { return err } s, err = signer.New(csp, priv)//重新签名返回证书 if err != nil { return err } return nil } return nil } err = filepath.Walk(keystorePath, walkFunc) if err != nil { return nil, nil, err } return priv, s, err }
然后返回到 getCA()方法中 我们查看 LoadCertificateECDSA()方法
func LoadCertificateECDSA(certPath string) (*x509.Certificate, error) { var cert *x509.Certificate var err error walkFunc := func(path string, info os.FileInfo, err error) error { if strings.HasSuffix(path, ".pem") { rawCert, err := ioutil.ReadFile(path) if err != nil { return err }//读取证书 block, _ := pem.Decode(rawCert) cert, err = utils.DERToX509Certificate(block.Bytes)//使用DER申城证书 } return nil } err = filepath.Walk(certPath, walkFunc) if err != nil { return nil, err } return cert, err//返回证书 }
我们再回到 extend()方法中 查看一下extendOrdererOrg()方法
func extendOrdererOrg(orgSpec OrgSpec) { orgName := orgSpec.Domain orgDir := filepath.Join(*inputDir, "ordererOrganizations", orgName) caDir := filepath.Join(orgDir, "ca") usersDir := filepath.Join(orgDir, "users") tlscaDir := filepath.Join(orgDir, "tlsca") orderersDir := filepath.Join(orgDir, "orderers") if _, err := os.Stat(orgDir); os.IsNotExist(err) { generateOrdererOrg(*inputDir, orgSpec)//不做说明 return } signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName)//上面已经说过了 tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName)//上面已近说过了 generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, false) adminUser := NodeSpec{ CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), } for _, spec := range orgSpec.Specs { err := copyAdminCert(usersDir, filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) if err != nil { fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n", orgName, spec.CommonName, err) os.Exit(1) } } }
到此命令../bin/cryptogen extend--config=./crypto-config.yaml的方法已经讲解完毕,我们明天讲解初始块的生成。