mcpField
A
axiom-code-signing-ref

axiom-code-signing-ref

github.com/charleswiltgen开发1.2k56 次安装今天更新
代码仓库

关于 axiom-code-signing-ref

面向 iOS/macOS 开发者的代码签名命令与 API 参考资料,汇集证书、描述文件、权限、Keychain、fastlane match 和 Xcode 构建设置的操作说明。

主要功能

  1. 01查询证书类型与操作命令
  2. 02检查描述文件内容
  3. 03提取并比较权限
  4. 04参考 Xcode 签名设置
  5. 05查看 fastlane match 与 CI 示例

适用场景

  1. 01查找签名诊断命令
  2. 02设置 CI 临时 Keychain
  3. 03配置 fastlane match
  4. 04核对 Xcode 导出设置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-code-signing-ref

安装后在 Claude Code 中输入/axiom-code-signing-ref确认已加载。

详细介绍

代码签名 API 参考

iOS/macOS 代码签名 CLI 和 API 的完整参考:证书管理、预置描述文件检查、权利提取、钥匙串操作、codesign 验证、fastlane match 和 Xcode 构建设置。

快速参考

# Diagnostic flow — run these 3 commands first for any signing issue
security find-identity -v -p codesigning          # List valid signing identities
security cms -D -i path/to/embedded.mobileprovision  # Decode provisioning profile
codesign -d --entitlements - MyApp.app             # Extract entitlements from binary

证书参考

证书类型
类型用途有效期每个账户的上限
Apple Development在已注册设备上调试构建1 年不限(每位开发者)
Apple Distribution提交至 App Store 和 TestFlight1 年每个账户 3 个
iOS Distribution(旧版)提交至 App Store(Xcode 11 之前)1 年每个账户 3 个
iOS Development(旧版)调试构建(Xcode 11 之前)1 年不限
Developer ID Application在 App Store 之外分发 macOS 应用5 年每个账户 5 个
Developer ID Installer为 macOS 软件包签名5 年每个账户 5 个
Apple Push ServicesAPNs .p12 证书身份验证(旧版)1 年每个 App ID 1 个
CSR 生成
# Generate Certificate Signing Request
openssl req -new -newkey rsa:2048 -nodes \
  -keyout CertificateSigningRequest.key \
  -out CertificateSigningRequest.certSigningRequest \
  -subj "/[email protected]/CN=Developer Name/C=US"

或者使用钥匙串访问:证书助理 → 从证书颁发机构请求证书。

证书检查
# View certificate details (from .cer file)
openssl x509 -in certificate.cer -inform DER -text -noout

# View certificate from .p12
openssl pkcs12 -in certificate.p12 -nokeys -clcerts | openssl x509 -text -noout

# List certificates in Keychain with SHA-1 hashes
security find-identity -v -p codesigning

# Example output:
#   1) ABC123... "Apple Development: [email protected] (TEAMID)"
#   2) DEF456... "Apple Distribution: Company Name (TEAMID)"
#      2 valid identities found

# Find specific certificate by name
security find-certificate -c "Apple Distribution" login.keychain-db -p

# Check certificate expiration (pipe PEM output to openssl)
security find-certificate -c "Apple Distribution" login.keychain-db -p | openssl x509 -noout -enddate
证书安装
# Import .p12 into Keychain (interactive — prompts for password)
security import certificate.p12 -k ~/Library/Keychains/login.keychain-db -P "$P12_PASSWORD" -T /usr/bin/codesign

# Import .cer into Keychain
security import certificate.cer -k ~/Library/Keychains/login.keychain-db

# For CI: import into temporary keychain (see CI section below)

预置描述文件参考

描述文件类型
类型包含内容使用场景
Development开发证书 + 设备 UDID + App ID + 权利在已注册设备上调试构建
Ad Hoc分发证书 + 设备 UDID + App ID + 权利无需 TestFlight,在指定设备上测试
App Store分发证书 + App ID + 权利(无设备列表)提交至 App Store 和 TestFlight
Enterprise企业证书 + App ID + 权利(无设备列表)内部分发(仅限企业计划)
描述文件内容

预置描述文件(.mobileprovision)是一个经过签名的 plist,包含:

