普通人自建基于 WiFi Calling 的通讯网络能否行得通
Tag WiFi-Calling, 语音通话, 通讯, on by view 0

写于:2026 年中 一句话结论:不行。 普通人没有合法、可行的通道走”运营商级 WiFi Calling”。技术上被三重锁死,第一道且最硬的一道就是 eUICC 证书信任链——私有证书行不通,这是硅片级的死结。能做的最远边界是应用层 VoIP over WiFi那不是 WiFi Calling


0. 写这篇文章的动机

我最近在做一个 SGP.22 SM-DP+ 的开源实现,仓库叫 sm-dp,目标是把”用户从二维码触发 eSIM Profile 下载”这条链路完整跑通。几个月时间,我把 ES9+ 第一步 initiateAuthentication 写完、容器化、跑通 HTTPS、跑通 nginx 反代、修了一遍又一遍的协议头(大小写不敏感 + 多版本协议号支持),最后 MiniLPA 真的把请求发到我服务器上,sm-dp 返回 HTTP 200 + 标准失败 envelope,错误码 subjectCode 8.8.4 / reasonCode 3.7,信息是:

“The SM-DP+ has no CERT.DPauth.ECDSA signed by a CI Public Key supported by the eUICC”

这一行错误信息不是 bug,不是协议实现不对,不是网络问题。它就是答案:eUICC 里没有能信任我 SM-DP+ 证书的 CI 公钥。

撞墙的位置:eUICC 证书信任链

我把这条墙讲清楚,再回答”那能不能自建 WiFi Calling”这个问题。


1. 先把两件事分清楚:运营商 WiFi Calling ≠ 应用层 VoIP over WiFi

读者里肯定有人把这两个当回事,所以我必须先拆开:

运营商 WiFi Calling(VoWiFi) 应用层 VoIP over WiFi
信令 IMS SIP(P-CSCF / S-CSCF / I-CSCF / TAS) App 自有协议(APNs / Signal Protocol / 自建 WS)
鉴权凭据 ISIM @ UICC(SIM 卡里那个 SIP Digest-AKA 凭据) App 账户 / 设备证书
寻址 E.164 MSISDN(手机号) App ID / UUID / 自编号
接入网 不可信 WiFi + IPsec/IKEv2 → ePDG → EPC/5GC → IMS 任何 IP 承载,裸 socket
通话对象 跨运营商经 IPX / IBCF 进 PSTN 私域;想进 PSTN 需 SIP Trunk
紧急呼叫 E.112 / E.911 路径(受 PLMN 管制) 通常无合规紧急呼叫能力
计费 / 合法监听 运营商 CDR + LI 合规 App 厂商服务器侧,不在运营商 CDR
在手机拨号盘里 是,作为运营商主叫 不是,仅 App 自己的来电界面

运营商WiFi Calling / VoWiFi 是一个 3GPP 规范的术语,本质是”把 IMS 语音搬到不可信 WiFi 上”。它不是”用 WiFi 打电话的 App”。两者在协议层完全平行,互不相通

读者能做的最远边界——也是我自己正在做的——是右列那一条。那不是 WiFi Calling。这一点必须先说死,不然下面没法讲。


2. 第一道锁(也是最硬的一道):eUICC 证书信任链无法自建,私有证书就是不行

这一节是整篇文章最重要的一节,我会写得很慢。

2.1 我手里这块 eUICC 里到底有什么

我用的是一块 Eastcompeace(东信和平)生产、GSMA SAS 编号 ED-ZI-UP-0826 的消费级商用 eUICC。svn 是 2.2.2,euiccFirmwareVer 4.2.0。我用 MiniLPA 读出 EUICCInfo2,展开 euiccCiPKIdListForVerification

euiccCiPKIdListForVerification: [
  "81370f5125d0b1d408d4c3b232e6d25e795bebfb",  // GSM Association - RSP2 Root CI1
]
euiccCiPKIdListForSigning: [
  "81370f5125d0b1d408d4c3b232e6d25e795bebfb",  // GSM Association - RSP2 Root CI1
]

