Fabric CA 代码结构解析
Fabric CA项目是超级账本Fabric内的MemberService组件, 对网络内各个实体的身份证书的管理, 它提供的功能有:
身份认证,或者从 LDAP(轻量目录访问协议) 中获取注册信息;
发行担保证书 ECerts (Enrollment Certificates);
发行交易证书 TCerts (Transaction Certificates),保障 Hyperledger Fabric 区域链交易平台上的信息匿名性和不可追踪性;
证书更新和撤销。
api 1 2 3 ├─api │ client.go │ net.go
主要是封装一些Request和Response的结构体,以及一些信息的结构体。
如: 新身份注册的请求体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type RegistrationRequest struct { Name string `json:"id" help:"Unique name of the identity"` Type string `json:"type" def:"client" help:"Type of identity being registered (e.g. 'peer, app, user')"` Secret string `json:"secret,omitempty" mask:"password" help:"The enrollment secret for the identity being registered"` MaxEnrollments int `json:"max_enrollments,omitempty" help:"The maximum number of times the secret can be reused to enroll (default CA's Max Enrollment)"` Affiliation string `json:"affiliation" help:"The identity's affiliation"` Attributes []Attribute `json:"attrs,omitempty"` CAName string `json:"caname,omitempty" skip:"true"` }
cmd 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ├─cmd │ ├─fabric-ca-client │ │ │ .gitignore │ │ │ main.go │ │ │ │ │ └─command │ │ │ affiliation.go │ │ │ certificate.go │ │ │ certificate_test.go │ │ │ clientcmd.go │ │ │ config.go │ │ │ config_test.go │ │ │ enroll.go │ │ │ gencrl.go │ │ │ gencsr.go │ │ │ getcainfo.go │ │ │ getcainfo_test.go │ │ │ identity.go │ │ │ main_test.go │ │ │ reenroll.go │ │ │ register.go │ │ │ revoke.go │ │ │ root.go │ │ │ │ │ └─mocks │ │ Command.go │ │ │ └─fabric-ca-server │ .gitignore │ config.go │ LICENSE │ main.go │ main_test.go │ servercmd.go
主要是封装一些fabric ca client 和 fabric ca server 常用的命令函数,以及获取配置信息 初始化CA 等工作的函数。
如:CA Client 命令的执行流程
fabric-ca-client/command/root.go
监听命令输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func RunMain (args []string ) error { saveOsArgs := os.Args os.Args = args cmdName := "" if len (args) > 1 { cmdName = args[1 ] } ccmd := NewCommand(cmdName) err := ccmd.Execute() os.Args = saveOsArgs return err }
fabric-ca-client/command/clientcmd.go
初始化cmd,注册各个命令函数,最后执行命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 func NewCommand (name string ) *ClientCmd { c := &ClientCmd{ myViper: viper.New(), } c.name = strings.ToLower(name) c.init() return c } func (c *ClientCmd) init () { c.rootCmd = &cobra.Command{ Use: cmdName, Short: longName, PersistentPreRunE: func (cmd *cobra.Command, args []string ) error { err := c.checkAndEnableProfiling() if err != nil { return err } util.CmdRunBegin(c.myViper) cmd.SilenceUsage = true return nil }, PersistentPostRunE: func (cmd *cobra.Command, args []string ) error { if c.profileMode != "" && c.profileInst != nil { c.profileInst.Stop() } return nil }, } c.rootCmd.AddCommand(c.newRegisterCommand(), newEnrollCmd(c).getCommand(), c.newReenrollCommand(), c.newRevokeCommand(), newGetCAInfoCmd(c).getCommand(), c.newGenCsrCommand(), c.newGenCRLCommand(), c.newIdentityCommand(), c.newAffiliationCommand(), createCertificateCommand(c)) c.rootCmd.AddCommand(&cobra.Command{ Use: "version" , Short: "Prints Fabric CA Client version" , Run: func (cmd *cobra.Command, args []string ) { fmt.Print(metadata.GetVersionInfo(cmdName)) }, }) c.registerFlags() log.Level = log.LevelInfo } func (c *ClientCmd) Execute () error { return c.rootCmd.Execute() }
后续就是判断命令是否可以运行、是否满足条件、预运行、正式运行、运行后执行…..
与之对应的 CA Server 就主要是读取配置文件、启动服务、生成MSP
fabric-ca-server/main.go
监听命令输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func RunMain (args []string ) error { saveOsArgs := os.Args os.Args = args cmdName := "" if len (args) > 1 { cmdName = args[1 ] } scmd := NewCommand(cmdName, blockingStart) err := scmd.Execute() os.Args = saveOsArgs return err }
fabric-ca-server/servercmd.go
构建新cmd、并初始化服务器,注册各种server的命令函数(如上)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 // NewCommand returns new ServerCmd ready for running func NewCommand(name string, blockingStart bool) *ServerCmd { s := &ServerCmd{ name: name, blockingStart: blockingStart, myViper: viper.New(), } s.init() return s } // init initializes the ServerCmd instance // It intializes the cobra root and sub commands and // registers command flgs with viper func (s *ServerCmd) init() { // root command rootCmd := &cobra.Command{ Use: cmdName, Short: longName, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { err := s.configInit() if err != nil { return err } cmd.SilenceUsage = true util.CmdRunBegin(s.myViper) return nil }, } s.rootCmd = rootCmd // initCmd represents the server init command initCmd := &cobra.Command{ Use: "init", Short: fmt.Sprintf("Initialize the %s", shortName), Long: "Generate the key material needed by the server if it doesn't already exist", } initCmd.RunE = func(cmd *cobra.Command, args []string) error { if len(args) > 0 { return errors.Errorf(extraArgsError, args, initCmd.UsageString()) } err := s.getServer().Init(false) if err != nil { util.Fatal("Initialization failure: %s", err) } log.Info("Initialization was successful") return nil } s.rootCmd.AddCommand(initCmd) // startCmd represents the server start command startCmd := &cobra.Command{ Use: "start", Short: fmt.Sprintf("Start the %s", shortName), } startCmd.RunE = func(cmd *cobra.Command, args []string) error { if len(args) > 0 { return errors.Errorf(extraArgsError, args, startCmd.UsageString()) } err := s.getServer().Start() if err != nil { return err } return nil } s.rootCmd.AddCommand(startCmd) var versionCmd = &cobra.Command{ Use: "version", Short: "Prints Fabric CA Server version", Run: func(cmd *cobra.Command, args []string) { fmt.Print(metadata.GetVersionInfo(cmdName)) }, } s.rootCmd.AddCommand(versionCmd) s.registerFlags() }
后续也是雷同,执行命令。
docker
主要是一些关于构建fabric ca docker容器的一些配置信息和docker-compose.yaml文件。
lib
这里是整个CA项目的核心部分,包含了CA证书签名颁发撤销、客户端,服务端的功能具体实现、以及对数据库和文件的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 ├─lib │ │ ca.go │ │ caconfig.go │ │ capkcs11_test.go │ │ ca_test.go │ │ certdbaccessor.go │ │ certdbaccessor_test.go │ │ client.go │ │ clientconfig.go │ │ client_test.go │ │ client_whitebox_test.go │ │ dbaccessor.go │ │ dbaccessor_test.go │ │ identity.go │ │ identity_test.go │ │ keyrequest.go │ │ keyrequestnopkcs11.go │ │ server.go │ │ serveraffiliations.go │ │ serveraffiliations_test.go │ │ servercertificates.go │ │ servercertificates_test.go │ │ serverconfig.go │ │ serverendpoint.go │ │ serverendpoint_test.go │ │ serverenroll.go │ │ serverenroll_test.go │ │ servergencrl.go │ │ serveridemixcri.go │ │ serveridemixenroll.go │ │ serveridentities.go │ │ serveridentities_test.go │ │ serverinfo.go │ │ serverinfo_test.go │ │ serverregister.go │ │ serverregister_test.go │ │ serverrequestcontext.go │ │ serverrevoke.go │ │ serverrevoke_test.go │ │ servertcert.go │ │ server_benchmarks_test.go │ │ server_test.go │ │ server_whitebox_test.go │ │ test-util.go │ │ util.go │ │ │ ├─attr │ │ attribute.go │ │ attribute_test.go │ │ │ ├─attrmgr │ │ attrmgr.go │ │ attrmgr_test.go │ │ │ ├─caerrors │ │ servererror.go │ │ servererror_test.go │ │ │ ├─client │ │ └─credential │ │ │ credential.go │ │ │ │ │ ├─idemix │ │ │ credential.go │ │ │ credential_test.go │ │ │ signerconfig.go │ │ │ │ │ └─x509 │ │ │ credential.go │ │ │ credential_test.go │ │ │ signer.go │ │ │ signer_test.go │ │ │ │ │ └─mocks │ │ Client.go │ │ Identity.go │ │ │ ├─common │ │ │ serverresponses.go │ │ │ │ │ └─log │ │ log.go │ │ log_test.go │ │ │ ├─metadata │ │ version.go │ │ version_test.go │ │ │ ├─mocks │ │ operations_server.go │ │ server_request_context.go │ │ │ ├─server │ │ ├─certificaterequest │ │ │ │ certificaterequest.go │ │ │ │ certificaterequest_test.go │ │ │ │ │ │ │ └─mocks │ │ │ CertificateRequest.go │ │ │ RequestContext.go │ │ │ │ │ ├─db │ │ │ │ db.go │ │ │ │ db_suite_test.go │ │ │ │ db_test.go │ │ │ │ metrics.go │ │ │ │ metrics_test.go │ │ │ │ migrator.go │ │ │ │ migrator_test.go │ │ │ │ tx.go │ │ │ │ tx_test.go │ │ │ │ │ │ │ ├─factory │ │ │ │ factory.go │ │ │ │ factory_test.go │ │ │ │ │ │ │ ├─mocks │ │ │ │ FabricCADB.go │ │ │ │ fabricCATX.go │ │ │ │ migrator.go │ │ │ │ Result.go │ │ │ │ SqlxDB.go │ │ │ │ sqlxTx.go │ │ │ │ │ │ │ ├─mysql │ │ │ │ │ migrator.go │ │ │ │ │ migrator_test.go │ │ │ │ │ mysql.go │ │ │ │ │ mysql_suite_test.go │ │ │ │ │ mysql_test.go │ │ │ │ │ │ │ │ │ └─mocks │ │ │ │ fabricCADB.go │ │ │ │ fabricCATx.go │ │ │ │ │ │ │ ├─postgres │ │ │ │ │ internal_test.go │ │ │ │ │ migrator.go │ │ │ │ │ migrator_test.go │ │ │ │ │ postgres.go │ │ │ │ │ postgres_suite_test.go │ │ │ │ │ postgres_test.go │ │ │ │ │ │ │ │ │ └─mocks │ │ │ │ fabricCADB.go │ │ │ │ fabricCATx.go │ │ │ │ │ │ │ ├─sqlite │ │ │ │ │ driver.go │ │ │ │ │ migrator.go │ │ │ │ │ migrator_test.go │ │ │ │ │ sqlite.go │ │ │ │ │ sqlite_suite_test.go │ │ │ │ │ sqlite_test.go │ │ │ │ │ │ │ │ │ └─mocks │ │ │ │ create.go │ │ │ │ fabricCADB.go │ │ │ │ fabricCATx.go │ │ │ │ │ │ │ └─util │ │ │ util.go │ │ │ util_suite_test.go │ │ │ util_test.go │ │ │ │ │ ├─idemix │ │ │ │ config.go │ │ │ │ creddbaccessor.go │ │ │ │ creddbaccessor_test.go │ │ │ │ cri.go │ │ │ │ cri_test.go │ │ │ │ enroll.go │ │ │ │ enroll_test.go │ │ │ │ idemixlib.go │ │ │ │ idemixlib_test.go │ │ │ │ idemix_roles.go │ │ │ │ issuer.go │ │ │ │ issuercredential.go │ │ │ │ issuercredential_test.go │ │ │ │ issuer_test.go │ │ │ │ issuer_whitebox_test.go │ │ │ │ nonce.go │ │ │ │ nonce_test.go │ │ │ │ ra_whitebox_test.go │ │ │ │ revocationauthority.go │ │ │ │ revocationauthority_test.go │ │ │ │ revocationkey.go │ │ │ │ revocationkey_test.go │ │ │ │ │ │ │ └─mocks │ │ │ Clock.go │ │ │ cred_db_accessor.go │ │ │ FabricCATx.go │ │ │ fabric_cadb.go │ │ │ IssuerCredential.go │ │ │ Lib.go │ │ │ my_issuer.go │ │ │ NonceManager.go │ │ │ Result.go │ │ │ RevocationAuthority.go │ │ │ server_request_ctx.go │ │ │ User.go │ │ │ │ │ ├─ldap │ │ │ client.go │ │ │ client_test.go │ │ │ │ │ ├─metrics │ │ │ metrics.go │ │ │ │ │ ├─operations │ │ │ operations_suite_test.go │ │ │ system.go │ │ │ system_test.go │ │ │ tls.go │ │ │ tls_test.go │ │ │ │ │ └─user │ │ │ user.go │ │ │ user_suite_test.go │ │ │ user_test.go │ │ │ │ │ └─mocks │ │ result.go │ │ userDB.go │ │ userTx.go │ │ │ ├─spi │ │ affiliation.go │ │ affiliation_test.go │ │ │ ├─streamer │ │ jsonstreamer.go │ │ jsonstreamer_test.go │ │ │ ├─tcert │ │ api.go │ │ keytree.go │ │ keytree_test.go │ │ tcert.go │ │ tcert_test.go │ │ util.go │ │ util_test.go │ │ │ └─tls │ tls.go │ tls_test.go
如 client 初始化时对MSP的生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 func (c *Client) Init () error { if !c.initialized { cfg := c.Config log.Debugf("Initializing client with config: %+v" , cfg) if cfg.MSPDir == "" { cfg.MSPDir = "msp" } mspDir, err := util.MakeFileAbs(cfg.MSPDir, c.HomeDir) if err != nil { return err } cfg.MSPDir = mspDir keyDir := path.Join(mspDir, "keystore" ) err = os.MkdirAll(keyDir, 0700 ) if err != nil { return errors.Wrap(err, "Failed to create keystore directory" ) } c.keyFile = path.Join(keyDir, "key.pem" ) certDir := path.Join(mspDir, "signcerts" ) err = os.MkdirAll(certDir, 0755 ) if err != nil { return errors.Wrap(err, "Failed to create signcerts directory" ) } c.certFile = path.Join(certDir, "cert.pem" ) c.caCertsDir = path.Join(mspDir, "cacerts" ) err = os.MkdirAll(c.caCertsDir, 0755 ) if err != nil { return errors.Wrap(err, "Failed to create cacerts directory" ) } c.ipkFile = filepath.Join(mspDir, "IssuerPublicKey" ) c.idemixCredsDir = path.Join(mspDir, "user" ) err = os.MkdirAll(c.idemixCredsDir, 0755 ) if err != nil { return errors.Wrap(err, "Failed to create Idemix credentials directory 'user'" ) } c.idemixCredFile = path.Join(c.idemixCredsDir, "SignerConfig" ) c.csp, err = util.InitBCCSP(&cfg.CSP, mspDir, c.HomeDir) if err != nil { return err } err = c.initHTTPClient() if err != nil { return err } c.initialized = true } return nil }
如: server服务的启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 func (s *Server) Start () (err error) { log.Infof("Starting server in home directory: %s" , s.HomeDir) s.serveError = nil if s.listener != nil { return errors.New("server is already started" ) } err = s.init(false ) if err != nil { err2 := s.closeDB() if err2 != nil { log.Errorf("Close DB failed: %s" , err2) } return err } s.registerHandlers() log.Debugf("%d CA instance(s) running on server" , len (s.caMap)) err = s.startOperationsServer() if err != nil { return err } err = s.Operations.RegisterChecker("server" , s) if err != nil { return nil } for _, ca := range s.caMap { startNonceSweeper(ca) } err = s.listenAndServe() if err != nil { err2 := s.closeDB() if err2 != nil { log.Errorf("Close DB failed: %s" , err2) } return err } return nil }
util
包含一些辅助工具类,如:文件读写序列化、类型转换、以及对Fabrci BCCSP的操作。
swagger
CA 暴露出的API接口信息
深入 如果系统深入,应该需要从lib
开始,从服务器和客户端的启动监听、到cmd的执行,以此类推。
如果是深入密码体系,应该从lib\tcert
、lib\tls
、lib\ca.go
等深入,了解其签名验证的流程。