主题
09 · CA 与证书签发
本章只描述代码与配置中可直接定位的事实。证书层级、根 CA / 中间 CA / 叶子证书的实际部署模式以 sign-ca/ 与 fabric-ca/ 源码为准;cbdc-chain 内部 docs/ 不作引用。
1. 系统中所有 CA 触点
| 触点 | 角色 | 主要文件 |
|---|---|---|
sign-ca/Dockerfile | 构建 fabric-ca-server + PKCS#11 库的镜像 | sign-ca/Dockerfile:7-93 |
sign-ca/cmd/sign-ca-cli/ | 离线签名工具(root self-sign + intermediate sign-csr) | sign-ca/cmd/sign-ca-cli/commands/*.go |
sign-ca/deploy/multi-ca/ | per-bank intermediate CA 部署样板 | sign-ca/deploy/multi-ca/docker-compose.yaml、root/README.md |
fabric-ca/lib/ | enroll/register/reenroll/revoke/gencrl/idemix 全部 HTTP 处理 | fabric-ca/lib/server*.go |
cbdc-infra/cbdc-tool/Dockerfile | 打包 fabric-ca-client + fxconfig + libkms_pkcs11.so | cbdc-infra/cbdc-tool/Dockerfile |
cbdc-network/Makefile | make setup-kms 调 cbdc-tool 生成网络层证书,并从 CA 拉 TLS root | cbdc-network/Makefile:85-117, 208-237 |
cbdc-biz/scripts/gen_crypto.sh | 在 setup 阶段为 issuer / auditor wallet + bizhub admin 调 fabric-ca-client enroll,并 gen_institution_cert 签发 institution 证书 | cbdc-biz/scripts/gen_crypto.sh:22-75, 268-405 |
cbdc-biz/app/bizhub/internal/biz/ca.go | 运行时调 fabric-ca /enroll /register(仅 bizhub) | cbdc-biz/app/bizhub/internal/biz/ca.go:166-295 |
cbdc-biz/app/bizhub/internal/server/mtls_middleware.go | 从 mTLS 客户端证书 OU/CN 提取 institution_code | cbdc-biz/app/bizhub/internal/server/mtls_middleware.go:62-105 |
2. 三件套:fabric-ca + sign-ca + sign-kms 的分工
| 组件 | 出处 | 关键事实 |
|---|---|---|
| fabric-ca-server | sign-ca/Dockerfile:47-54 | FABRIC_CA_REF=v1.5.16、GO_TAGS=pkcs11 |
| Idemix 默认曲线 | sign-ca/Dockerfile:93 | CMD 强制 --idemix.curve gurvy.Bn254,覆盖 fabric-ca 默认 amcl.Fp256bn(fabric-ca/lib/server/idemix/config.go:30) |
| PKCS#11 库 | sign-ca/Dockerfile:78 | 从 ${SIGN_KMS_IMAGE} COPY libkms_pkcs11.so 到 /usr/local/lib/ |
| KMS 接口 | sign-kms/p11client/proto/kms.proto:7-13 | 5 个 RPC:GenerateKeypair / GetPublicKey / Sign / Verify / HealthCheck |
| 私钥不出库 | sign-kms/internal/biz/kms_biz.go:268-317 | Sign 只接收 digest + key handle,PKCS#11 C_Sign 在 HSM 内完成;protobuf 无 ExportPrivateKey 类 RPC |
| namespace = HSM partition | sign-kms/internal/biz/kms_biz.go:56-69 | namespace.TokenLabel 字段绑定到 PKCS#11 partition;JWT 中的 partitionID 用于路由 |
| PKCS#11 PIN | sign-ca/deploy/multi-ca/docker-compose.yaml:94 | fabric-ca-server 通过 FABRIC_CA_SERVER_BCCSP_PKCS11_PIN=${KMS_PIN_BANK1} 注入 JWT 作 PIN |
3. 证书层级(含中间 CA)
Root CA (offline / 离线)
├─ 私钥:sign-kms root partition
├─ 证书:sign-ca/deploy/multi-ca/root/ca-cert.pem(静态)
└─ 由 sign-ca-cli self-sign 生成
│
│ sign-ca-cli sign-csr(离线签 CSR)
▼
┌──────────────────────────────────────────────┐
│ │
Intermediate CA (per-bank) fabric-ca-server(cbdc-ca-server-kms)
├─ 私钥:sign-kms partition KMS_PIN_BANKn ├─ 私钥:sign-kms partition KMS_USER_PIN
├─ 证书:deploy/multi-ca/bank<n>/ca-cert.pem ├─ 仓库内 conf/ca 配为 root/独立运行
└─ 运行 fabric-ca-server (sign-ca 镜像) │ (parentserver.url 留空,见 §5.4/§11)
└─ 是否做中间 CA 取决于部署方
│ │
▼ ▼
Bank wallet certs Orderer/Committer/Biz-app
(institution-NNN admin / users) (issuer, endorser, auditor,
institution-001, mTLS server)仓库现状
sign-ca/deploy/multi-ca/是完整的 root → intermediate → leaf 三层模板(sign-ca/deploy/multi-ca/docker-compose.yaml:1-26、root/README.md:1-51)。cbdc-network/configs/test-full-kms.yaml的kms:块(:23-27)只给出 endpoint / token_label / ca_url,未声明任何分层/中间 CA(无intermediate.parentserver.url);意味着 cbdc-network 默认走"单 fabric-ca-server"形态——这台 server 自身既可以是 root,也可以是 intermediate,取决于${CA_URL}指向的 fabric-ca-server 启动配置(见 §6)。- 是否启用 intermediate 由部署方通过
fabric-ca-server-config.yaml: intermediate.parentserver.url决定,配置定义见fabric-ca/lib/caconfig.go:160-171。
4. Bootstrap:root → intermediate 的离线签发
来源:sign-ca/deploy/multi-ca/docker-compose.yaml:1-26、sign-ca/deploy/multi-ca/root/README.md:1-51、sign-ca/cmd/sign-ca-cli/。
4.1 sign-ca-cli 三个命令的代码事实
| 命令 | 入口 | 关键逻辑 | 是否调 KMS |
|---|---|---|---|
self-sign | sign-ca/cmd/sign-ca-cli/commands/self_sign.go:19, 59-104 | x509.CreateCertificate(rand.Reader, tmpl, tmpl, ..., signer)(template=parent=tmpl 表示自签) | ✅ OpenP11Signer(pki/p11.go:52-102)+ C_Sign |
gen-csr | sign-ca/cmd/sign-ca-cli/commands/gen_csr.go:17, 67 | x509.CreateCertificateRequest(rand.Reader, tmpl, signer) | ✅ 同上,调 C_Sign 给 CSR 自签 |
sign-csr | sign-ca/cmd/sign-ca-cli/commands/sign_csr.go:17-127 | 读 issuer cert 与 CSR → 校验 CSR 签名 → 由 issuer cert 推 issuer SKI → 校验 KMS key 与 issuer cert 公钥一致 → BuildCATemplate(PathLen) → x509.CreateCertificate(tmpl, issuerCert, csr.PublicKey, signer) | ✅ issuer 私钥 |
BuildCATemplate(sign-ca/cmd/sign-ca-cli/pki/cert.go:36-64)固定 IsCA: true,KeyUsage = CertSign | CRLSign | DigitalSignature,BasicConstraintsValid: true:
PathLen < 0→ 不设约束(无限层级,根用)PathLen == 0→MaxPathLen=0, MaxPathLenZero=true(该 cert 不可再签下级 CA,叶级 intermediate 用)PathLen > 0→MaxPathLen=PathLen(多级 intermediate)
4.2 multi-ca 部署的 bootstrap 顺序
sign-ca/deploy/multi-ca/docker-compose.yaml:8-26 注释中明确:
docker compose up -d kms postgres启基础设施- 浏览器打开
:9201,per-bank 创建 partition,拿 JWT 写入.env的KMS_PIN_BANK<n> docker compose run --rm pg-init(profile=init,docker-compose.yaml:63-81)初始化 PG role + database- 预放
bank<n>/ca-cert.pem(由前述 sign-csr 离线签好),fabric-ca-server 启动时检测到该文件存在则跳过自动 self-sign docker compose up -d ca-bank<n>
root/README.md:1-6 强调:root partition 无 fabric-ca-server service、无 DB、无端口,私钥只活在 sign-kms root partition 内,由密钥仪式委员会持有 JWT。
5. fabric-ca 内置 intermediate CA 模式
仓库现状之外,fabric-ca-server 自身支持"启动时向父 CA enroll 拿 sub-CA cert"的内置 intermediate 模式(与 §4 的"离线 sign-csr 预放"是两种不同实现)。代码事实:
5.1 配置字段
fabric-ca/lib/caconfig.go:160-171:
go
type ParentServer struct {
URL string `opt:"u" help:"URL of the parent fabric-ca-server (e.g. http://<username>:<password>@<address>:<port)" mask:"url"`
CAName string `help:"Name of the CA to connect to on fabric-ca-server"`
}
type IntermediateCA struct {
ParentServer ParentServer
TLS tls.ClientTLSConfig
Enrollment api.EnrollmentRequest
}YAML 路径:intermediate.parentserver.url / intermediate.parentserver.caname / intermediate.tls.* / intermediate.enrollment.*。
启动 flag:-u <parent-url>(opt:"u" 标签)。
5.2 Bootstrap 流程
fabric-ca/lib/ca.go:271-300:
go
if ca.Config.Intermediate.ParentServer.URL != "" {
log.Debugf("Getting CA cert; parent server URL is %s", ...)
// 构造 ClientConfig(TLS + Enrollment + CAName)
resp, err = clientCfg.Enroll(ca.Config.Intermediate.ParentServer.URL, ca.HomeDir)
}启动时若 ParentServer.URL 非空 → 当前 server 作为 client 向父 CA 调 /enroll 拿 sub-CA cert,落盘到 ca.HomeDir。
5.3 证书链构造
fabric-ca/lib/ca.go:390-406, 435:
go
func (ca *CA) getCAChain() (chain []byte, err error) {
// 1) 若 ca-chain.pem 已存在 → 直接返回
// 2) 若 ParentServer.URL == "" → 该 CA 是 root,返回 ca-cert.pem
// 3) 否则报错——intermediate 必须有 ca-chain.pem(由 enroll 流程创建)
}链文件默认名:ca-chain.pem(fabric-ca/lib/caconfig.go:122 def:"ca-chain.pem")。链拼接顺序受环境变量 CA_CHAIN_PARENT_FIRST 控制(fabric-ca/lib/ca.go:368-377)。
5.4 两种 intermediate 模式对比
| 维度 | 离线 sign-csr(§4) | 内置 enroll(§5) |
|---|---|---|
| 触发点 | 仪式机手动一次性 | fabric-ca-server 启动时自动 |
| Root 在线性 | 永久离线,root 私钥只在 sign-kms root partition | 父 CA 必须在线,否则 sub-CA 起不来 |
| 私钥流动 | 全程不出 sign-kms | 同上(用 BCCSP PKCS#11 即可) |
| 链文件 | 部署方手工拼 ca-chain.pem 或 fabric-ca 启动后 /cainfo 返回 | fabric-ca 自动写 ca-chain.pem |
| 当前仓库使用 | sign-ca/deploy/multi-ca/ 走这条 | 部署方在 fabric-ca-server-config.yaml 配 intermediate.parentserver.url 启用;cbdc-biz/conf/ca/fabric-ca-server-config.yaml:195-199 有 intermediate: 块但 url 为空(即未启用,作 root/独立运行) |
6. 签发流程(fabric-ca HTTP API)
6.1 端点清单
来源:fabric-ca/lib/server.go:549-570(registerHandlers + registerHandler,前缀 /api/v1/ 与裸路径 /<path> 双注册)。
| 路径 | 处理函数 | 注册位置 | 方法 | 成功码 |
|---|---|---|---|---|
/enroll | enrollHandler | fabric-ca/lib/serverenroll.go:49-57 | POST | 201 |
/reenroll | reenrollHandler | fabric-ca/lib/serverenroll.go:59-67 | POST | 201 |
/register | registerHandler | fabric-ca/lib/serverregister.go:23-31 | POST | 201 |
/revoke | revokeHandler | fabric-ca/lib/serverrevoke.go:36-43 | POST | 200 |
/gencrl | genCRLHandler | fabric-ca/lib/servergencrl.go:36-43 | POST | 200 |
/cainfo | cainfoHandler | fabric-ca/lib/serverinfo.go:14-21 | GET/POST/HEAD | 200 |
/idemix/credential | handleIdemixEnrollReq | fabric-ca/lib/serveridemixenroll.go:16-24 | POST | 201 |
/idemix/cri | handleIdemixCRIReq | fabric-ca/lib/serveridemixcri.go:13-21 | POST | 201 |
/healthz | healthz lib | fabric-ca/lib/server/operations/system.go:149 | — | 200 |
API 路径前缀常量:fabric-ca/lib/server.go:52 apiPathPrefix = "/api/v1/"。
6.2 enroll 流程时序
关键代码:
- 签名核心:
fabric-ca/lib/serverenroll.go:156cert, err := ca.enrollSigner.Sign(req.SignRequest) enrollSigner初始化:fabric-ca/lib/ca.go:749-753goca.enrollSigner, err = util.BccspBackedSigner(c.CA.Certfile, c.CA.Keyfile, policy, ca.csp)- BCCSP CSP(
ca.csp)通过bccsp.factory在初始化时按Default: PKCS11走 PKCS#11,CA 私钥的句柄存在 fabric-ca-server 进程内、私钥本身永远在 sign-kms 内(见 §2)。
6.3 reenroll 与 enroll 的差异
fabric-ca/lib/serverenroll.go:87-94:
go
func reenrollHandler(ctx *serverRequestContextImpl) (interface{}, error) {
id, err := ctx.TokenAuthentication() // 用现有 cert 的 token 鉴权
...
resp, err := handleEnroll(ctx, id) // 共用 handleEnroll
}唯一区别:鉴权方式 — enroll 用 BasicAuthentication(user+pass),reenroll 用 TokenAuthentication(持有的有效 X.509 cert 派生 token)。证书生成逻辑完全相同。
6.4 register 流程
fabric-ca/lib/serverregister.go:34-68(HTTP 层)+ 135-177(核心 registerUserID):
users 表 schema:fabric-ca/lib/server/db/sqlite/sqlite.go:138(id / token / type / affiliation / attributes / state / max_enrollments / level / incorrect_password_attempts)。
返回的 Secret 即"一次性口令",配合 enroll 的 Basic Auth 使用。
6.5 revoke 与 gencrl
fabric-ca/lib/serverrevoke.go:60-191:
| 模式 | 入口分支 | 持久化动作 |
|---|---|---|
| 按 Serial+AKI | :86-129 | certDBAccessor.RevokeCertificate(req.Serial, req.AKI, reason) :124 |
| 按身份 | :129-175 | certDBAccessor.RevokeCertificatesByID(req.Name, reason) :162 + user.Revoke() :155 |
若 req.GenCRL == true(:182-189),同步生成 CRL。独立 /gencrl 端点:fabric-ca/lib/servergencrl.go:46-83,需 hf.GenCRL 属性(:70-72)。
吊销原因码 RFC 5280:fabric-ca/lib/serverrevoke.go:46-57。
certificates 表:fabric-ca/lib/server/db/sqlite/sqlite.go:154(含 status / reason / revoked_at 列)。
6.6 Idemix 凭证签发
fabric-ca/lib/serveridemixenroll.go:16-33:
go
// POST /api/v1/idemix/credential
ca.issuer.IssueCredential(&idemixServerCtx{ctx})Idemix issuer 初始化:fabric-ca/lib/ca.go:136-143
go
ca.issuer = idemix.NewIssuer(ca.Config.CA.Name, ca.HomeDir,
&ca.Config.Idemix, ca.csp, idemix.NewLib(curveID), curveID)曲线选择:fabric-ca/lib/ca.go:1299-1312 curveIDFromConfig();默认 amcl.Fp256bn(fabric-ca/lib/server/idemix/config.go:30),可选 gurvy.Bn254 / amcl.Fp256Miraclbn(fabric-ca/lib/common/idemix/common.go:45-48)。sign-ca 镜像在 CMD 强制 --idemix.curve gurvy.Bn254(sign-ca/Dockerfile:93)。
Issuer key 文件(fabric-ca/lib/server/idemix/config.go:17-26, 41-66):
| 文件 | 位置 |
|---|---|
IssuerPublicKey | $HomeDir/IssuerPublicKey |
IssuerSecretKey | $HomeDir/msp/keystore/IssuerSecretKey |
IssuerRevocationPublicKey | $HomeDir/IssuerRevocationPublicKey |
IssuerRevocationPrivateKey | $HomeDir/msp/keystore/IssuerRevocationPrivateKey |
7. cbdc-* 仓库如何调 CA
7.1 cbdc-network setup 阶段(网络层证书)
来源:cbdc-network/Makefile:85-117, 208-237。
事实:
setup-fabric-kms(Makefile:95-98,KMS_CONFIG 缺省configs/test-full-kms.yaml,Makefile:82):调 cbdc-tool 容器内config-builder setup,生成 orderer/committer 的 crypto material 与 yaml 到./out/。out/内的具体证书来自config-builder(cbdc-tool 内置工具),不直接 shell 调fabric-ca-client。fetch-fabric-ca-root(Makefile:208-233):TLS_ENABLED=true时,从${CA_URL}/cainfo(去掉 URL 中凭证后)拿result.CAChain(base64),分发到out/local-deployment/committer-*/config/tls/各目录。此处仅取 Fabric CA 根证书,不做 enroll。${CA_URL}默认值(cbdc-network/.env.example:32):http://admin:adminpw@cbdc-dev.sign.global:7054。
configs/test-full-kms.yaml:23-27 的 KMS 段:
yaml
kms:
enabled: true
endpoint: '${SIGN_KMS_ENDPOINT}'
token_label: '${KMS_TOKEN_LABEL}'
ca_url: '${CA_URL}'未声明 intermediate.parentserver.url;是否启用 intermediate 由 ${CA_URL} 背后那台 fabric-ca-server 的 fabric-ca-server-config.yaml 决定(部署方配置,不在仓库内)。
7.2 cbdc-biz setup 阶段(业务层身份)
来源:cbdc-biz/scripts/gen_crypto.sh。脚本里 fabric-ca-client enroll 出现在三类钱包/MSP 身份:
- issuer wallet(
issuer/keys/wallet/iss,gen_crypto.sh:22-35) - auditor wallet(
auditor/keys/wallet/aud,:41-54) - bizhub admin MSP(
bizhub/ca-msp/msp,:63-76)
每段结构相同:
bash
docker run --rm \
-v "${dir}:/app/msp" \
-e SIGN_KMS_ENDPOINT="..." \
-e KMS_TOKEN_LABEL="..." \
-e KMS_USER_PIN="..." \
-e CA_URL="..." \
${DOCKER_TOOLS_IMAGE} \
sh -c '
envsubst < fabric-ca-client-config.yaml.tpl > fabric-ca-client-config.yaml
./fabric-ca-client enroll \
-c "./fabric-ca-client-config.yaml" \
--url "$CA_URL" \
--mspdir "./msp"
'拿到的 cert 落到容器挂载的 MSP 目录,运行时由各应用 core.yaml 的 fabric.default.msps[] 直接读。
institution 的身份则由 gen_institution_cert(gen_crypto.sh:268-408)单独生成,不走上面的 enroll 模板:
- 先 enroll 出一张 TLS Intermediate CA(
--enrollment.profile ca+hf.IntermediateCA=true,:114-147,得到CA:TRUE证书); - 再用
openssl req -subj "/O=CBDC/OU=institution/CN=institution-${code}-01"+openssl x509 -req(由该 Intermediate CA 签)生成 institution 统一证书(FSC P2P + bizhub mTLS 共用,:340-362); - 同时为该 institution enroll 一份 KMS 支撑的 CA admin MSP(
bizhub/ca-msp/institution-<code>/msp,PIN 取INSTITUTION_<code>_KMS_PIN,:375-405),供 §7.3 的 bizhub 运行时加载。
证书链:Fabric CA(Root,私钥在 KMS)→ Bank Intermediate CA (pathlen:0) → institution / bizhub 叶子证书(gen_crypto.sh:262 注释)。
7.3 cbdc-biz 运行时:bizhub 调 enroll / register
来源:cbdc-biz/app/bizhub/internal/biz/ca.go。
bizhub 运行时直接 import github.com/hyperledger/fabric-ca/lib(ca.go:31),为每家 institution 构造独立的 lib.Client + admin Identity(loadInstitutionAdmin,ca.go:166-245):
go
cspOpts := &factory.FactoryOpts{
Default: "PKCS11",
PKCS11: &pkcs11.PKCS11Opts{
Library: defaults.GetLibrary(),
Label: label, // pkcs11TokenLabel(defaults)
Pin: caCfg.GetPin(), // 每家 institution 自己的 JWT
Hash: defaults.GetHash(),
Security: int(defaults.GetSecurity()),
},
}
client := &lib.Client{Config: &lib.ClientConfig{
URL: caCfg.GetUrl(),
MSPDir: caCfg.GetAdminMsp(),
CSP: cspOpts,
}}
client.Init()token label 由 pkcs11TokenLabel(defaults)(ca.go:149-158)从全局配置 ca.pkcs11Defaults.label 读取——所有 institution 共享同一 label(缺省即报错,无 os.Getenv 兜底);per-institution 的隔离靠各自的 Pin(JWT,Bootstrap institutions[].ca.pin)路由到不同 partition。
institution admin 按需懒加载:getInstitutionAdmin(ca.go:121-137)首次被调用时才 loadInstitutionAdmin 并缓存,不是启动时全量加载。后续 Register(ca.go:247-295)经 admin.identity.Register() 动态注册机构用户,Enroll(ca.go:297+)另起一个临时 lib.Client 调 /enroll。
7.4 其他业务应用:静态 MSP + KMS 签名
- issuer / endorser / auditor / institution 的
main.go没有 importfabric-ca-client,启动时不调 enroll; - 它们读
core.yaml: fabric.default.msps[].path指向的静态 MSP 目录(cert 已经在 setup 阶段由gen_crypto.sh放好),私钥句柄通过 BCCSP PKCS#11 走 sign-kms:
yaml
fabric:
default:
driver: fabricx
msps:
- id: user
mspType: bccsp
mspID: Org1MSP
path: ./keys/fabric/user
opts:
BCCSP:
Default: PKCS11
PKCS11:
Library: /usr/local/lib/libkms_pkcs11.so
Label: KMS_TK
Pin: ${KMS_USER_PIN}来源:cbdc-biz/conf/issuer/core.yaml:71-92。Token SDK wallet 同样走 PKCS#11(:144-155)。
7.5 cbdc-infra/cbdc-tool 镜像
来源:cbdc-infra/cbdc-tool/Dockerfile:1-50、cbdc-infra/Makefile:18-22。
- 基础镜像:
FROM ghcr.io/built-by-sign/fabric-x-tool:${FABRIC_X_TOOL_TAG}(Dockerfile:8;ARG默认v0.0.9,Dockerfile:1),fabric-ca-client由该基础镜像自带(cbdc-tool/Dockerfile 内未显式RUN install)。 libkms_pkcs11.so:Dockerfile:20COPY --from=so_source /usr/lib/libkms_pkcs11.so /app/(so_source=${SIGN_KMS_IMAGE})。
cbdc-infra/Makefile:18-22 的 build-cbdc-tool:
makefile
$(CONTAINER_CLI) build --platform=$(PLATFORM) -f ./cbdc-tool/Dockerfile \
$(if $(FABRIC_X_TOOL_TAG),--build-arg FABRIC_X_TOOL_TAG=$(FABRIC_X_TOOL_TAG)) \
--build-arg SIGN_KMS_IMAGE=$(SIGN_KMS_IMAGE) \
-t $(IMAGE_PREFIX)/cbdc-tool:$(TAG) .cbdc-ca-server-kms 镜像(sign-ca/Dockerfile):cbdc-infra/Makefile:15 的 build-all 依赖 build-ca-server-kms、:29 push cbdc-ca-server-kms:$(TAG),但 build-ca-server-kms 的 target 实体并未在 cbdc-infra/Makefile 内定义(sign-ca 仓库的镜像构建 target 名为 build,见 sign-ca/Makefile:41)。
8. mTLS 与运行时身份提取
来源:cbdc-biz/app/bizhub/internal/server/grpc.go:21-91、cbdc-biz/app/bizhub/internal/server/mtls_middleware.go:22-134。
8.1 服务端 TLS 装配
grpc.go:64 tls.LoadX509KeyPair(cfg.Cert, cfg.Key) 加载 server cert / key;:74-87 当 RequireClientCert==true 时读 CA 证书并设 ClientAuth = tls.RequireAndVerifyClientCert。
cbdc-biz/conf/bizhub/core.yaml:52-57:
yaml
tls:
enabled: true
cert: ./keys/mtls-server.crt
key: ./keys/mtls-server.key
ca_cert: ./keys/mtls-ca.crt # Fabric CA root
require_client_cert: true8.2 客户端证书 → 角色 / institution_code
extractMTLSIdentity(mtls_middleware.go:73-105)读 client cert 的 Subject OU(leaf.Subject.OrganizationalUnit[0]),按 auth.Role 常量(pkg/common/auth/context.go:16,19,22)匹配:
| OU 值 | 角色 | institution_code 来源 | 行号 |
|---|---|---|---|
institution | RoleInstitution | 从 CN(约定 institution-<code>-<seq>,split - 取 parts[1]) | :91-100 |
central | RoleCentralBank | 无(服务身份,不带 institution_code) | :101-102 |
auditor | RoleAuditor | 无 | :101-102 |
其它 OU(issuer/bizhub/endorser/orderer-* 等)或无 cert → 不识别,请求放行(:104)。仅 RoleInstitution 会强制校验/回填请求体的 institution_code(:38-55,通过 protobuf 反射,:107-134)。
这意味着:institution client cert 的 OU 必须是字面量 institution、CN 必须是 institution-<code>-<seq>。该 cert 由 cbdc-biz/scripts/gen_crypto.sh:340-352 的 openssl req -subj "/O=CBDC/OU=institution/CN=institution-${code}-01" 生成(见 §7.2 末),并由 TLS Intermediate CA 签发。
9. 撤销链路
- X.509 cert 撤销:fabric-ca
/revoke→ certificates 表 →/gencrl拉 CRL →cbdc-biz/pkg/common/revocation缓存(refreshInterval = 30 * time.Second,cache.go:32;详见 02 信任与身份模型 §失效与撤销)。 - KMS token 撤销:sign-kms
DisableAccessToken把 access token 记录置为disabled(kms_manage_biz.go:506-510),后续 JWT 校验拒绝,签名调用立即失败(无需等 CRL)。两条路独立:cert 撤销影响 mTLS / MSP 身份,KMS token 撤销影响 PKCS#11 签名调用。
10. 关键事实速查表
| 问题 | 答案 | 出处 |
|---|---|---|
| 默认 Idemix 曲线 | gurvy.Bn254(被 sign-ca Dockerfile CMD 强制) | sign-ca/Dockerfile:93 |
| fabric-ca 版本 | v1.5.16 | sign-ca/Dockerfile:47 |
| fabric-ca build tag | pkcs11 | sign-ca/Dockerfile:54 |
| PKCS#11 库路径(容器内) | /usr/local/lib/libkms_pkcs11.so | sign-ca/Dockerfile:78、sign-ca/cmd/sign-ca-cli/commands/doc.go:20 |
| PKCS#11 PIN 来源 | FABRIC_CA_SERVER_BCCSP_PKCS11_PIN env,注入 JWT | sign-ca/deploy/multi-ca/docker-compose.yaml:94 |
| Token label | 固定 KMS_TK(全局),按 JWT 路由 partition | sign-ca/cmd/sign-ca-cli/pki/p11.go:35、cbdc-network/.env.example:29 |
| HTTP API 前缀 | /api/v1/ | fabric-ca/lib/server.go:52 |
| Intermediate CA 启动 flag | -u <parent-url> | fabric-ca/lib/caconfig.go:161 |
| Intermediate CA 链文件 | ca-chain.pem(默认) | fabric-ca/lib/caconfig.go:122、ca.go:435 |
| bizhub 运行时是否 enroll | 是(动态注册/enroll 机构用户) | cbdc-biz/app/bizhub/internal/biz/ca.go:247-295, 297+ |
| 其他业务应用是否运行时 enroll | 否,读静态 MSP + KMS 签名 | cbdc-biz/app/<app>/cmd/<app>/main.go 无 fabric-ca/lib import |
| setup 阶段 enroll 入口 | cbdc-biz/scripts/gen_crypto.sh 通过 cbdc-tool 容器跑 fabric-ca-client enroll | cbdc-biz/scripts/gen_crypto.sh:22-75 |
| TLS root 拉取 | make fetch-fabric-ca-root:curl ${CA_URL}/cainfo → 解 base64 CAChain | cbdc-network/Makefile:208-233 |
11. [未核]
cbdc-biz/scripts/gen_crypto.sh中 issuer / auditor / bizhub-admin enroll 用的fabric-ca-client-config.yaml.tpl模板内容(决定这些钱包私钥是落盘还是走 PKCS#11)—— 模板由 cbdc-tool 镜像内置,不在本仓库。- cbdc-network
config-builder setup生成的 orderer / committer crypto material 内部走 cryptogen 还是 fabric-ca-client 的具体分支(config-builder实体在 fabric-x-tool 镜像内,本仓库不含其源码)。 cbdc-biz/conf/ca/fabric-ca-server-config.yaml含intermediate.parentserver.url字段但留空(未启用内置 intermediate 模式);启用该模式所需的 parent URL / 凭证由部署方填入,仓库未给出可用样例。- Idemix issuer key 在多机部署下是否每个 CA 实例独立生成 vs 共享(fabric-ca 默认每实例独立,cbdc-chain 部署侧编排不在本仓库)。