就一项。不是”列表里主要是 GSMA,但也可以有别人”——是只有一项

这一项是 GSM Association - RSP2 Root CI1 的公钥指纹。整张芯片一辈子就认这一个 CI。它的公钥在 eUICC 出厂时被一次性烧入 eUICC 内部的 ECASD(Embedded Certificate Authority Security Domain)—— ECASD 是 eUICC 的 JavaCard 安全元件里专门管理证书链的应用。这个烧入是 OTP(一次性可编程)或同等强度的写保护,软件层面改不了。

2.2 我试过”绕过”,结果就是不行

我 OpenSSL 生成了一对 ECDSA P-256 私钥,自签了一张 CI 证书,role OID 用 id-rsp-ci1.3.6.1.4.1.46898.3)。再用这张自签 CI 给 SM-DP+ 签了一张 CERT.DPauth.ECDSA,role OID 用 id-rsp-dp-authentication。我把 SM-DP+ 跑起来,让 MiniLPA 触发下载。

协议层面一切正常POST /gsma/rsp2/es9plus/initiateAuthentication 200 OK,所有握手都过,serverCertificate 也下发了。但真正的 Profile 下载在 ES10b 阶段被 eUICC 拒接——eUICC 拿到 serverCertificate 后会沿着 DPauth → CI → GSMA Root CI1 做链式验签,发现”这张 DPauth 是由一张不在我信任集的 CI 签的”,链路到我的自签 CI 时断了,回退到根时对不上,于是拒接。

报错就是上面那个 8.8.4 / 3.7:”无 CI 信任的 ECDSA 证书”。

2.3 一个常见误区:”装个根证书到手机能不能绕过”

有人问过我:”那我把 GSMA Root CI1 的证书装到手机的系统信任根里,不就解决了吗?”

不行。这是一个典型的认知误区,原因有两个:

第一,iOS / Android 的”系统信任根”只管 TLS / HTTPS 客户端校验,跟 eUICC 完全无关。iOS 上你装一个企业 CA 根证书,它影响的是 Safari / Mail / 第三方 App 怎么验 HTTPS 服务器。Android 7+ 默认连用户 CA 都不信,要 root 才能让 App 默认信用户 CA。但 eUICC 是独立的 JavaCard 安全元件,跟主系统隔离,主系统的”信任根”管不到它。eUICC 验签用的是它自己烧死在 ECASD 里的那张 GSMA Root CI1 公钥,只此一份

第二,eUICC 的 ECASD 没有外部 APDU 写接口。ECASD 是 eUICC OS 厂商(Eastcompeace / Idemia / Thales 等)在工厂模式下用厂商签名固件装入的,运行态下不允许任何 APDU 修改它的信任列表。你能换的只有 Profile(普通应用),碰不到 ECASD。能”修改” ECASD 信任列表的唯一合法途径是 eUICC 固件更新——但固件更新包也得由 EUM(eUICC 厂商)私钥签发,EUM 的根又是 GSMA Root CI。走到哪里都绕回 GSMA

2.4 那”开发 / 仿真 eUICC”呢?—— 能绕,但用途有限

必须诚实补一刀:“绕”对部分 eUICC 是可以的。少数开发 / 仿真 eUICC 的 ECASD 是”软”的,工厂模式允许加载额外 CI 信任锚:

  • osmocom 系列(swp-euicc 等)
  • 某些 Idemia / Valid 测试卡(需通过厂商渠道申请,明确”测试模式”)
  • 纯软件仿真器(如某些 JavaCard 仿真器)

在这些卡上,你可以把自己生成的自签 CI 公钥塞进信任集,eUICC 就会信。但这些卡不是消费级 eUICC,不能用于任何商用场景(运营商商用网不识别它们)。它们的用途是:

  • 协议层验证(”我的 SM-DP+ 协议实现对不对”)✓
  • 端到端加密路径验证(”签名验签链路通不通”)✓
  • 真实商用 Profile 下载 ✗
  • 让消费级手机原生电话 App 把你的 SM-DP+ 当运营商 ✗

