mcpField
A
axiom-keychain-ref

axiom-keychain-ref

github.com/charleswiltgenセキュリティ1.2k36 回インストール今日更新
リポジトリ

axiom-keychain-ref について

iOS と macOS の Keychain Services を使う開発者向け API リファレンスです。SecItem 操作、項目属性、一意性ルール、アクセシビリティ、戻り値をまとめ、正確なクエリや保存処理を支援します。

主な機能

  1. 01SecItem CRUD 関数の動作
  2. 02Keychain 項目クラスと属性
  3. 03項目クラス別の一意性ルール
  4. 04検索・戻り値プロパティの一覧
  5. 05アクセシビリティとアクセス制御

活用シーン

  1. 01Keychain の追加・検索・更新・削除クエリ作成
  2. 02一意性ルールによる重複項目エラーの診断
  3. 03戻り値の型とアクセシビリティの選択

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/axiom-keychain-refを入力して読み込まれたか確認します。

詳細

Keychain Services API リファレンス

iOS/macOS Keychain Services の包括的な API リファレンスです。SecItem の CRUD 関数、アイテムクラスの属性、一意性の制約、アクセシビリティレベル、アクセス制御フラグ、生体認証との統合、エラーコードを網羅しています。

クイックリファレンス

// Add a generic password
let addQuery: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.app",
    kSecAttrAccount as String: "[email protected]",
    kSecValueData as String: "secret".data(using: .utf8)!
]
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)

// Read a generic password
let readQuery: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.app",
    kSecAttrAccount as String: "[email protected]",
    kSecReturnData as String: true,
    kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let readStatus = SecItemCopyMatching(readQuery as CFDictionary, &result)
let data = result as? Data

// Update a generic password
let updateQuery: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.app",
    kSecAttrAccount as String: "[email protected]"
]
let updateAttributes: [String: Any] = [
    kSecValueData as String: "newSecret".data(using: .utf8)!
]
let updateStatus = SecItemUpdate(updateQuery as CFDictionary, updateAttributes as CFDictionary)

// Delete a generic password
let deleteQuery: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.app",
    kSecAttrAccount as String: "[email protected]"
]
let deleteStatus = SecItemDelete(deleteQuery as CFDictionary)

SecItem 関数

