从已签名 App 恢复被删除的 iOS 开发证书
从已签名 App 恢复被删除的 iOS 开发证书
适用场景:本机钥匙串中的 Apple Development 证书被误删(security delete-certificate),
但私钥仍然存在,且本机/项目里留有用该证书签名过的产物(.app/.ipa)。
本文从这些签名产物中把证书提取回来,与保留的私钥配对,完整恢复签名身份。
原理:为什么能恢复
iOS 代码签名身份(codesign identity)= 证书(public key 载体)+ 私钥,两者缺一不可:
签名身份 = 证书(.cer,含公钥)+ 私钥(本机钥匙串)- 已签名的 App 中嵌入了签名时的证书链(叶子证书 + 中间证书 + 根证书),
codesign --extract-certificates可将其提取为 DER 格式的证书文件; security delete-certificate只删除证书,默认不删除私钥(除非加-t选项)。
私钥删除后会保留为"孤儿私钥",只是命令行工具(find-key/dump-keychain)
受 ACL 保护往往枚举不到,但 Keychain Access 图形界面可见;- 因此:补回证书文件 → 导入钥匙串 → 自动与保留的私钥配对 → 签名身份完整复原。
为什么不用开发者中心下载:免费个人团队(Personal Team)账号在developer.apple.com没有 "Certificates, IDs & Profiles" 页面(该页面仅付费
开发者计划可访问);Xcode 也不会"打开就自动下载"服务器证书(只在签名构建时按需
创建)。从签名产物提取是免费账号唯一能"原样复原"的途径。
前置条件
- [x] 被删证书曾在某次签名中使用过(产物
.app/.ipa的签名内嵌着它) - [x] 私钥仍在钥匙串(用下方 Step 1 确认;通常满足——删证书不删私钥)
- [x] macOS + Xcode 命令行工具(
xcrun/codesign/security/openssl)
详细步骤
Step 1 · 确认私钥仍在(关键前提)
图形界面最可靠:
- 打开 钥匙串访问(Keychain Access)
- 左侧选择 登录 钥匙串
- 右上搜索被删证书的名称(如
Apple Development) - 若能看到黄色钥匙图标(没有证书配对的私钥)→ 私钥在,可以继续
命令行佐证(注意:受 ACL 保护的私钥可能枚举不到,"搜不到"不代表私钥丢了):
security find-identity -v -p codesigning # 看当前签名身份(应为 0)
security dump-keychain ~/Library/Keychains/login.keychain-db 2>/dev/null | grep -c "class: 0x00000040" # 私钥类条目,仅供佐证Step 2 · 找到用该证书签过名的产物
在项目/本机搜索所有 .app / .ipa:
find . -name "*.app" -type d 2>/dev/null | grep -v ".dSYM"
find . -name "*.ipa" 2>/dev/null逐一查看签名证书,确认哪几个产物用的是被删证书:
codesign -dv --verbose=4 <path/to/xxx.app> 2>&1 | grep -E "^Authority="预期输出(Authority= 行即签名证书链,第一行是叶子证书):
Identifier=com.example.app
Authority=Apple Development: [email protected] (TEAMID12345) ← 被删的证书
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA提示:同一任务可能产生多个签名产物(如命令行部署脚本重签的产物、IDE 自动签名
构建的产物等),每个产物都嵌着签名时用的那张证书——多张证书可能分散在不同
产物里,都值得检查一遍。
Step 3 · 提取签名证书链
进入 .app 目录,对可执行文件(或 .app 目录)执行:
cd <path/to/xxx.app>
codesign -d --extract-certificates ./<可执行文件名>可执行文件名即 App 主二进制(不确定就ls找非资源文件的可执行文件)。
亦可直接对.app目录提取,不同 macOS 版本输出路径略有差异,以实际生成为准。
在当前目录生成三个 DER 编码证书(没有扩展名,属正常):
codesign0 ← 叶子证书(签名证书本体,最关键的)
codesign1 ← 中间证书(Apple WWDR)
codesign2 ← 根证书(Apple Root CA,系统一般已有)Step 4 · 确认提取的证书就是要恢复的那张
openssl x509 -inform der -in codesign0 -noout -subject -fingerprint -sha1与 Step 2 中 Authority 行的 CN 比对;sha1 Fingerprint 应与被删证书的 SHA-1 一致
(可用 security find-certificate -Z 的历史记录回想确认)。
Step 5 · 导入钥匙串
security add-certificates codesign0 # 叶子证书:必须
security add-certificates codesign1 # 中间证书:若提示"already in default keychain"即系统已有,无碍默认导入 登录钥匙串(与被删证书原位置一致)。
Step 6 · 验证身份恢复
security find-identity -v -p codesigning恢复成功时应出现:
1) <SHA1> "Apple Development: [email protected] (TEAMID12345)"
1 valid identities found显示 valid identities = 证书已与保留的私钥配对成功,可正常签名部署。
多张证书的恢复
一个签名产物只嵌一张叶子证书(签名时选的那张)。若误删多张,需为每张找到
各自的签名产物,重复 Step 2~6。常见的“多张证书分散来源”:
- 部署脚本重签的产物(通常自动选用钥匙串里第一张可用证书)
- IDE 自动签名构建的产物(可能选用另一张证书)
逐一提取导入后,find-identity 会恢复出与删除前一致的签名身份列表。
限制:只能恢复找到签名来源的证书;删除前过多张、但只部分签过名的,
其余证书无法从签名产物复原(只能走 Xcode 重建流程)。
注意事项
- 有效期不变:提取导入的证书仍是当初签发的那张,受原有效期限制
(免费开发者证书常为 1 年,过期需走 Xcode 重建流程)。 codesign0/1/2是临时文件,保留在.app目录内无害;如需清爽可删除。- 私钥仍是安全核心:恢复只补了证书,私钥从未导出;切勿把私钥文件外发。
- 命令行枚举不到私钥 ≠ 私钥丢失:以 Keychain Access 图形界面为准。
- 若私钥也不在(删除时用了
-t,或证书来自其他机器且未迁移私钥),
本方法无效,只能让 Xcode 在签名构建时重新生成证书(免费账号标准流程)。
与其它恢复途径对比
| 途径 | 免费账号可用 | 是否"原样复原" | 备注 |
|---|---|---|---|
开发者中心下载 .cer | ❌(需付费计划) | ✅ | developer.apple.com/account 无证书页 |
| Xcode 自动恢复 | ✅ | ❌(重建=新证书新私钥) | 登录账号后触发一次签名构建即可,但非原证书 |
| 从已签名产物提取(本文) | ✅ | ✅ | 证书原样复原,且与保留私钥配对 |