我手头这块 Eastcompeace 不在列。本文后面所有讨论都以”商用 eUICC”为前提。开发卡的”绕过”是另一篇文章的话题,不能混淆。

2.5 GSMA PKI 的真相

把上面这些事实落到 GSMA PKI 体系里看:

GSMA Root CI(公开信任锚,固化在每张合规 eUICC 的 ECASD)
    │ 由 GSMA Root CI 私钥签发
Sub-CI(也叫 CI)
    │ - EUM 厂商(Eastcompeace / Idemia / Thales / Valid / G+D 等)持有
    │ - 这些 CI 的公钥被它们出厂的 eUICC 信任
End-entity 证书:SM-DP+ / SM-DS / EUM

这张图的三个特征决定了”个人不可能”:

  1. Root CI 私钥不卖:GSMA Root CI 私钥物理隔离在 GSMA 金库里,没有任何合法出售渠道。任何说”出售 GSMA Root CI 私钥”的网站都是骗子。

  2. Sub-CI 只发给通过 SAS-SM / SAS-SDS 现场审计的企业:SAS 是 GSMA 的安全认证体系,SM(Subscription Management)针对 SM-DP+ 服务,SDS 针对 SM-DS。审计员是 GSMA 授权的第三方(BSI / atsec / TÜV 等),要查你的:

    • HSM(硬件安全模块,FIPS 140-2 Level 3 或同等),必须,不能把 SM-DP+ 私钥存成 PEM 文件塞进容器
    • 物理安保(双人控制、门禁、监控)
    • 密钥管理与备份方案
    • 站点隔离、网络隔离
    • 人员背景调查
    • 年度复审
  3. 审计周期和钱:从启动到拿证 6 到 12 个月,钱 六位数 USD 起步(HSM 几万到十几万 + 审计费 + 持续合规运维人力)。

任何个人 / 小团队,没有这条路

2.6 结论(这一节最重要的一句话)

eUICC 证书信任链是个人根本无法触碰的硅片级约束,私有证书行不通,这不是软件问题。

我在 sm-dp 里跑通 ES9+ 协议层之后撞上的墙,就是这堵墙。这堵墙在我手里这块 Eastcompeace 芯片上不可逾越,对任何商用 eUICC 都不可逾越,对所有 GSMA 体系内的”自建 SM-DP+“尝试都不可逾越。这是 eSIM 安全模型的核心:如果信任锚能由软件改写,整个体系就崩了。


3. 第二道锁:运营商 IMS 核心网不是你想接就能接

即便你解决了证书链(你做不到,但假设做到了),下一个墙是运营商 IMS 核心网

运营商 WiFi Calling 的完整链路是:

UE(手机)
   │  IPsec/IKEv2 隧道(SWu 接口,TS 33.402)
ePDG(运营商侧加密网关,Cisco / Ericsson / Nokia / Mavenir 商用产品)
   │  GTP / PMIPv6(3GPP TS 23.402 S2b / TS 23.501 非授信接入)
EPC / 5GC(核心网:MME / SGW / PGW / AMF / SMF / UPF)
   │  SIP(IMS 接入)
IMS 核心:P-CSCF → I-CSCF → S-CSCF → TAS → SBC
   │                                    │
   │                                    │ 媒体:RTP / SRTP(受 QoS 控制)
   ▼                                    ▼
HSS / UDR(用户数据库,存 ISIM 凭据)
   │ 跨运营商经 IBCF 进 IPX → 对端运营商 IMS → PSTN

相关 3GPP 规范锚点:

  • TS 23.228(IMS 总体)
  • TS 23.402(非授信非 3GPP 接入,ePDG / SWu / S2b)
  • TS 23.501 / 23.502(5G 系统架构,非授信接入归入 5GC)
  • TS 24.502(非授信接入的会话管理)
  • TS 33.402(IKEv2 / IPsec 安全)

