eSIM Profile 派發測試專案
January 2, 2026 · View on GitHub
本專案實作了 GSMA RSP (Remote SIM Provisioning) 規範中的 SM-DP+ 伺服器與 LPA 客戶端測試環境。
eSIM Profile 派發流程概述
根據 GSMA SGP.22 規範,eSIM Profile 的遠端派發涉及以下角色:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SM-DP+ │ │ LPA │ │ eUICC │
│ (伺服器) │◄───►│ (客戶端) │◄───►│ (硬體) │
└─────────────┘ └─────────────┘ └─────────────┘
Profile Local Profile 嵌入式
準備與綁定 Assistant SIM 晶片
完整的 ES9+ Profile 下載流程
| 步驟 | API 名稱 | 方向 | 說明 | 本專案狀態 |
|---|---|---|---|---|
| 1 | InitiateAuthentication | LPA → SM-DP+ | 發送 eUICC 資訊,開始認證 | ✅ 已實作 |
| 2 | (eUICC 處理) | LPA ↔ eUICC | eUICC 驗證伺服器簽章,產生回應 | ✅ 軟體模擬 |
| 3 | AuthenticateClient | LPA → SM-DP+ | 發送 eUICC 簽章,完成雙向認證 | ✅ 軟體模擬 |
| 4 | GetBoundProfilePackage | LPA → SM-DP+ | 取得綁定的 Profile 封包 | ✅ 軟體模擬 |
| 5 | (Profile 安裝) | LPA ↔ eUICC | eUICC 解密並安裝 Profile | ✅ 模擬完成 |
| 6 | HandleNotification | LPA → SM-DP+ | 通知伺服器安裝結果 | ⚠️ 部分支援 |
詳細流程說明
步驟 1: InitiateAuthentication ✅
LPA 發送:
├── euiccChallenge (16 位元組隨機數)
├── euiccInfo1 (eUICC 版本與支援的 CI 公鑰 ID)
└── smdpAddress (SM-DP+ 伺服器地址)
SM-DP+ 回應:
├── transactionId (交易識別碼)
├── serverSigned1 (伺服器簽章資料)
├── serverSignature1 (ECDSA 簽章)
├── serverCertificate (伺服器憑證)
└── euiccCiPKIdToBeUsed (選定的 CI 公鑰 ID)
步驟 2: eUICC 處理 ✅ (軟體模擬)
- 軟體 eUICC 驗證 serverSignature1 和 serverCertificate
- 使用測試 PKI 私鑰產生 euiccSigned1
- 準備 prepareDownloadResponse
步驟 3: AuthenticateClient ✅ (軟體模擬)
- LPA 發送 euiccSigned1 給 SM-DP+
- SM-DP+ 驗證 eUICC 身份(憑證鏈驗證通過)
- 伺服器準備 Profile 綁定
步驟 4: GetBoundProfilePackage ✅ (軟體模擬)
- LPA 發送 prepareDownloadResponse
- SM-DP+ 回傳加密的 BoundProfilePackage (約 12KB)
- Profile 使用 eUICC 特定金鑰加密
步驟 5: Profile 安裝 ✅ (模擬)
- 模擬 eUICC 接收 BoundProfilePackage
- 實際安裝需要真實 eUICC 硬體
步驟 6: HandleNotification ⚠️ (部分支援)
- LPA 通知 SM-DP+ 安裝結果
- 伺服器端 session 管理限制,回傳 500 錯誤(非關鍵)
專案架構
smdpp/
├── docker-compose.yml # Docker Compose 設定
├── Dockerfile.smdpp # SM-DP+ 伺服器 Docker 映像
├── Dockerfile.client # Go 客戶端 Docker 映像
├── Dockerfile.asn1helper # ASN.1 Helper 服務映像
├── main.go # Go 客戶端程式碼
├── go.mod # Go 模組設定
├── asn1_helper.py # ASN.1 編碼輔助服務
├── scripts/
│ └── gen_full_pki.sh # PKI 憑證產生腳本
└── README.md # 本文件
元件說明
SM-DP+ 伺服器 (osmo-smdpp)
- 基於 Osmocom pySim 專案
- Python 3.11 實作
- 支援 ES9+ API (GSMA SGP.22)
- 包含測試憑證與 Profile
ASN.1 Helper 服務 (asn1_helper.py)
- Python Flask 服務,監聽 port 9999
- 使用 pySim 的
rsp.asn1模組編碼複雜的 ASN.1 結構 - 動態從 CI 憑證提取 Subject Key Identifier 作為 PKID
- 提供以下端點:
/encode/euiccInfo1- 編碼 eUICC 資訊/encode/euiccSigned1- 編碼 eUICC 簽章資料/encode/authenticateServerResponse- 編碼伺服器認證回應/encode/prepareDownloadResponse- 編碼下載準備回應
Go 客戶端 (main.go)
- 軟體 eUICC 模擬器
- ECDSA P-256 金鑰產生與簽章
- 完整 ES9+ 流程實作
- 支援兩種模式:
- HTTP 測試模式: 不需硬體,完整模擬 ES9+ 流程
- 硬體模式: 需要 QMI/MBIM eUICC 設備
PKI 憑證產生 (gen_full_pki.sh)
- 產生完整的測試 PKI 憑證鏈
- 支援 GSMA Variant O (nameConstraints)
- 產生的憑證:
- CI (Certificate Issuer) 根憑證
- EUM (eUICC Manufacturer) 中間憑證 (含 nameConstraints)
- eUICC 終端憑證
- SM-DP+ DPauth/DPpb 憑證
快速開始
前置作業
首先產生測試 PKI 憑證:
# 產生完整 PKI 憑證鏈
./scripts/gen_full_pki.sh
啟動服務
# 啟動所有服務 (SM-DP+、ASN.1 Helper、Client)
docker compose up
# 只啟動伺服器
docker compose up smdpp asn1-helper
# 重新建置並啟動
docker compose up --build
環境變數
| 變數 | 說明 | 預設值 |
|---|---|---|
| HTTP_TEST_MODE | 1=HTTP 測試模式, 0=硬體模式 | 1 |
| SMDP_HOST | SM-DP+ 伺服器位址 | smdpp:8443 |
| SMDP_ADDRESS | SM-DP+ 邏輯地址 | testsmdpplus1.example.com |
| ASN1_HELPER_URL | ASN.1 Helper 服務位址 | http://asn1-helper:9999 |
測試結果範例
軟體模擬模式下的完整 ES9+ 流程輸出:
=== ES9+ Step 1: InitiateAuthentication ===
Response status: 200
Got transactionId: 0C4820EE324046F9BDE1B2991818228B
Got serverSigned1 (272 bytes)
Got serverCertificate
=== ES9+ Step 3: AuthenticateClient ===
Using software eUICC with EID: 89049032123451234512345678901235
Response status: 200
AuthenticateClient success!
Got smdpSigned2 (100 bytes)
Got smdpSignature2 (71 bytes)
=== ES9+ Step 4: GetBoundProfilePackage ===
Response status: 200
Got BoundProfilePackage (12543 bytes)
✓ Profile package received successfully!
=== ES9+ Step 5: Profile Installation (Simulated) ===
In real hardware mode, the profile would be installed to eUICC
Simulating successful installation...
=== ES9+ Step 6: HandleNotification ===
Sending installation notification...
(Server may return 500 due to session management - non-critical)
=== ES9+ Flow Complete ===
All steps executed successfully!
軟體 eUICC 模擬技術
為什麼可以模擬?
本專案透過以下方式繞過真實 eUICC 硬體需求:
- 自建 PKI 憑證鏈: 產生完整的 CI → EUM → eUICC 憑證鏈
- 軟體金鑰: 使用 ECDSA P-256 軟體金鑰代替硬體安全元件
- ASN.1 編碼服務: 正確編碼 SGP.22 規範定義的複雜 ASN.1 結構
- 符合 GSMA Variant O: EUM 憑證包含 nameConstraints 擴充
關鍵技術細節
憑證鏈驗證
CI (Certificate Issuer)
├── EUM Certificate (with nameConstraints: IIN=89049032)
│ └── eUICC Certificate (EID: 89049032123451234512345678901235)
└── DPauth/DPpb Certificates (SM-DP+ 使用)
EID 格式
- 測試 EID:
89049032123451234512345678901235 - IIN (前 8 碼):
89049032(須符合 EUM 的 nameConstraints) - Luhn 檢查碼: 最後一碼
5
限制說明
雖然可以完成 ES9+ 流程,但有以下限制:
- Profile 無法真正安裝: BoundProfilePackage 使用 eUICC 公鑰加密,軟體私鑰無法解密真正的 Profile 內容
- 僅適用於測試: 需要伺服器端也使用測試憑證
- Step 6 部分問題: osmo-smdpp 的 session 管理導致 HandleNotification 回傳 500
硬體模式
如需完成真正的 Profile 安裝,需要以下硬體之一:
- QMI 介面的 eUICC 模組 (如 Qualcomm 晶片)
- MBIM 介面的 eUICC 模組
- PC/SC 智慧卡讀卡機 + eUICC 卡
# 硬體模式 (需要 /dev/cdc-wdm0 或類似設備)
HTTP_TEST_MODE=0 docker compose up client
相關規範
- GSMA SGP.21 - RSP 架構
- GSMA SGP.22 - RSP 技術規範
- GSMA SGP.02 - eUICC 遠端 Profile 管理
SM-DP+ 伺服器限制
功能限制
本專案的 smdpp.py 是一個 概念驗證實作,以下是主要限制:
| 項目 | 狀態 | 說明 |
|---|---|---|
| ES9+ API | ✅ 完整 | 支援完整 Profile 下載流程 |
| ES2+ API | ❌ 缺少 | 無營運商後台介面 |
| SM-DS 整合 | ❌ 缺少 | 無 Discovery Service 整合 |
| Confirmation Code | ⚠️ 部分 | 未完整實作驗證邏輯 |
| Profile 狀態管理 | ⚠️ 簡化 | 基於檔案/記憶體的 session 儲存 |
| 高可用性 | ❌ 缺少 | 無負載平衡或叢集支援 |
Profile 來源
# Profile 從檔案系統讀取 (簡化實作)
path = os.path.join(self.upp_dir, matchingId) + '.der'
- 需預先準備
.der格式的 Unprotected Profile Package (UPP) - 無動態 Profile 產生功能
- 無與電信商 BSS/OSS 系統整合
憑證限制
# 使用固定的測試主機名稱
HOSTNAME = 'testsmdpplus1.example.com' # 必須與憑證匹配
- 使用自簽測試憑證,非 GSMA 認證的 CI 憑證
- 無法與商業 eUICC 互通
- 僅支援 NIST P-256 和 Brainpool P-256 曲線
適用場景
| 用途 | 適合度 | 說明 |
|---|---|---|
| 開發測試 | ✅ 非常適合 | 測試 LPA 客戶端實作 |
| PoC 驗證 | ✅ 適合 | 驗證 RSP 協議流程 |
| 學習教育 | ✅ 適合 | 理解 SGP.22 規範 |
| 小規模內部部署 | ⚠️ 需額外開發 | 需加入 ES2+ 和狀態管理 |
| 商業營運部署 | ❌ 不適合 | 缺少必要的營運功能 |
若需商業部署
商業級 SM-DP+ 需要額外實作:
- ES2+ 介面 - 與電信商後台系統整合
- SM-DS 整合 - Profile Discovery 服務
- HSM 整合 - 硬體安全模組保護金鑰
- Profile 庫存管理 - 動態 Profile 分配
- 審計日誌 - 合規性記錄
- 高可用架構 - 叢集、負載平衡、災難復原
- GSMA SAS 認證 - 安全認證標準
License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
SM-DP+ HTTP Service
Early proof-of-concept towards a SM-DP+ HTTP service for GSMA consumer eSIM RSP (Remote SIM Provisioning).
GSMA RSP ES 介面總覽
根據 GSMA SGP.21/SGP.22 規範,RSP 架構定義了以下介面:
| 介面 | 連接端點 | 說明 | 本專案實作 |
|---|---|---|---|
| ES1 | SM-DP+ ↔ Operator (BSS) | 營運商業務系統與 SM-DP+ 之間的介面,用於 Profile 訂購、管理 | ❌ |
| ES2+ | SM-DP+ ↔ Operator | Profile 下載訂單管理、狀態通知 | ❌ |
| ES3 | SM-DS ↔ Operator | 事件註冊、刪除(用於 SM-DS 模式) | ❌ |
| ES4 | SM-SR ↔ Operator | M2M 架構中的 SM-SR 介面(Consumer RSP 不使用) | ❌ 不適用 |
| ES5 | SM-SR ↔ eUICC | M2M 架構中的遠端管理介面(Consumer RSP 不使用) | ❌ 不適用 |
| ES6 | SM-DP ↔ SM-SR | M2M 架構中 Profile 傳輸介面(Consumer RSP 不使用) | ❌ 不適用 |
| ES7 | SM-DS ↔ SM-DP+ | SM-DP+ 向 SM-DS 註冊/刪除事件 | ❌ |
| ES8+ | SM-DP+ ↔ eUICC | Profile 下載、安裝的安全通道(透過 LPA 轉發) | ⚠️ 部分 |
| ES9+ | SM-DP+ ↔ LPA | LPA 與 SM-DP+ 之間的 HTTPS 介面 | ✅ 主要實作 |
| ES10a | LPA ↔ eUICC (LDS) | 本地發現服務(Local Discovery Services) | ❌ LPA 端 |
| ES10b | LPA ↔ eUICC (LPD) | 本地 Profile 下載(Local Profile Download) | ❌ LPA 端 |
| ES10c | LPA ↔ eUICC (LUI) | 本地使用者介面(Local User Interface) | ❌ LPA 端 |
| ES11 | LPA ↔ SM-DS | LPA 查詢 SM-DS 取得待處理事件 | ❌ LPA/SM-DS 端 |
| ES12 | SM-DS ↔ SM-DS | Root SM-DS 與 Alternative SM-DS 之間的介面 | ❌ SM-DS 端 |
架構說明
┌─────────────┐ ES2+ ┌──────────┐
│ Operator │◄────────────► │ SM-DP+ │ ◄── 本專案
│ (BSS) │ │ │
└─────────────┘ └────┬─────┘
│ ES9+ (HTTPS)
▼
┌──────────┐
│ LPA │
│ (Device) │
└────┬─────┘
│ ES10a/b/c (Local)
▼
┌──────────┐
│ eUICC │
└──────────┘
本專案實作的 ES9+ 端點
| 端點 | SGP.22 章節 | 說明 |
|---|---|---|
/gsma/rsp2/es9plus/initiateAuthentication | 5.6.1 | 啟動認證流程 |
/gsma/rsp2/es9plus/authenticateClient | 5.6.3 | 客戶端(eUICC)認證 |
/gsma/rsp2/es9plus/getBoundProfilePackage | 5.6.2 | 取得綁定的 Profile 套件 |
/gsma/rsp2/es9plus/handleNotification | 5.6.4 | 處理通知(安裝結果等) |
/gsma/rsp2/es9plus/cancelSession | 5.6.5 | 取消會話 |
為什麼不需要實作所有介面?
- ES4/ES5/ES6 - 這些是 M2M(機器對機器)架構的介面,Consumer RSP 使用不同架構
- ES10a/ES10b/ES10c - 這些是 LPA 與 eUICC 之間的本地介面,由設備端實作
- ES11/ES12 - 這些是 SM-DS 相關介面,本專案僅實作 SM-DP+
- ES1/ES2+/ES3/ES7 - 這些是後端系統整合介面,PoC 階段可簡化
使用方式
# 基本執行
python3 smdpp.py
# 使用 Brainpool 曲線
python3 smdpp.py -b
# 詳細輸出
python3 smdpp.py -v
# 禁用 SSL(開發測試用)
python3 smdpp.py -s
延伸
要讓手機透過掃描 QR Code 新增 eSIM,需要補充以下幾個關鍵服務:
- QR Code 產生服務 - 產生符合 SGP.22 規範的 Activation Code
- ES2+ 介面 - 讓營運商系統可以下載訂單、查詢狀態
- SM-DS 服務(可選) - 如果要支援 SM-DS 模式而非直接 QR Code
- 公開可存取的 HTTPS 端點 - 手機需要能連到 SM-DP+
必要條件總覽
| 項目 | 必要性 | 目前狀態 | 說明 |
|---|---|---|---|
| QR Code 產生服務 | ✅ 必要 | ❌ 缺少 | 產生 Activation Code |
| ES2+ 介面 | ✅ 必要 | ❌ 缺少 | Profile 訂單管理 |
| 公網 HTTPS | ✅ 必要 | ❌ 缺少 | 手機需可存取 |
| 有效 TLS 憑證 | ✅ 必要 | ❌ 測試憑證 | 需 CA 簽發 |
| GSMA CI 憑證 | ✅ 必要 | ❌ 測試憑證 | 需 GSMA 認證(最大障礙) |
| Profile 庫存 | ✅ 必要 | ⚠️ 簡化 | 需真實營運商 Profile |
| SM-DS 整合 | ⚠️ 可選 | ❌ 缺少 | Push 模式需要 |
1. QR Code 產生服務
Activation Code 格式(SGP.22 規範)
LPA:1$<SM-DP+ 地址>$<Matching ID>[$<Confirmation Code Flag>]
範例:
LPA:1$smdp.example.com$K2ABC-XY9HG-L3DEF
| 欄位 | 說明 | 範例 |
|---|---|---|
LPA:1$ | 固定前綴,表示 RSP v2.x | LPA:1$ |
| SM-DP+ Address | SM-DP+ 伺服器 FQDN | smdp.example.com |
| Matching ID | Profile 識別碼(與下載訂單關聯) | K2ABC-XY9HG-L3DEF |
| Confirmation Code Flag(可選) | 是否需要確認碼 | 1 = 需要 |
2. ES2+ 介面
ES2+ 是營運商後台系統與 SM-DP+ 之間的介面,用於管理 Profile 下載訂單。
必要端點
| 端點 | 說明 | 優先級 |
|---|---|---|
DownloadOrder | 建立 Profile 下載訂單 | ✅ 必要 |
ConfirmOrder | 確認訂單(釋放 Profile) | ✅ 必要 |
ReleaseProfile | 釋放 Profile 供下載 | ✅ 必要 |
GetProfileStatus | 查詢 Profile 狀態 | ⚠️ 建議 |
CancelOrder | 取消訂單 | ⚠️ 建議 |
ES2+ 流程
┌──────────┐ ┌──────────┐
│ Operator │ │ SM-DP+ │
│ (BSS) │ │ │
└────┬─────┘ └────┬─────┘
│ 1. DownloadOrder │
│──────────────────────────────►│
│ Response (matchingId) │
│◄──────────────────────────────│
│ 2. ConfirmOrder │
│──────────────────────────────►│
│ 3. 產生 QR Code │
│ LPA:1$smdp.example.com$... │
│◄──────────────────────────────│
3. 公網 HTTPS 與有效憑證
手機的 LPA 必須能透過網際網路連接到 SM-DP+:
- 公網 IP 或域名 - SM-DP+ 需有公開可存取的位址
- 有效 TLS 憑證 - 需由公認 CA 簽發(Let's Encrypt 等)
- 防火牆設定 - 開放 443 port
4. GSMA 認證 CI 憑證(最大障礙)
這是最大的障礙。真實手機的 eUICC 只信任 GSMA 認證的 CI(Certificate Issuer)簽發的憑證鏈:
GSMA Root CI (手機 eUICC 預載)
└── SM-DP+ Certificate (需 GSMA 認證)
| 情況 | 可行性 | 說明 |
|---|---|---|
| 測試憑證 + 真實手機 | ❌ 不可行 | 手機 eUICC 不信任自簽憑證 |
| 測試憑證 + 軟體 eUICC | ✅ 可行 | 本專案目前做法 |
| GSMA 憑證 + 真實手機 | ✅ 可行 | 需通過 SAS 認證 |
取得 GSMA 認證的途徑
- 成為 GSMA 會員 - 加入 GSMA 組織
- 通過 SAS 認證 - Security Accreditation Scheme(3-12 個月)
- 或與現有 SM-DP+ 供應商合作 - 如 IDEMIA、Thales、G+D 等
實作優先順序建議
| 階段 | 工作項目 | 時間估計 |
|---|---|---|
| 1 | 公網部署 + TLS 憑證 | 1-2 天 |
| 2 | ES2+ 介面實作 | 2-4 週 |
| 3 | QR Code 產生服務 | 1 週 |
| 4 | GSMA 認證 | 3-12 個月 ⚠️ |
總結
技術實作(QR Code、ES2+)相對簡單,真正的障礙是取得 GSMA 認證的 CI 憑證。
對於非 GSMA 會員,建議:
- 與現有 SM-DP+ 供應商合作(如 IDEMIA、Thales、G+D、Oasis Smart SIM)
- 而非自建完整 SM-DP+ 服務
參考規範
- SGP.21 - RSP Architecture
- SGP.22 - RSP Technical Specification
- SGP.26 - RSP Test Specification
License
GNU Affero General Public License v3.0 (AGPL-3.0)