SecItemAdd
func SecItemAdd(_ attributes: CFDictionary, _ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus

attributes 辞書で受け付けるもの:アイテムクラス + アイテム属性 + 値プロパティ + 戻り値の型プロパティ。

検索プロパティ(kSecMatch*)は受け付けません。追加クエリで kSecMatchLimit を指定するとエラーになります。

result:追加したアイテムを受け取る必要がない場合は nil を渡します。kSecReturn* キーで指定した形式のアイテムを受け取るには、ポインターを渡します。ほとんどの場合は nil を渡してください。結果の取得を要求すると、追加の読み取りが発生します。

SecItemCopyMatching
func SecItemCopyMatching(_ query: CFDictionary, _ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus

query 辞書で受け付けるもの:アイテムクラス + アイテム属性 + 検索プロパティ + 戻り値の型プロパティ。

値プロパティ(kSecValueData)は検索条件として受け付けません。

result:型は、設定されている kSecReturn* キーによって異なります。

  • kSecReturnData のみ → CFData
  • kSecReturnAttributes のみ → CFDictionary
  • kSecReturnRef のみ → SecKey / SecCertificate / SecIdentity
  • kSecReturnPersistentRef のみ → CFData(永続参照)
  • 複数の kSecReturn* キー → 要求された型を含む CFDictionary
  • kSecMatchLimit = kSecMatchLimitAll → 上記の型を含む CFArray
SecItemUpdate
func SecItemUpdate(_ query: CFDictionary, _ attributesToUpdate: CFDictionary) -> OSStatus

query 辞書で受け付けるもの:アイテムクラス + アイテム属性 + 検索プロパティ。更新するアイテムの検索に使用します。

attributesToUpdate 辞書で受け付けるもの:アイテム属性 + 値プロパティ。これらは一致したアイテムに適用されます。アイテムクラスや検索プロパティは受け付けません。

kSecValueData を更新すると、保存されているシークレットが置き換えられます。属性(例:kSecAttrLabel)を更新すると、シークレットには触れずにメタデータが変更されます。

SecItemDelete
func SecItemDelete(_ query: CFDictionary) -> OSStatus

query 辞書で受け付けるもの:アイテムクラス + アイテム属性 + 検索プロパティ。

macOS では、デフォルトで一致するアイテムをすべて削除します(暗黙的な kSecMatchLimitAll)。iOS でも、一致するアイテムをすべて削除します。確認は行われず、削除は即座に実行されます。


アイテムクラス

kSecClassGenericPassword

汎用のシークレットストレージです。最もよく使用されるクラスです。

属性キー型
サービスkSecAttrServiceCFString
アカウントkSecAttrAccountCFString
アクセスグループkSecAttrAccessGroupCFString
アクセス可能性kSecAttrAccessibleCFString(定数)
同期可能kSecAttrSynchronizableCFBoolean
ラベルkSecAttrLabelCFString
説明kSecAttrDescriptionCFString
コメントkSecAttrCommentCFString
汎用kSecAttrGenericCFData
作成者kSecAttrCreatorCFNumber(FourCharCode)
タイプkSecAttrTypeCFNumber(FourCharCode)
作成日kSecAttrCreationDateCFDate(読み取り専用)
変更日kSecAttrModificationDateCFDate(読み取り専用)
kSecClassInternetPassword

URL に関連付けられた認証情報です。必要になることはまれで、ほとんどのアプリでは汎用パスワードを使用します。

属性キー型
サーバーkSecAttrServerCFString
プロトコルkSecAttrProtocolCFString(定数)
ポートkSecAttrPortCFNumber
パスkSecAttrPathCFString
アカウントkSecAttrAccountCFString
認証タイプkSecAttrAuthenticationTypeCFString(定数)
セキュリティドメインkSecAttrSecurityDomainCFString
アクセス可能性kSecAttrAccessibleCFString(定数)
アクセスグループkSecAttrAccessGroupCFString
同期可能kSecAttrSynchronizableCFBoolean
ラベルkSecAttrLabelCFString
コメントkSecAttrCommentCFString
作成者kSecAttrCreatorCFNumber(FourCharCode)
タイプkSecAttrTypeCFNumber(FourCharCode)
kSecClassCertificate

X.509 証明書です。通常はシステムが管理し、アプリのコードでは管理しません。

属性キー型
サブジェクトkSecAttrSubjectCFData(読み取り専用)
発行者kSecAttrIssuerCFData(読み取り専用)
シリアル番号kSecAttrSerialNumberCFData(読み取り専用)
サブジェクトキー IDkSecAttrSubjectKeyIDCFData(読み取り専用)
公開鍵ハッシュkSecAttrPublicKeyHashCFData(読み取り専用)
証明書の種類kSecAttrCertificateTypeCFNumber
証明書のエンコーディングkSecAttrCertificateEncodingCFNumber
ラベルkSecAttrLabelCFString
アクセスグループkSecAttrAccessGroupCFString
同期可能kSecAttrSynchronizableCFBoolean
kSecClassKey

暗号鍵(RSA、EC、AES)です。暗号化、署名、鍵共有に使用されます。

属性キー型
鍵クラスkSecAttrKeyClassCFString(定数)
アプリケーションラベルkSecAttrApplicationLabelCFData
アプリケーションタグkSecAttrApplicationTagCFData
鍵の種類kSecAttrKeyTypeCFString(定数)
ビット単位の鍵サイズkSecAttrKeySizeInBitsCFNumber
実効鍵サイズkSecAttrEffectiveKeySizeCFNumber
永続kSecAttrIsPermanentCFBoolean
機密kSecAttrIsSensitiveCFBoolean
抽出可能kSecAttrIsExtractableCFBoolean
ラベルkSecAttrLabelCFString
アクセスグループkSecAttrAccessGroupCFString
同期可能kSecAttrSynchronizableCFBoolean
トークン IDkSecAttrTokenIDCFString
kSecClassIdentity

デジタル ID は、秘密鍵と組み合わせられた証明書です。独立したストレージクラスではなく、一致する証明書と鍵からシステムが合成します。kSecClassIdentity 項目を直接追加することはできません。証明書と鍵を個別に追加してください。両方が同じ kSecAttrPublicKeyHash を共有している場合、クエリは ID を返します。

Quinn「The Eskimo!」の技術ノート「SecItem: Pitfalls and Best Practices」(forums/thread/724013)を参照してください。デジタル ID は保存された項目ではなく、仮想的な結合です。


クラスごとの一意性制約

各キーチェーン項目は、属性の一部によって一意に識別されます。同じ主キーを持つ項目を 2 つ目として追加すると、errSecDuplicateItem(-25299)が返されます。既存の項目を変更するには、SecItemUpdate を使用してください。

クラス主キー属性
汎用パスワードkSecAttrService + kSecAttrAccount + kSecAttrAccessGroup + kSecAttrSynchronizable
インターネットパスワードkSecAttrServer + kSecAttrPort + kSecAttrProtocol + kSecAttrAuthenticationType + kSecAttrPath + kSecAttrAccount + kSecAttrAccessGroup + kSecAttrSynchronizable
証明書kSecAttrCertificateType + kSecAttrIssuer + kSecAttrSerialNumber + kSecAttrAccessGroup + kSecAttrSynchronizable
鍵kSecAttrApplicationLabel + kSecAttrApplicationTag + kSecAttrKeyType + kSecAttrKeySizeInBits + kSecAttrEffectiveKeySize + kSecAttrKeyClass + kSecAttrAccessGroup + kSecAttrSynchronizable
IDN/A(証明書 + 鍵の仮想的な結合)

結果:一意な kSecAttrAccount 値を設定せずに、同じ kSecAttrService の下に複数ユーザーのトークンを保存すると、2 人目のユーザーに対する SecItemAdd は errSecDuplicateItem を返します。


属性定数リファレンス

ID 属性
定数型使用対象
kSecAttrServiceCFStringGenericPassword
kSecAttrAccountCFStringGenericPassword、InternetPassword
kSecAttrServerCFStringInternetPassword
kSecAttrLabelCFStringすべてのクラス
kSecAttrDescriptionCFStringGenericPassword、InternetPassword
kSecAttrCommentCFStringGenericPassword、InternetPassword
kSecAttrGenericCFDataGenericPassword
セキュリティ属性
定数型使用対象
kSecAttrAccessibleCFString(定数)すべてのクラス
kSecAttrAccessControlSecAccessControlすべてのクラス
kSecAttrAccessGroupCFStringすべてのクラス
kSecAttrSynchronizableCFBooleanすべてのクラス

kSecAttrAccessible と kSecAttrAccessControl は相互に排他的です。両方を設定するとエラーになります。kSecAttrAccessControl の作成時にアクセシビリティレベルが含まれるためです。

トークン属性
定数型用途
kSecAttrTokenIDCFStringキーをハードウェアトークンに紐付けます
kSecAttrTokenIDSecureEnclaveCFString(値)Secure Enclave — EC キーのみ(256 ビット)
キーメタデータ属性
定数型値
kSecAttrKeyTypeCFStringkSecAttrKeyTypeRSA、kSecAttrKeyTypeECSECPrimeRandom
kSecAttrKeySizeInBitsCFNumber256(EC)、2048/4096(RSA)
kSecAttrKeyClassCFStringkSecAttrKeyClassPublic、kSecAttrKeyClassPrivate、kSecAttrKeyClassSymmetric
kSecAttrApplicationTagCFDataキーの検索に使用するアプリ定義のタグ
kSecAttrApplicationLabelCFData公開鍵の SHA-1 ハッシュ(自動生成)

検索プロパティ

SecItemCopyMatching、SecItemUpdate(クエリパラメーター)、および SecItemDelete のクエリで使用します。

定数型用途
kSecMatchLimitCFString または CFNumber最大結果数 — kSecMatchLimitOne、kSecMatchLimitAll、または明示的な整数上限を指定する CFNumber(例:結果を 5 件に制限)
kSecMatchCaseInsensitiveCFBoolean文字列属性の大文字と小文字を区別しない照合
kSecMatchLimit のデフォルト

デフォルト値は状況によって異なり、バグのよくある原因です。

関数デフォルト動作
SecItemCopyMatchingkSecMatchLimitOne最初に一致した項目を返します
SecItemDeleteすべて一致一致する項目をすべて削除します

意図を明確にするため、SecItemCopyMatching では常に kSecMatchLimit を明示的に設定してください。SecItemDelete で kSecMatchLimit を省略すると、一致する項目がすべて削除されます。これは仕様であり、バグではありません。


戻り値の型プロパティ

SecItemCopyMatching と SecItemAdd の戻り値を制御します。クエリ辞書に設定します。

定数戻り値結果の型
kSecReturnDataシークレット(パスワードのバイト列、キーデータ)CFData
kSecReturnAttributes項目メタデータ辞書CFDictionary
kSecReturnRefキーチェーンオブジェクトの参照SecKey、SecCertificate、または SecIdentity
kSecReturnPersistentRef永続参照(アプリの再起動後も保持されます)CFData
クラスごとの戻り値の型の動作
クラスkSecReturnDatakSecReturnRef
汎用パスワードパスワードのバイト列該当なし(参照型なし)
インターネットパスワードパスワードのバイト列該当なし(参照型なし)
証明書DER エンコードされた証明書データSecCertificate
キーキーデータ(抽出可能な場合)SecKey
ID該当なしSecIdentity
複数の戻り値の型

複数の kSecReturn* キーが true の場合、結果は次のキーを持つ CFDictionary になります。

  • kSecValueData → データ
  • kSecValueRef → 参照
  • kSecValuePersistentRef → 永続参照
  • kSecReturnAttributes が true の場合は、すべての属性キーも含まれます

kSecMatchLimitAll が設定されている場合、結果は上記の要素を含む CFArray になります。


値の型プロパティ

追加、クエリ、および更新の各辞書で、値の指定または取得に使用します。

定数型用途
kSecValueDataCFDataシークレット(パスワード、キー素材)
kSecValueRefSecKey / SecCertificate / SecIdentityキーチェーンオブジェクトの参照
kSecValuePersistentRefCFData項目への永続参照
操作ごとの動作
プロパティSecItemAddSecItemCopyMatchingSecItemUpdate
kSecValueDataシークレットを設定します検索条件としては無効ですシークレットを置き換えます
kSecValueRef参照先のオブジェクトを追加します参照で検索します無効です
kSecValuePersistentRef無効です永続参照で検索します無効です

アクセシビリティ定数

キーチェーン項目を読み取り可能にするタイミングを制御します。kSecAttrAccessible で設定します。

定数利用可能なタイミングバックアップに保持iCloud 経由で同期
kSecAttrAccessibleWhenUnlockedデバイスのロック解除中はいはい(デフォルト)
kSecAttrAccessibleAfterFirstUnlock初回のロック解除後から再起動まではいはい
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnlyデバイスのロック解除中、かつパスコード設定済みいいえいいえ
kSecAttrAccessibleWhenUnlockedThisDeviceOnlyデバイスのロック解除中いいえいいえ
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly初回のロック解除後から再起動までいいえいいえ

デフォルト:新しい項目には kSecAttrAccessibleWhenUnlocked が適用されます。

ThisDeviceOnly バリアント:項目は暗号化されたバックアップに含まれず、iCloud Keychain 経由で同期されません。デバイスに紐付いたシークレット(生体認証で保護されたトークン、Secure Enclave キーなど)に使用します。

WhenPasscodeSetThisDeviceOnly:ユーザーがパスコードを削除すると、項目も削除されます。パスコードの削除後も保持してはならないシークレットに使用します。

AfterFirstUnlock:再起動後にユーザーが一度ロックを解除すると、バックグラウンドで利用可能になります。バックグラウンドフェッチ、プッシュ通知ハンドラー、バックグラウンドの URLSession 完了処理に必要です。

非推奨(使用しないでください):kSecAttrAccessibleAlways、kSecAttrAccessibleAlwaysThisDeviceOnly。


SecAccessControlCreateFlags

キーチェーン項目に対するきめ細かなアクセス制御です。SecAccessControlCreateWithFlags で作成し、kSecAttrAccessControl で設定します。

すべてのフラグ
フラグ用途
.userPresence生体認証またはデバイスのパスコード
.biometryAny登録済みの生体認証(新たな登録後も有効)
.biometryCurrentSet現在の生体認証セットのみ(生体認証情報の変更時に無効化)
.devicePasscodeデバイスのパスコードが必要です
.privateKeyUsageSecure Enclave キーの署名操作に必要です
.applicationPasswordアプリが提供するパスワード(ほかの認証要素に加えて使用)
.watchペアリング済みの Apple Watch で認証できます
.or論理 OR でフラグを組み合わせます(いずれか 1 つを満たせば認証できます)
.and論理 AND でフラグを組み合わせます(すべてを満たす必要があります)
アクセス制御の作成
var error: Unmanaged<CFError>?
guard let accessControl = SecAccessControlCreateWithFlags(
    kCFAllocatorDefault,
    kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
    [.biometryCurrentSet, .or, .devicePasscode],
    &error
) else {
    let nsError = error!.takeRetainedValue() as Error
    fatalError("Failed to create access control: \(nsError)")
}

let query: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.app",
    kSecAttrAccount as String: "auth-token",
    kSecAttrAccessControl as String: accessControl,
    kSecValueData as String: tokenData
]
let status = SecItemAdd(query as CFDictionary, nil)
フラグの組み合わせ
組み合わせ意味
[.biometryAny]登録済みの指紋または顔認証
[.biometryCurrentSet]現在の指紋または顔認証セット(再登録すると無効化)
[.biometryCurrentSet, .or, .devicePasscode]生体認証またはパスコードによるフォールバック
[.biometryCurrentSet, .and, .applicationPassword]生体認証とアプリのパスワード
[.privateKeyUsage]Secure Enclave キー操作(署名、復号)
[.biometryAny, .or, .watch]生体認証またはペアリング済みの Watch

.biometryAny と .biometryCurrentSet の違い:銀行トークンなど、セキュリティ要件の高い項目には .biometryCurrentSet を使用します。ユーザーが新しい指紋を登録すると、項目にアクセスできなくなります。その場合、アプリで再認証を行い、項目を再保存する必要があります。新たな登録後もアクセスを無効にする必要のない、利便性を重視する項目には .biometryAny を使用します。


LocalAuthentication との統合

キーチェーンでの LAContext

LAContext で生体認証を事前評価してから、そのコンテキストをキーチェーンクエリに渡すと、2 回目の生体認証プロンプトを避けられます。

import LocalAuthentication

let context = LAContext()
context.localizedReason = "Access your credentials"

var authError: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) else {
    // Biometrics unavailable — handle error or fall back to passcode
    return
}