IMS 凭据在 ISIM @ UICC——也就是 SIM 卡里的 SIP Digest-AKA 凭据。这意味着”号码”绑在 SIM 卡上,不绑在 App 上。你给朋友发个”我的 WiFi Calling 号码是 13800138000”,那个号码必须在运营商 HSS 里登记,必须有 ISIM 凭据,必须有对应的 SM-DP+ Profile 已下发到某张 UICC。这条链路没有任何一个环节是开放的

  • ePDG 是运营商专有设备
  • HSS/HLR 是运营商核心数据库
  • IBCF 是运营商间边界
  • IPX 是 GSMA 运营的 IP 交换网络(Equinix / Etisalat / Tata 是主要运营商),不接入散户

这是企业基础设施级别的封闭,普通人连”租一个 IMS”都做不到。


4. 第三道锁:iOS / Android WiFi Calling 入口是运营商 entitlement,不是用户开关

假设(不可能的假设)你前两关都过了,你的 SM-DP+ 把 Profile 下发到了某张 eUICC 上,你还需要 iOS / Android 在系统设置里亮出”WiFi 通话”开关

4.1 iOS

iOS 的 WiFi Calling 开关不是用户能强制打开的。它出现的条件是:

  1. 系统读到一张经过 Apple 审核的 carrier bundle / IPCC(carrier.plist + 配套 APN、IMS entitlement、号码映射)
  2. Modem 固件支持 IMS VoWiFi
  3. eUICC 上有对应运营商下发的 Profile

参考 Apple 官方文档:Use Wi-Fi calling on your iPhone。Apple 维护一个运营商审核流程,运营商必须提交自己的 carrier bundle 经 Apple 审核。散户的 carrier bundle 不会被审核

4.2 Android

Android 类似但更复杂。Android 11+ 的 IMS API(ImsService / ImsManager)是 AOSP 提供的接口框架,但实现必须由运营商提供

  • 运营商的 IMS 服务二进制(OEM / modem 厂商预装或系统镜像里)
  • carrier_config.xml / carrier_settings 配置文件(描述 PLMN、APN、IMS entitlement)
  • Modem HAL(QMI / RIL / IMS 调制解调器层)支持 IMS

参考 Android 官方文档:Wi-Fi calling

裸 AOSP / 第三方 ROM 没有这些运营商二进制,永远显示不出 WiFi Calling 开关。LineageOS / GrapheneOS / Pixel Experience 上你都不会看到这个开关。

4.3 平台权力

这一道锁的本质是平台权力——苹果和 Google 决定”哪个运营商能被点亮”。这不是开放接口,不是 SDK 调一调就能开。运营商必须:

  • 走 Apple 的 Carrier Bundle 审核流程
  • 与 Google 签 carrier entitlement 协议
  • 接受苹果 / 谷歌的合规审计

普通开发者、创业公司想绕过去?没门。


5. 应用层 VoIP 进不去 IMS

行,我们退一万步——不追求运营商 WiFi Calling,就做个 App 让你和朋友能语音通话。是不是就行了?

可以。但要清醒地知道,这条路是和 IMS 完全平行的另一条路:

  • FaceTime:信令走 APNs,媒体 P2P(ICE/STUN/TURN),完全不进运营商 IMS / ePDG / SIP / ISIM
  • WhatsApp / Signal / Telegram:应用层 E2EE(Signal Protocol 等),UDP/TCP/TLS 上的 proprietary 信令,不注册到 IMS,不用 ePDG,不读 ISIM
  • 我的 rtpd:自建 WebSocket 信令 + UDP RTP 媒体,phone-android / phone-ios 通过 UniFFI 调用 rtpd-sdk,跑的是 48 kHz Opus / G.711 PCMU over UDP RTP

这些应用在 App 层面 用 CallKit / VOIP Push 让锁屏体验接近原生电话——iOS 上 App 可以在锁屏弹出来电 UI,点击接听,CallKit 让通话显示在系统的”通话中”界面里。但媒体始终在 App 自己控制的实时连接里,不进运营商核心网,不被运营商 CDR 计费,不走 ePDG,不使用 ISIM 凭据。

GSMA 在 2018 年的一份白皮书里把这类服务统称为 OTT(Over-The-Top)VoIP,明确区别于运营商 VoWiFi:GSMA blog - OTT Calling Protocol Analysis