├── AppIDName           — App ID name
├── ApplicationIdentifierPrefix  — Team ID
├── CreationDate        — When profile was created
├── DeveloperCertificates  — Embedded signing certificates (DER-encoded)
├── Entitlements        — Granted entitlements
│   ├── application-identifier
│   ├── aps-environment (development|production)
│   ├── com.apple.developer.associated-domains
│   ├── keychain-access-groups
│   └── ...
├── ExpirationDate      — When profile expires (1 year)
├── Name                — Profile name in Apple Developer Portal
├── ProvisionedDevices  — UDIDs (Development/Ad Hoc only)
├── TeamIdentifier      — Team ID array
├── TeamName            — Team display name
├── TimeToLive          — Days until expiration
├── UUID                — Unique profile identifier
└── Version             — Profile version (1)
解码预置描述文件
# Decode and display full contents
security cms -D -i path/to/embedded.mobileprovision

# Extract specific fields
security cms -D -i embedded.mobileprovision | plutil -extract Entitlements xml1 -o - -

# Check aps-environment (push notifications)
security cms -D -i embedded.mobileprovision | grep -A1 "aps-environment"

# Check expiration
security cms -D -i embedded.mobileprovision | grep -A1 "ExpirationDate"

# List provisioned devices (Development/Ad Hoc only)
security cms -D -i embedded.mobileprovision | grep -A100 "ProvisionedDevices"

# Check team ID
security cms -D -i embedded.mobileprovision | grep -A1 "TeamIdentifier"
描述文件安装路径
# Installed profiles (Xcode manages these)
~/Library/MobileDevice/Provisioning Profiles/

# List installed profiles
ls ~/Library/MobileDevice/Provisioning\ Profiles/

# Decode a specific installed profile
security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/<UUID>.mobileprovision

# Find profile embedded in app bundle
find ~/Library/Developer/Xcode/DerivedData -name "embedded.mobileprovision" -newer . 2>/dev/null | head -5

# Install a profile manually (copy to managed directory)
cp MyProfile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/

权利参考

常见权利
权利键值
App IDapplication-identifierTEAMID.com.example.app
推送通知aps-environmentdevelopment / production
App 组com.apple.security.application-groups["group.com.example.shared"]
钥匙串共享keychain-access-groups["TEAMID.com.example.keychain"]
关联域com.apple.developer.associated-domains["applinks:example.com"]
iCloudcom.apple.developer.icloud-container-identifiers容器 ID
HealthKitcom.apple.developer.healthkittrue
Apple Paycom.apple.developer.in-app-payments商户 ID
网络扩展com.apple.developer.networking.networkextension类型数组
Siricom.apple.developer.siritrue
使用 Apple 登录com.apple.developer.applesignin["Default"]
权利 .plist 格式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>aps-environment</key>
    <string>development</string>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.shared</string>
    </array>
    <key>com.apple.developer.associated-domains</key>
    <array>
        <string>applinks:example.com</string>
    </array>
</dict>
</plist>
提取与比较
# Extract entitlements from signed app binary
codesign -d --entitlements - /path/to/MyApp.app

# Extract to file for comparison
codesign -d --entitlements entitlements.plist /path/to/MyApp.app

# Compare entitlements between app and provisioning profile
diff <(codesign -d --entitlements - MyApp.app 2>/dev/null) \
     <(security cms -D -i embedded.mobileprovision | plutil -extract Entitlements xml1 -o - -)

