]> git.saurik.com Git - apple/security.git/blob - keychain/TrustedPeersHelper/Container_RecoveryKey.swift
Security-59306.101.1.tar.gz
[apple/security.git] / keychain / TrustedPeersHelper / Container_RecoveryKey.swift
1 import CoreData
2 import Foundation
3
4 extension Container {
5 func preflightVouchWithRecoveryKey(recoveryKey: String,
6 salt: String,
7 reply: @escaping (String?, Set<String>?, TPPolicy?, Error?) -> Void) {
8 self.semaphore.wait()
9 let reply: (String?, Set<String>?, TPPolicy?, Error?) -> Void = {
10 os_log("preflightRecoveryKey complete: %{public}@",
11 log: tplogTrace, type: .info, traceError($3))
12 self.semaphore.signal()
13 reply($0, $1, $2, $3)
14 }
15
16 self.fetchAndPersistChangesIfNeeded { fetchError in
17 guard fetchError == nil else {
18 os_log("preflightRecoveryKey unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
19 reply(nil, nil, nil, fetchError)
20 return
21 }
22
23 // Ensure we have all policy versions claimed by peers, including our sponsor
24 self.fetchPolicyDocumentsWithSemaphore(versions: self.model.allPolicyVersions()) { _, fetchPolicyDocumentsError in
25 guard fetchPolicyDocumentsError == nil else {
26 os_log("preflightRecoveryKey unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
27 reply(nil, nil, nil, fetchPolicyDocumentsError)
28 return
29 }
30
31 self.moc.performAndWait {
32 guard let egoPeerID = self.containerMO.egoPeerID,
33 let egoPermData = self.containerMO.egoPeerPermanentInfo,
34 let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
35 os_log("preflightRecoveryKey: no ego peer ID", log: tplogDebug, type: .default)
36 reply(nil, nil, nil, ContainerError.noPreparedIdentity)
37 return
38 }
39
40 let keyFactory = TPECPublicKeyFactory()
41 guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
42 reply(nil, nil, nil, ContainerError.invalidPermanentInfoOrSig)
43 return
44 }
45
46 var recoveryKeys: RecoveryKey
47 do {
48 recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
49 } catch {
50 os_log("preflightRecoveryKey: failed to create recovery keys: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
51 reply(nil, nil, nil, ContainerError.failedToCreateRecoveryKey)
52 return
53 }
54
55 // Dear model: if i were to use this recovery key, what peers would I end up using?
56 guard self.model.isRecoveryKeyEnrolled() else {
57 os_log("preflightRecoveryKey: recovery Key is not enrolled", log: tplogDebug, type: .default)
58 reply(nil, nil, nil, ContainerError.recoveryKeysNotEnrolled)
59 return
60 }
61
62 guard let sponsorPeerID = self.model.peerIDThatTrustsRecoveryKeys(TPRecoveryKeyPair(signingSPKI: recoveryKeys.peerKeys.signingKey.publicKey.keyData,
63 encryptionSPKI: recoveryKeys.peerKeys.encryptionKey.publicKey.keyData)) else {
64 os_log("preflightRecoveryKey Untrusted recovery key set", log: tplogDebug, type: .default)
65 reply(nil, nil, nil, ContainerError.untrustedRecoveryKeys)
66 return
67 }
68
69 guard let sponsor = self.model.peer(withID: sponsorPeerID) else {
70 os_log("preflightRecoveryKey Failed to find peer with ID", log: tplogDebug, type: .default)
71 reply(nil, nil, nil, ContainerError.sponsorNotRegistered(sponsorPeerID))
72 return
73 }
74
75 do {
76 let bestPolicy = try self.model.policy(forPeerIDs: sponsor.dynamicInfo?.includedPeerIDs ?? [sponsor.peerID],
77 candidatePeerID: egoPeerID,
78 candidateStableInfo: sponsor.stableInfo)
79
80 let views = try bestPolicy.views(forModel: selfPermanentInfo.modelID)
81 reply(recoveryKeys.peerKeys.peerID, views, bestPolicy, nil)
82 } catch {
83 os_log("preflightRecoveryKey: error fetching policy: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
84 reply(nil, nil, nil, error)
85 return
86 }
87 }
88 }
89 }
90 }
91 }