互通 PSTN 仍然需要 SIP Trunk + 落地号,回到运营商身份,绕不开。


6. GSMA SGP.22 “999” 是不是个人通道?

不是。这是个常见误解。

GSMA 在 SGP.22 体系里确实给非传统运营商 / 私有网络 / MVNO 保留了一个简化通道,对应 Apple iOS 上的”999 标识”。它的本质是:

  • 简化版 SAS-SM 合规(不是免除,仍然要 GSMA 注册 + 当地监管备案)
  • iOS PLMN 白名单(”999”是一个 MCC/MNC 范围,由 Apple 审核)
  • 走标准 SGP.22 协议(仍然是 GSMA Root CI 签发的 CI 链)

它的目标客户是:

  • 企业 / 园区 / 港口 / 矿区 / 校园的私有 5G/LTE 网络运营商
  • 有 ICP/ISP 资质的 MVNO
  • 政府 / 应急 / 国防通信

不是个人。仍然要法人主体,仍然要 GSMA 注册,仍然要合规审计。它降的是合规门槛,不是消除 GSMA PKI——这点要讲清楚。


7. “那我做私有 IMS 网不就完了?”——是的,企业可行,个人不是合适主体

有些读者看到上面可能会想:”既然问题在 IMS 核心网,那我自建一个 IMS 私有网给园区用不就行了?”

这条路技术上完全可行,且已经有很多商用产品。具体拓扑:

私有基站(small cell / 5G gNB)
私有 5GC:AMF / SMF / UPF
私有 IMS:CSCF / TAS / SBC / HSS
私有 ISIM / USIM 凭据 → 行业终端(防爆手机 / 三防 PDA / 工业模组)

商用方案提供商:Athonet、Celona、CoreNetwork Dynamics、Mavenir、华为、中兴、京信、佰才邦等。

能做什么

  • ✅ 园区内部打通:工人 A 给工人 B 走 IMS VoNR / VoLTE
  • ✅ 行业终端之间互联互通
  • ✅ 私有网络的 QoS / 紧急呼叫 / 计费 / 调度

不能做什么

  • ✗ 出园区打电话给北京/纽约/伦敦的朋友:仍要公网运营商 SIP Trunk + 落地号
  • ✗ 让消费级 iPhone / 普通 Android 原生电话 App 显示为你的私有运营商:需要 Apple / Google 审核 carrier bundle,要 GSMA PKI 颁发合法 SM-DP+ 证书链
  • ✗ 在淘宝上卖给个人用户:合规不允许

个人适不适合

  • 50–500 用户的企业场景:可走 Athonet / Celona / Mavenir 这类 SaaS 化方案,半年到一年部署完成,百万级人民币预算
  • 个人 / 小作坊:不合适。HSM + 现场审计 + GSMA 注册 + 当地工信部备案(频谱 + 电信业务资质),百万级设备和合规起步
  • 不要混淆:私有 IMS 网不是”WiFi Calling 替代品”,它是企业自建专网方案

结论:私有 IMS 是企业选项,不是个人 “WiFi Calling” 的替代品。


8. 我手头这套栈在整张图里是什么位置

让我把我自己跑的东西摆出来,给读者一个具象的”普通人能做的最远边界”:

┌──────────────────────────────────────────────────────────────┐
│ phone-android (Kotlin / Compose, 48 kHz Opus over UDP RTP)   │
│ phone-ios     (SwiftUI, G.711 PCMU over UDP RTP)            │
│       │                                                        │
│       │ UniFFI bindings                                        │
│       ▼                                                        │
│ rtpd-sdk (Rust)                                                │
│       │                                                        │
│       │ WebSocket signaling + UDP RTP                         │
│       ▼                                                        │
│ rtpd (Rust) ──── PostgreSQL(短号注册、状态)                  │
└──────────────────────────────────────────────────────────────┘

        完全在 IP 层之上,不进运营商 IMS / ePDG / ISIM
        类比:FaceTime / WhatsApp / Signal / 自建 SIP PBX