context.evaluatePolicy(
    .deviceOwnerAuthenticationWithBiometrics,
    localizedReason: "Authenticate to access credentials"
) { success, error in
    guard success else { return }

    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: "com.example.app",
        kSecAttrAccount as String: "auth-token",
        kSecReturnData as String: true,
        kSecMatchLimit as String: kSecMatchLimitOne,
        kSecUseAuthenticationContext as String: context
    ]
    var result: AnyObject?
    let status = SecItemCopyMatching(query as CFDictionary, &result)
}
LAContext の Keychain キー
キー型目的
kSecUseAuthenticationContextLAContext認証済みのコンテキストを再利用します(二重のプロンプトを回避します)
kSecUseAuthenticationUICFStringUI の動作を制御します:kSecUseAuthenticationUIAllow(デフォルト)、kSecUseAuthenticationUIFail、kSecUseAuthenticationUISkip

kSecUseAuthenticationUIFail:生体認証のプロンプトを表示せずに、errSecInteractionNotAllowed を返します。UI を表示せずにアイテムの存在を確認する場合に使用します。

LAPolicy の種類
ポリシー要件
.deviceOwnerAuthenticationWithBiometricsFace ID または Touch ID のみ
.deviceOwnerAuthentication生体認証またはパスコードによるフォールバック
BiometryType の検出
let context = LAContext()
var error: NSError?
context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)

