主题
14 · Fabric-X 认证与 MSP 协同
本章回答一个具体问题:Fabric-X 里这些 MSP 到底如何协同工作。所有 :line 引用指向 fabric-x-orderer/ / fabric-x-committer/,以及二者共享的 fabric-x-common/msp(vendored 于 fabric-x-orderer/vendor/.../fabric-x-common/msp/,与 module cache @v0.2.x 一致)。
一句话现状:Fabric-X 没有一个统一的 MSP 校验点。所有信任源自同一个 channel/shared config block —— 里面每个 party 一份
FabricMSPConfig;orderer 与 committer 各自把它重建成一个channelconfig.Bundle(内含一个MSPManager+PolicyManager),然后在不同检查点、以不均匀强度消费这些 MSP:有的走完整 Fabric MSP,有的为性能退化成裸 ECDSA 公钥,有的业务点甚至可以完全绕开 MSP。
配套阅读:02 信任与身份模型(KMS/mTLS/链上权限 5 道关卡)、09 CA 与证书签发(fabric-ca / sign-pki / sign-kms 签发侧)。
1. 唯一信任根:一个 party = 一个 org MSP,身兼两职
- 网络里的 MSP 集合 = 每个 party 一个
org{partyID}(org1..orgN)。同一个org{i}同时被写进 config 的Orderer.Organizations与Application.Organizations两个组(fabric-x-orderer/config/generate/config_block_gen.go:70-122)——这与经典 Fabric(orderer org ≠ application org)不同。没有单独的 "client org",客户端 / 管理员是同一 org 下的users/user、users/admin(fabric-x-orderer/common/tools/armageddon/cryptogen.go:76-86)。 - 每个节点角色(router / batcher / consenter / assembler)共享该 party 的
LocalMSPID = org{partyID}(fabric-x-orderer/config/generate/local_config_gen.go:215),但各自有独立的LocalMSPDir(自己的 cert/key)。 Consenter条目引用MSPID: org{i}+Identity: party.ConsenterConfig.SignCert(config_block_gen.go:52-61、fabric-x-orderer/config/shared_config.go:75)。
1.1 签名 CA 与 TLS CA 全程分离
每 party 生成两套 CA(cryptogen.go:242-266):
| 维度 | 签名 CA | TLS CA |
|---|---|---|
| 磁盘目录 | msp/cacerts(+ intermediatecerts) | msp/tlscacerts(+ tlsintermediatecerts) |
| 引擎存储 | bccspmsp.rootCerts / intermediateCerts | bccspmsp.tlsRootCerts / tlsIntermediateCerts |
| 校验逻辑 | validateCAIdentity | validateTLSCAIdentity(独立 x509.VerifyOptions) |
来源:fabric-x-common/msp/mspimplsetup.go:109-169(signing)与 :472-523(TLS,作为独立信任根)。一个 FabricMSPConfig / 一个 MSP 对象内部并存两套互不混用的信任根 —— 对应磁盘上 cacerts vs tlscacerts 两个目录。
1.2 实际生成器 + NodeOUs 现状
角色区分靠 admincerts,不是 NodeOUs
Arma 网络引导用的是 common/tools/armageddon/cryptogen.go(GenerateCryptoConfig,:87-107;目录布局 :45-86),不是 internal/cryptogen/msp(后者只有测试在调,等于死代码)。armageddon 不生成 config.yaml / NodeOUs —— 用显式 admincerts(逐字节比对)做管理员识别(createAdminSignCertAndPrivateKey,cryptogen.go:357-377),尽管 MSP 引擎完整支持 NodeOU 枚举与强制(mspimplsetup.go:341-416、mspimplvalidate.go:234-291)。签名证书严格来说只有 batcher / consenter 必需(签 BAS / 区块),但对所有角色都生成了。
1.3 MSP 配置怎么"流通"
MSP 配置内嵌在 config block 的每个 Organization 组里(fabric-x-common/common/channelconfig/organization.go:25-27 的 OrganizationProtos.MSP)。NewChannelConfig(channel.go:85-124)遍历 Application/Orderer 子组的每个 org MSP,最后 CreateMSPManager()(channelconfig/msp.go:99-110)把它们汇成一个 MSPManager。
于是每个 orderer / committer 节点独立地从(引导或最新)config block 重建这个 Bundle —— 大家的 MSP 视图天然一致,且随 config-update 区块一起轮换。此外每个节点从本地磁盘加载自己那张 SignCert(fabric-x-orderer/common/msputils/localmsp.go:17-49,被 node/server/arma.go:71,106,147,188 各角色调用)作为签名身份 SigningIdentity。
2. 同一张 SignCert,三种用法(协同的关键机巧)
一个 consenter 的同一张签名证书用在三处,验证代码路径却完全不同:
| 用途 | 验证方式 | 出处 |
|---|---|---|
| 区块背书策略里的 MSP 身份 | 完整 MSP + SignaturePolicyEnvelope(N-of-M) | fabric-x-orderer/node/consensus/synchronizer/sig_verifier.go:90-262(msppb.NewIdentity(MspId, Identity) + EvaluateSignedData;consenter 按 ID 查 :264-271) |
| BFT 共识快路径签名 | 裸 ECDSA 公钥 map((shard,partyID)→ecdsa.PublicKey),公钥从 SignCert 提取,不走 MSP | node/crypto/verifier.go:30-77;公钥来源 config/config.go:697-703;验签 node/consensus/consensus.go:483-560,629-631 |
| 节点间 RPC 认证握手 | 签 {ver,ts,from,to,SessionBinding},SessionBinding = TLS 导出密钥材料(绑定到具体 mTLS 连接、防重放);对照 MemberMapping(nodeID→裸公钥/身份) | node/comm/commauth.go:240-284、node/comm/clusterservice.go:114-167;密钥材料 node/comm/util.go:657-680(label "orderer v3 authentication label") |
签名者始终是节点本地 MSP 的 SigningIdentity(同一把私钥/算法),只是 orderer 内部为低延迟走裸 ECDSA、区块校验走完整 MSP/policy。MemberMapping 由 config 的 consenter 集填充(clusterservice.go:229-254),所以裸公钥路径与 MSP 路径咬合在同一份 consenter 证书上。
3. 认证检查点全景
| 检查点 | 用的 MSP | 强度 / 出处 |
|---|---|---|
| ① 传输 mTLS | 只验 TLS CA(tlscacerts),与签名 CA 分离,不提取身份 | 只证"连得上",不做业务授权;内部端口强制 mTLS(node/utils/util.go:84-91,155-162),客户端端口可选 |
| ② 客户端广播 | 完整 MSP:SigFilter→/Channel/Writers→DeserializeIdentity + Validate + SatisfiesPrincipal(member) | common/requestfilter/sigfilter.go:35-53;policy 名 policies.ChannelWriters,来自 bundle.PolicyManager()(node/config/utils.go:39-73);默认关(clientSignatureVerificationRequired=false,test/utils/utils.go:147);batcher 独立复验(node/batcher/requests_inspector_verifier.go:143-161) |
| ③ orderer 内部 | 裸 ECDSA + TLS 会话绑定握手(见 §2),非 MSP | 高性能快路径;⚠️ ConsenterSupportAdapter.SignatureVerifier() 目前是返回 nil 的 stub(TODO 缺口,node/consensus/consenter_support_adapter.go:43-51) |
| ④ 区块校验 | 完整 MSP:/Channel/Orderer/BlockValidation = N-of-M over consenter MSP 身份 | orderer 同步器(synchronizer/sig_verifier.go:90-262)与 committer(下 §4)都这么验;config 加载时强制该策略"必须正好是 consenter 集"(config/verify/orderer_rules.go:528-585,consenter 一致性 :416-463,TLS-CA 一致性 :590-614) |
| ⑤ committer 每笔交易 | 每 namespace 一套策略,可选 MSP:MspRule(Fabric cauthdsl DSL)或 ThresholdRule(裸公钥,完全不碰 MSP) | 业务合法性的真正闸门;见 §4 |
4. Committer 的关键分叉:业务身份可绕开 MSP
Committer 侧刻意把两层解耦。
4.1 orderer 区块投递验证 —— 完整 Fabric MSP
- 连 orderer 的客户端身份是一份完整 Fabric MSP 本地身份(
utils/ordererdial/identity.go:20-41,msp.LoadLocalMspDir+GetDefaultSigningIdentity),用于签 deliver 流的SeekInfo。 - orderer 端点的 TLS 信任根直接取自 config block 的 orderer-org CA 证书(
utils/ordererdial/dialinfo.go:37-83,从m.OrdererOrganizations的org.CACerts推),不是单独的信任库。 - 区块校验走
policies.BlockValidation+protoutil.BlockSigVerifier(BFT 时按数字 consenter ID 查身份)—— 标准 Fabric MSP/policy(utils/deliverorderer/verify.go:193-251,279-301);config 区块到来时重载 Bundle/policy,信任随之轮换(verify.go:256-277)。
4.2 每笔交易的 namespace 签名策略 —— MSP 可选
applicationpb.NamespacePolicy 是个 oneof(fabric-x-common/api/applicationpb/config.proto):
| 规则 | 含义 | 是否用 MSP | 出处 |
|---|---|---|---|
ThresholdRule | {scheme, public_key},对裸公钥验签,不解析证书/不查 MSP(endorsement 的 Identity 字段被忽略) | ❌ 无 MSP | utils/signature/verify.go:91-110(NewNsVerifierFromKey)、verify_ecdsa.go:23-48 |
MspRule | 一个 Fabric SignaturePolicyEnvelope,经 cauthdsl.NewPolicyProvider(idDeserializer) 评估(如 OR('Org1MSP.member')),与经典 Fabric 链码背书策略同款,只是按 namespace 而非 chaincode 作用域 | ✅ 完整 MSP | utils/signature/verify.go:63-82(NewNsVerifierFromMsp) |
分派开关:NewNsVerifier 的 switch(utils/signature/verify.go:63-72)。逐 namespace 校验入口:service/verifier/verify.go:125-167(找不到策略 → ABORTED_SIGNATURE_INVALID)。支持方案 ECDSA / EdDSA / BLS(utils/signature/types.go:29-38);三者都是"公钥 + 方案",无证书链逻辑。
一个可疑常量
EdDSA 验签用了固定 Context: "Example_ed25519ctx"(utils/signature/verify_eddsa.go:14-30)—— 看起来像遗留的占位/测试上下文串,值得留意。
4.3 谁能设/改 namespace 策略 —— 治理仍归完整 MSP
- 设/改一个 namespace 的策略,是一笔写入
_metanamespace 的交易(key = 目标 namespace ID,value = 序列化NamespacePolicy);通道级配置变更走_config(committerpb.MetaNamespaceID="_meta"/ConfigNamespaceID="_config")。 - 这两类治理交易由通道级
/Channel/Application/LifecycleEndorsement(完整 Fabric MSP) 把关(service/verifier/policy/policy.go:34,149-156)—— namespace 不能自证 / 自改自己的治理。 _confignamespace 的交易"不在此处按 namespace 策略验签,其签名由排序服务验"(service/verifier/verify.go:138-142)。- 策略更新的来源严格是已落账的链上状态:coordinator 只在 VC 报
COMMITTED后才updateFromTx(service/coordinator/validator_committer_manager.go:368-393),再经VerifierUpdates增量下发,Verifier 端updatePolicies解析后 atomic 无锁热替换(service/verifier/verify.go:39-104)。
5. MSP 引擎如何校验一个身份
共享引擎 fabric-x-common/msp 的 bccspmsp(X.509/BCCSP 实现)身份生命周期:
DeserializeIdentity → Validate → SatisfiesPrincipal
(解析 cert / 查已知 (建链 + CRL (role / identity / OU /
cert-ID) 撤销 + OU 校验) combined / anonymity 主体)MSPManager.DeserializeIdentity(mspmgrimpl.go:75-106)先按MspId查mspsMap,查不到直接报"MSP %s is not defined on channel"(:82-84)—— 身份必须属于 config 里声明过的某个 org。bccspmsp.DeserializeIdentity(mspimpl.go:398-418)→validateIdentity(mspimplvalidate.go:21-61:算法检查 → 建证书链 → CRL 撤销比对 → OU 校验)。SatisfiesPrincipal(mspimpl.go:448-705)处理ROLE(MEMBER/ADMIN/CLIENT/PEER/ORDERER)、IDENTITY(逐字节 cert 匹配)、ORGANIZATION_UNIT、COMBINED、匿名等主体;NodeOU 开启时 admin/orderer role 走hasOURole,否则回退到admincerts逐字节匹配。
Setup 管线(mspimplsetup.go)依次装载:签名 CA(setupCAs)、TLS CA(setupTLSCAs,独立信任根)、NodeOUs(setupNodeOUsV142,FabricNodeOus 为空则 ouEnforcement=false)、admins、CRL、本地签名身份。
6. 与 CBDC 部署的映射
- CBDC 的链上闸门包括 committer 上 namespace 策略;Auditor 审计与 Endorser 背书由 Panurus/FSC 交易链路实施。认证层次见信任与身份模型,不要再用固定“每笔五签”概括所有 driver 与钱包类型。
- 网络层 MSP 由 Fabric-X topology 生成;开发环境证书流程位于
dev/scripts/gen_crypto.sh与dev/internal/controller/(见 09 CA 与证书签发)。 - Orderer / Committer 的 KMS-enabled 镜像与网络构建逻辑当前归
cbdc-infra/cbdc-network/;开发 topology 来源是dev/config/network/,生成结果在dev/run/config/cbdc-network/。旧顶层cbdc-network/Makefile不是当前入口。
7. 已知软点与缺口
| # | 问题 | 出处 |
|---|---|---|
| 1 | 客户端广播签名默认关(ClientSignatureVerificationRequired=false) | fabric-x-orderer/test/utils/utils.go:147 |
| 2 | MSP 的 admin/member role 在部分 config 路径不严格区分(组织私钥即可满足策略) | 见 02 信任模型 · 缺陷清单 |
| 3 | mTLS 只做连通性证明,不提取调用方身份做授权 | node/router/shard_router.go |
| 4 | armageddon 不生成 NodeOUs,角色识别退回 admincerts | common/tools/armageddon/cryptogen.go(无 config.yaml) |
| 5 | ConsenterSupportAdapter.SignatureVerifier() 为返回 nil 的 stub | node/consensus/consenter_support_adapter.go:43-51 |
[未核]
internal/cryptogen/msp仅被测试引用(grep 无生产调用点),据此判为死代码/遗留;未见显式弃用注释。applicationpb.Tx.ASN1Marshal的逐字节签名输入未追(位于fabric-x-common);仅确认它是VerifyNs的签名对象(utils/signature/verify.go:121)。policies.ChannelWriters从ImplicitMetaPolicy到 per-orgSignaturePolicy的完整评估逻辑在 vendoredfabric-x-common/common/policies,仅核对了常量定义,未逐行追评估器。- batcher→consenter 的 BAF 提交(
consenter_control_event_sender.go,走Consensus.NotifyEvent流)是否也套用 §2 的NodeAuthRequest握手,未确认。 - §2/§4 各缺口在 fabric-x 最新主干是否已修,未核。