┌──────────────────────────────────────────────────────────────┐
│ MiniLPA (Kotlin 桌面 GUI)                                      │
│       │                                                        │
│       │ GSMA RSP 流程                                          │
│       ▼                                                        │
│ sm-dp (Rust / Rocket, SGP.22 SM-DP+)                         │
│   - ES9+ /gsma/rsp2/es9plus/initiateAuthentication ✓          │
│   - ES9+ /gsma/rsp2/es9plus/authenticateClient (待实现)        │
│   - ES9+ /gsma/rsp2/es9plus/getBoundProfilePackage (待实现)   │
│   - 卡在:ProfilePackagingProvider = UnavailableProvider      │
│   - 原因:没有 GSMA 签发的 CERT.DPauth.ECDSA                 │
└──────────────────────────────────────────────────────────────┘

左边那套(rtpd + phone-*)是”应用层 VoIP over any-IP”,我可以做,可以给你用,可以做完整加密协议,可以用 iOS CallKit 让体验接近原生电话。但它永远进不了运营商拨号盘

右边那套(sm-dp + MiniLPA)是”eSIM 个人化通道”,我可以做完整协议层,但永远拿不到 GSMA 签发的 SM-DP+ 证书,所以商用 eUICC 永远不信我。

这两个栈的交集:没有。它们解决不同的问题,互不替代。


9. 结论

TL;DR(再说一遍):普通人自建”运营商级 WiFi Calling”——不行。三重锁死:

  1. eUICC 证书信任链(首道锁,最硬) —— GSMA Root CI1 公钥烧死在 ECASD,私有证书行不通,软件改不了,这是硅片级的死结。
  2. 运营商 IMS 核心网 —— 凭据在 ISIM @ UICC,ePDG / HSS / IBCF / IPX 全部是企业级专有基础设施。
  3. iOS / Android WiFi Calling 入口 —— carrier entitlement + carrier bundle + modem 固件,平台权力决定谁能被点亮。

普通人能做的最远边界:应用层 VoIP over WiFi。它不是 WiFi Calling,不能进运营商拨号盘,不能跨运营商互通 PSTN 出园区,但仍能在 IP 范围内提供良好体验——我手头的 rtpd + phone-android / phone-ios 就是这个边界的一个真实案例。

“那能不能做私有 IMS 网?”——企业可以,个人不行,仍要 GSMA 注册 + 合规审计 + 法人主体。

“那 GSMA SGP.22 ‘999’ 是不是个人通道?”——不是。简化通道仍是企业通道,仍然走 GSMA PKI。

“那把 GSMA Root CI 装到手机系统信任根里能不能绕过?”——不能。iOS / Android 系统信任根管不到 eUICC,ECASD 是独立的 JavaCard 安全元件。

如果你想做”普通人能用的语音通话网络”,我的真实建议:

  • 不要碰 eSIM / SM-DP+ 这一条路,除非你是企业、愿意投百万级 + 半年到一年走 SAS-SM
  • 走应用层 VoIP——IP 网络上能跑通就好,iOS CallKit 让体验接近原生电话,体验上限就在这里
  • 要合法合规:不要碰真实 PSTN 互通,不要碰紧急呼叫责任,不要碰 PLMN 标识

如果你想做”私有 5G/LTE + 私有 IMS”——这是个百万级起步的企业项目,不是个人项目,请按企业路径走。


10. 参考资料


11. 写在最后

我搭 sm-dp 的初衷是”我想搞清楚 eSIM 到底是怎么工作的”。结果搞清楚之后,发现这条路对个人没有商用落点

搞清楚的过程本身有价值。我跑完了协议层,撞上了 eUICC 信任链这堵墙,写下这篇文章,至少能让下一个想”自建 eSIM 运营商”的朋友少走三个月弯路。

对普通开发者来说,应用层 VoIP over IP 仍然是 IP 网络上能做的事情里体验最好的一条路。iOS CallKit 让它看起来像电话,Signal Protocol 让它端到端加密,WebRTC 让浏览器免装 App。它不是运营商级 WiFi Calling,但它真正可用的语音通信。

这是我能给出的最诚实的答案。