switch context.biometryType {
case .faceID:    // Face ID available
case .touchID:   // Touch ID available
case .opticID:   // Optic ID available (visionOS)
case .none:      // No biometric hardware
@unknown default: break
}
LAError コード
エラーコード原因
.authenticationFailed-1ユーザーの認証に失敗しました
.userCancel-2ユーザーが「キャンセル」をタップしました
.userFallback-3ユーザーが「パスワードを入力」をタップしました
.systemCancel-4システムがキャンセルしました(アプリがバックグラウンドに移行)
.passcodeNotSet-5パスコードが設定されていません
.biometryNotAvailable-6ハードウェアが利用できないか、制限されています
.biometryNotEnrolled-7生体認証が登録されていません
.biometryLockout-8認証の失敗が多すぎます

OSStatus エラーコード

よく使われる Keychain の OSStatus 値と、その根本原因です。

エラーコード説明よくある原因
errSecSuccess0操作に成功しました—
errSecDuplicateItem-25299アイテムはすでに存在します同じ主キーで追加しようとしています — 代わりに SecItemUpdate を使用してください
errSecItemNotFound-25300一致するアイテムがありませんクエリ属性が間違っているか、アイテムが保存されていません
errSecInteractionNotAllowed-25308UI プロンプトがブロックされましたアイテムに認証が必要ですがデバイスがロックされているか、kSecUseAuthenticationUIFail が設定されています
errSecAuthFailed-25293認証に失敗しましたパスワードが間違っている、生体認証に失敗した、または ACL によって拒否されました
errSecMissingEntitlement-34018Keychain のエンタイトルメントがありませんアプリに keychain-access-groups エンタイトルメントがありません — ユニットテストターゲットでよく発生します
errSecNoSuchAttr-25303属性が見つかりませんアイテムクラスで有効ではない属性をクエリしています
errSecParam-50パラメーターが無効ですクエリ辞書の形式が不正です — 型の不一致(例:Data が必要な箇所に String を指定)を確認してください
errSecAllocate-108メモリを確保できませんでしたシステムリソースが枯渇しています
errSecDecode-26275データをデコードできませんアイテムが破損しているか、エンコード形式が一致しません
errSecNotAvailable-25291Keychain を利用できませんKeychain データベースがありません(まれなケース — Simulator のリセット、またはインストールの破損)
Swift での OSStatus の解釈
let status = SecItemAdd(query as CFDictionary, nil)
if status != errSecSuccess {
    let message = SecCopyErrorMessageString(status, nil) as? String ?? "Unknown error"
    print("Keychain error \(status): \(message)")
}
テストターゲットでの -34018

