Fabric CA 代码结构解析

Fabric CA项目是超级账本Fabric内的MemberService组件, 对网络内各个实体的身份证书的管理, 它提供的功能有:

  1. 身份认证,或者从 LDAP(轻量目录访问协议) 中获取注册信息;

  2. 发行担保证书 ECerts (Enrollment Certificates);

  3. 发行交易证书 TCerts (Transaction Certificates),保障 Hyperledger Fabric 区域链交易平台上的信息匿名性和不可追踪性;

  4. 证书更新和撤销。

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
// RegistrationRequest for a new identity
type RegistrationRequest struct {
// Name is the unique name of the identity
Name string `json:"id" help:"Unique name of the identity"`
// Type of identity being registered (e.g. "peer, app, user")
Type string `json:"type" def:"client" help:"Type of identity being registered (e.g. 'peer, app, user')"`
// Secret is an optional password. If not specified,
// a random secret is generated. In both cases, the secret
// is returned in the RegistrationResponse.
Secret string `json:"secret,omitempty" mask:"password" help:"The enrollment secret for the identity being registered"`
// MaxEnrollments is the maximum number of times the secret can
// be reused to enroll.
MaxEnrollments int `json:"max_enrollments,omitempty" help:"The maximum number of times the secret can be reused to enroll (default CA's Max Enrollment)"`
// is returned in the response.
// The identity's affiliation.
// For example, an affiliation of "org1.department1" associates the identity with "department1" in "org1".
Affiliation string `json:"affiliation" help:"The identity's affiliation"`
// Attributes associated with this identity
Attributes []Attribute `json:"attrs,omitempty"`
// CAName is the name of the CA to connect to
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
// RunMain is the fabric-ca client main
func RunMain(args []string) error {
// Save the os.Args
saveOsArgs := os.Args
os.Args = args

// Execute the command
cmdName := ""
if len(args) > 1 {
cmdName = args[1]
}
ccmd := NewCommand(cmdName)
err := ccmd.Execute()

// Restore original os.Args
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
// NewCommand returns new ClientCmd ready for running
func NewCommand(name string) *ClientCmd {
c := &ClientCmd{
myViper: viper.New(),
}
c.name = strings.ToLower(name)
c.init()
return c
}


// init initializes the ClientCmd instance
// It intializes the cobra root and sub commands and
// registers command flgs with viper
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
}

// Execute runs this ClientCmd
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
// RunMain is the fabric-ca server main
func RunMain(args []string) error {
// Save the os.Args
saveOsArgs := os.Args
os.Args = args

cmdName := ""
if len(args) > 1 {
cmdName = args[1]
}
scmd := NewCommand(cmdName, blockingStart)

// Execute the command
err := scmd.Execute()

// Restore original os.Args
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
// Init initializes the client
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
// Key directory and file
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")

// Cert directory and file
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")

// CA certs directory
c.caCertsDir = path.Join(mspDir, "cacerts")
err = os.MkdirAll(c.caCertsDir, 0755)
if err != nil {
return errors.Wrap(err, "Failed to create cacerts directory")
}

// CA's Idemix public key
c.ipkFile = filepath.Join(mspDir, "IssuerPublicKey")

// Idemix credentials directory
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")

// Initialize BCCSP (the crypto layer)
c.csp, err = util.InitBCCSP(&cfg.CSP, mspDir, c.HomeDir)
if err != nil {
return err
}
// Create http.Client object and associate it with this client
err = c.initHTTPClient()
if err != nil {
return err
}

// Successfully initialized the client
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
// Start the fabric-ca server
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")
}

// Initialize the server
err = s.init(false)
if err != nil {
err2 := s.closeDB()
if err2 != nil {
log.Errorf("Close DB failed: %s", err2)
}
return err
}

// Register http handlers
s.registerHandlers()

log.Debugf("%d CA instance(s) running on server", len(s.caMap))

// Start operations server
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)
}

// Start listening and serving
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\tcertlib\tlslib\ca.go等深入,了解其签名验证的流程。