# Extract entitlements from .ipa
unzip -o MyApp.ipa -d /tmp/ipa_contents
codesign -d --entitlements - /tmp/ipa_contents/Payload/*.app

# Verify entitlements match between build and profile
codesign -d --entitlements - --xml MyApp.app  # XML format

CLI 命令参考

security 命令
# --- Identity & Certificate ---

# List valid code signing identities
security find-identity -v -p codesigning
# -v: valid only, -p codesigning: code signing policy

# Find certificate by common name
security find-certificate -c "Apple Distribution" login.keychain-db -p
# -c: common name substring, -p: output PEM, keychain is positional arg

# Find certificate by SHA-1 hash
security find-certificate -Z -a login.keychain-db | grep -B5 "ABC123"

# --- Import/Export ---

# Import .p12 (with password, allow codesign access)
security import certificate.p12 -k login.keychain-db -P "$PASSWORD" -T /usr/bin/codesign -T /usr/bin/security

# Import .cer
security import certificate.cer -k login.keychain-db

# Export certificate to .p12
security export -t identities -f pkcs12 -k login.keychain-db -P "$PASSWORD" -o exported.p12

# --- Provisioning Profile Decode ---

# Decode provisioning profile (CMS/PKCS7 signed plist)
security cms -D -i embedded.mobileprovision

# --- Keychain Management ---

# Create temporary keychain (for CI)
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain

# Set as default keychain
security default-keychain -s build.keychain

# Add to search list (required for codesign to find certs)
security list-keychains -d user -s build.keychain login.keychain-db

# Unlock keychain (required in CI before signing)
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain

# Set keychain lock timeout (0 = never lock during session)
security set-keychain-settings -t 3600 -l build.keychain
# -t: timeout in seconds, -l: lock on sleep

# Allow codesign to access keys without UI prompt (critical for CI)
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" build.keychain

# Delete keychain (CI cleanup)
security delete-keychain build.keychain
codesign 命令
# --- Signing ---

# Sign with specific identity
codesign -s "Apple Distribution: Company Name (TEAMID)" MyApp.app
# -s: signing identity (name or SHA-1 hash)

# Sign with entitlements file
codesign -s "Apple Distribution" --entitlements entitlements.plist MyApp.app

# Force re-sign (overwrite existing signature)
codesign -f -s "Apple Distribution" MyApp.app

# Sign with timestamp (required for notarization)
codesign -s "Developer ID Application" --timestamp MyApp.app

# Deep sign (sign all nested code — frameworks, extensions)
codesign --deep -s "Apple Distribution" MyApp.app
# Warning: --deep is unreliable for complex apps. Sign each component individually.

# --- Verification ---

# Verify signature is valid
codesign --verify --verbose=4 MyApp.app

# Verify deep (check nested code)
codesign --verify --deep --strict MyApp.app

# Display signing information
codesign -dv MyApp.app
# Shows: Identifier, Format, TeamIdentifier, Signing Authority chain

# Display verbose signing info
codesign -dvvv MyApp.app

# Extract entitlements from signed binary
codesign -d --entitlements - MyApp.app
codesign -d --entitlements - --xml MyApp.app  # XML format
openssl 命令

注意:macOS 自带的是 LibreSSL,而不是 OpenSSL。在原版 macOS 上,某些 openssl pkcs12 命令可能会因“MAC verification failed”而失败。如有需要,请通过 brew install openssl 安装 OpenSSL,然后使用完整路径(/opt/homebrew/opt/openssl/bin/openssl)。

# --- Certificate Inspection ---

# View .cer details
openssl x509 -in certificate.cer -inform DER -text -noout

# View .pem details
openssl x509 -in certificate.pem -text -noout

# Check certificate expiration
openssl x509 -in certificate.cer -inform DER -noout -enddate

# Extract public key
openssl x509 -in certificate.cer -inform DER -pubkey -noout

# --- PKCS12 (.p12) ---

# Extract certificate from .p12
openssl pkcs12 -in certificate.p12 -nokeys -clcerts -out cert.pem

# Extract private key from .p12
openssl pkcs12 -in certificate.p12 -nocerts -nodes -out key.pem

# Create .p12 from cert + key
openssl pkcs12 -export -in cert.pem -inkey key.pem -out certificate.p12

# Verify .p12 contents
openssl pkcs12 -info -in certificate.p12 -nokeys

Xcode 构建设置参考

设置键值
代码签名样式CODE_SIGN_STYLEAutomatic / Manual
签名身份CODE_SIGN_IDENTITYApple Development / Apple Distribution / iPhone Distribution
开发团队DEVELOPMENT_TEAM团队 ID(10 位字母数字)
配置描述文件PROVISIONING_PROFILE_SPECIFIER描述文件名称或 UUID
配置描述文件(旧版)PROVISIONING_PROFILE描述文件 UUID(已弃用,请使用 SPECIFIER)
其他代码签名标志OTHER_CODE_SIGN_FLAGS--timestamp / --options runtime
代码签名权利CODE_SIGN_ENTITLEMENTS.entitlements 文件的路径
启用强化运行时ENABLE_HARDENED_RUNTIMEYES / NO(macOS)
xcodebuild 签名覆盖项
# Automatic signing
xcodebuild -scheme MyApp -configuration Release \
  CODE_SIGN_STYLE=Automatic \
  DEVELOPMENT_TEAM=YOURTEAMID

# Manual signing
xcodebuild -scheme MyApp -configuration Release \
  CODE_SIGN_STYLE=Manual \
  CODE_SIGN_IDENTITY="Apple Distribution: Company Name (TEAMID)" \
  PROVISIONING_PROFILE_SPECIFIER="MyApp App Store Profile"

# Archive for distribution
xcodebuild archive -scheme MyApp \
  -archivePath build/MyApp.xcarchive \
  CODE_SIGN_STYLE=Manual \
  CODE_SIGN_IDENTITY="Apple Distribution" \
  PROVISIONING_PROFILE_SPECIFIER="MyApp App Store"

# Export .ipa from archive
xcodebuild -exportArchive \
  -archivePath build/MyApp.xcarchive \
  -exportOptionsPlist ExportOptions.plist \
  -exportPath build/ipa
ExportOptions.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>app-store</string>
    <key>teamID</key>
    <string>YOURTEAMID</string>
    <key>signingStyle</key>
    <string>manual</string>
    <key>signingCertificate</key>
    <string>Apple Distribution</string>
    <key>provisioningProfiles</key>
    <dict>
        <key>com.example.myapp</key>
        <string>MyApp App Store Profile</string>
    </dict>
    <key>uploadSymbols</key>
    <true/>
</dict>
</plist>

导出方法的值:app-store、ad-hoc、enterprise、development、developer-id。


fastlane match 参考

设置
# Initialize match (interactive — choose storage type)
fastlane match init
# Options: git, google_cloud, s3, azure_blob

# Generate certificates + profiles for all types
fastlane match development
fastlane match appstore
fastlane match adhoc
Matchfile
# fastlane/Matchfile
git_url("https://github.com/your-org/certificates.git")
storage_mode("git")

type("appstore")  # Default type

app_identifier(["com.example.app", "com.example.app.widget"])
username("[email protected]")
team_id("YOURTEAMID")

# For multiple targets with different profiles
# for_lane(:beta) do
#   type("adhoc")
# end
用法
# Generate or fetch development certs + profiles
fastlane match development

# Generate or fetch App Store certs + profiles
fastlane match appstore

# CI: read-only mode (never create, only fetch)
fastlane match appstore --readonly

# Force regenerate (revokes existing)
fastlane match nuke distribution  # Revoke all distribution certs
fastlane match appstore           # Generate fresh
# Also: nuke development, nuke enterprise
CI 环境变量
MATCH_GIT_URL="https://github.com/your-org/certificates.git"
MATCH_PASSWORD="encryption_password"       # Encrypts the repo
MATCH_KEYCHAIN_NAME="fastlane_tmp"
MATCH_KEYCHAIN_PASSWORD="keychain_password"
MATCH_READONLY="true"                      # CI should never create certs
FASTLANE_USER="[email protected]"
FASTLANE_TEAM_ID="YOURTEAMID"
CI Fastfile 示例
# fastlane/Fastfile
lane :release do
  setup_ci  # Creates temporary keychain

  match(
    type: "appstore",
    readonly: true,  # Critical: never create certs in CI
    keychain_name: "fastlane_tmp",
    keychain_password: ""
  )

  build_app(
    scheme: "MyApp",
    export_method: "app-store"
  )

  upload_to_app_store(skip_metadata: true, skip_screenshots: true)
end

CI 的钥匙串管理

完整的 CI 钥匙串设置脚本
#!/bin/bash
set -euo pipefail

KEYCHAIN_NAME="ci-build.keychain-db"
KEYCHAIN_PASSWORD="ci-temporary-password"

# 1. Create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"

# 2. Add to search list (MUST include login.keychain-db or it disappears)
security list-keychains -d user -s "$KEYCHAIN_NAME" login.keychain-db

# 3. Unlock keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"

# 4. Prevent keychain from locking during build
security set-keychain-settings -t 3600 -l "$KEYCHAIN_NAME"

# 5. Import signing certificate
security import "$P12_PATH" -k "$KEYCHAIN_NAME" -P "$P12_PASSWORD" \
  -T /usr/bin/codesign -T /usr/bin/security

# 6. Allow codesign access without UI prompt (CRITICAL)
# Without this, CI gets errSecInternalComponent
security set-key-partition-list -S apple-tool:,apple: -s \
  -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"

echo "Keychain ready for code signing"
CI 钥匙串清理脚本
#!/bin/bash
# Run in CI post-build (always, even on failure)

KEYCHAIN_NAME="ci-build.keychain-db"

# Delete temporary keychain
security delete-keychain "$KEYCHAIN_NAME" 2>/dev/null || true

# Restore default keychain search list
security list-keychains -d user -s login.keychain-db
GitHub Actions 示例
- name: Install signing certificate
  env:
    P12_BASE64: ${{ secrets.P12_BASE64 }}
    P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
    KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
    PROVISION_PROFILE_BASE64: ${{ secrets.PROVISION_PROFILE_BASE64 }}
  run: |
    # Decode certificate
    echo "$P12_BASE64" | base64 --decode > certificate.p12

    # Decode provisioning profile
    echo "$PROVISION_PROFILE_BASE64" | base64 --decode > profile.mobileprovision

    # Create and configure keychain
    security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
    security list-keychains -d user -s build.keychain login.keychain-db
    security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
    security set-keychain-settings -t 3600 -l build.keychain
    security import certificate.p12 -k build.keychain -P "$P12_PASSWORD" \
      -T /usr/bin/codesign -T /usr/bin/security
    security set-key-partition-list -S apple-tool:,apple: -s \
      -k "$KEYCHAIN_PASSWORD" build.keychain

    # Install provisioning profile
    mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
    cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/

- name: Cleanup keychain
  if: always()
  run: security delete-keychain build.keychain 2>/dev/null || true
Xcode Cloud

Xcode Cloud 会自动管理签名:

  • 证书由 Apple 管理,无需手动管理证书
  • 配置描述文件会从 Developer Portal 获取
  • 在 Xcode → 云端工作流设置中配置签名
  • 如有需要,可使用 ci_post_clone.sh 执行自定义钥匙串操作

APNs 身份验证:.p8 与 .p12

方面.p8(基于令牌).p12(基于证书)
有效期永不过期(撤销后失效)1 年(必须每年续期)
适用范围团队中的所有 App单个 App ID
每个团队的上限2 个密钥每个 App ID 1 个证书
设置复杂度较低(一个密钥适用于所有 App)较高(每个 App 使用一个证书)
服务端实现需要生成 JWT 令牌TLS 客户端证书
推荐是(Apple 当前的建议)旧版(仍受支持)
.p8 密钥用法
# Generate JWT for APNs (simplified — use a library in production)
# Header: {"alg": "ES256", "kid": "KEY_ID"}
# Payload: {"iss": "TEAM_ID", "iat": TIMESTAMP}
# Sign with .p8 private key

# JWT is valid for 1 hour — cache and refresh before expiry
.p12 证书用法
# Send push with certificate authentication
curl -v \
  --cert-type P12 --cert apns-cert.p12:password \
  --header "apns-topic: com.example.app" \
  --header "apns-push-type: alert" \
  --data '{"aps":{"alert":"Hello"}}' \
  --http2 https://api.sandbox.push.apple.com/3/device/$TOKEN
# Production: https://api.push.apple.com/3/device/$TOKEN

错误代码参考

security 命令错误
错误代码原因
errSecInternalComponent-2070钥匙串已锁定,或未调用 set-key-partition-list
errSecItemNotFound-25300在搜索的钥匙串中找不到证书/密钥
errSecDuplicateItem-25299钥匙串中已存在证书
errSecAuthFailed-25293钥匙串密码错误
errSecInteractionNotAllowed-25308钥匙串已锁定,且无法使用 UI(CI 中未解锁)
errSecMissingEntitlement-34018App 缺少访问钥匙串所需的权利
codesign 错误
错误原因修复方法
No signing certificate found钥匙串中没有有效身份导入证书或检查是否过期
ambiguous (matches ...)存在多个匹配的身份指定完整身份名称或 SHA-1 哈希
not valid for use in ...证书类型不匹配(开发版与分发版)使用正确的证书类型
a sealed resource is missing or invalid签名后资源被修改所有修改完成后重新签名
invalid signature (code or signature have been modified)签名后二进制文件遭到篡改重新签名或重新构建
ITMS(App Store 上传)错误
代码错误原因解决方法
ITMS-90035签名无效证书类型错误或证书已过期使用有效的 Apple Distribution 证书签名
ITMS-90161配置描述文件无效配置描述文件与应用不匹配在 Developer Portal 中重新生成配置描述文件
ITMS-90046代码签名 Entitlements 无效Entitlements 不在配置描述文件中在门户中添加功能,然后重新生成配置描述文件
ITMS-90056缺少推送通知 Entitlement配置描述文件中没有 aps-environment启用推送通知功能
ITMS-90174缺少配置描述文件未嵌入配置描述文件使用正确的签名设置进行归档
ITMS-90283配置描述文件无效配置描述文件已过期下载新的配置描述文件
ITMS-90426Swift 支持无效Swift 库未正确签名使用 Xcode 的管理器导出(不要手动导出)
ITMS-90474缺少 Bundle IdentifierBundle ID 与配置描述文件不匹配确保 Xcode、门户和配置描述文件中的 Bundle ID 一致
ITMS-90478Team ID 无效Team ID 不匹配检查 DEVELOPMENT_TEAM 构建设置
ITMS-90717App Store 分发证书无效使用开发证书提交到 App Store切换为 Apple Distribution 证书

资源

WWDC:2021-10204、2022-110353

文档:/security、/bundleresources/entitlements、/xcode/distributing-your-app

技能:axiom-code-signing、axiom-code-signing-diag

评论

支持 Markdown