ユニットテストランナー(XCTest)には、keychain-access-groups エンタイトルメントがないことがよくあります。回避策:

  1. テストターゲットにホストアプリケーションを追加します(Xcode → テストターゲット → General → Host Application)
  2. ユニットテストではメモリ内モックを使用し、実際の Keychain は統合テストでのみ使用します

Keychain の共有

アクセスグループ

デフォルトでは、アイテムはアプリごとに分離されています。アプリ間または拡張機能間で共有するには:

  1. Xcode で「Keychain Sharing」ケイパビリティを有効にします
  2. 共有アクセスグループの識別子を追加します
  3. アイテムを追加する際に kSecAttrAccessGroup を設定します
let query: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.shared",
    kSecAttrAccount as String: "shared-token",
    kSecAttrAccessGroup as String: "TEAMID.com.example.shared",
    kSecValueData as String: tokenData
]

アクセスグループの形式は $(TeamIdentifierPrefix)$(GroupIdentifier) です。明示的なアクセスグループが設定されていないアイテムは、エンタイトルメント内のアプリの最初のアクセスグループがデフォルトになります。

iCloud Keychain の同期

kSecAttrSynchronizable を true に設定すると、iCloud Keychain 経由で同期されます:

let query: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrService as String: "com.example.app",
    kSecAttrAccount as String: "sync-token",
    kSecAttrSynchronizable as String: true,
    kSecValueData as String: tokenData
]

同期可能なアイテムでは、ThisDeviceOnly のアクセシビリティレベルや SecAccessControl は使用できません。kSecAttrAccessibleWhenUnlocked または kSecAttrAccessibleAfterFirstUnlock を使用する必要があります。

クエリ時、kSecAttrSynchronizable のデフォルトは kSecAttrSynchronizableAny です(ローカルアイテムと同期済みアイテムの両方を返します)。絞り込むには、true または false を明示的に設定します。


Resources

WWDC: 2013-709, 2014-711, 2020-10147

Docs: /security/keychain_services, /localauthentication, /security/secaccesscontrolcreateflags, /security/secitemadd(::)

Skills: axiom-code-signing-ref, axiom-app-attest

コメント