2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <Foundation/Foundation.h>
25 #import <TrustedPeers/TrustedPeers.h>
26 #import <objc/runtime.h>
28 #import "keychain/ckks/CKKSKeychainBackedKey.h"
29 #import "keychain/ckks/CKKSTLKShare.h"
31 #import "keychain/ot/OTConstants.h"
33 NS_ASSUME_NONNULL_BEGIN
35 // Any client hoping to use the TrustedPeersHelperProtocol should have an entitlement
36 // 'com.apple.private.trustedpeershelper.client' set to boolean YES.
38 @interface TrustedPeersHelperPeerState
: NSObject
<NSSecureCoding
>
39 @
property (nullable
) NSString
* peerID
;
40 @property BOOL identityIsPreapproved
;
41 @property TPPeerStatus peerStatus
;
42 @property BOOL memberChanges
;
43 @property BOOL unknownMachineIDsPresent
;
44 @
property (nullable
) NSString
* osVersion
;
46 - (instancetype
)initWithPeerID
:(NSString
* _Nullable
)peerID
47 isPreapproved
:(BOOL
)isPreapproved
48 status
:(TPPeerStatus
)peerStatus
49 memberChanges
:(BOOL
)memberChanges
50 unknownMachineIDs
:(BOOL
)unknownMachineIDs
51 osVersion
:(NSString
* _Nullable
)osVersion
;
54 @interface TrustedPeersHelperPeer
: NSObject
<NSSecureCoding
>
55 @
property (nullable
) NSString
* peerID
;
56 @
property (nullable
) NSData
* signingSPKI
;
57 @
property (nullable
) NSData
* encryptionSPKI
;
58 @
property (nullable
) NSSet
<NSString
*>* viewList
;
60 - (instancetype
)initWithPeerID
:(NSString
*)peerID
61 signingSPKI
:(NSData
*)signingSPKI
62 encryptionSPKI
:(NSData
*)encryptionSPKI
63 viewList
:(NSSet
<NSString
*>*)viewList
;
66 @interface TrustedPeersHelperEgoPeerStatus
: NSObject
<NSSecureCoding
>
67 @property TPPeerStatus egoStatus
;
68 @property NSString
* _Nullable egoPeerID
;
69 @
property (assign
) uint64_t numberOfPeersInOctagon
;
71 // Note: this field does not include untrusted peers
72 @property NSDictionary
<NSString
*, NSNumber
*>* viablePeerCountsByModelID
;
74 // Note: this field does include untrusted peers
75 @property NSDictionary
<NSString
*, NSNumber
*>* peerCountsByMachineID
;
77 @property BOOL isExcluded
;
78 @property BOOL isLocked
;
80 - (instancetype
)initWithEgoPeerID
:(NSString
* _Nullable
)egoPeerID
81 status
:(TPPeerStatus
)egoStatus
82 viablePeerCountsByModelID
:(NSDictionary
<NSString
*, NSNumber
*>*)viablePeerCountsByModelID
83 peerCountsByMachineID
:(NSDictionary
<NSString
*, NSNumber
*>*)peerCountsByMachineID
84 isExcluded
:(BOOL
)isExcluded
85 isLocked
:(BOOL
)isLocked
;
89 // This protocol describes the interface of the TrustedPeersHelper XPC service.
90 @protocol TrustedPeersHelperProtocol
92 // This is used by a unit test which exercises the XPC-service plumbing.
93 - (void)pingWithReply
:(void (^)(void))reply
;
95 - (void)dumpWithContainer
:(NSString
*)container
96 context
:(NSString
*)context
97 reply
:(void (^)(NSDictionary
* _Nullable
, NSError
* _Nullable
))reply
;
99 - (void)departByDistrustingSelfWithContainer
:(NSString
*)container
100 context
:(NSString
*)context
101 reply
:(void (^)(NSError
* _Nullable
))reply
;
103 - (void)distrustPeerIDsWithContainer
:(NSString
*)container
104 context
:(NSString
*)context
105 peerIDs
:(NSSet
<NSString
*>*)peerIDs
106 reply
:(void (^)(NSError
* _Nullable
))reply
;
108 - (void)trustStatusWithContainer
:(NSString
*)container
109 context
:(NSString
*)context
110 reply
:(void (^)(TrustedPeersHelperEgoPeerStatus
*status
,
111 NSError
* _Nullable error
))reply
;
113 - (void)resetWithContainer
:(NSString
*)container
114 context
:(NSString
*)context
115 resetReason
:(CuttlefishResetReason
)reason
116 reply
:(void (^)(NSError
* _Nullable error
))reply
;
118 - (void)localResetWithContainer
:(NSString
*)container
119 context
:(NSString
*)context
120 reply
:(void (^)(NSError
* _Nullable error
))reply
;
122 // The following three machine ID list manipulation functions do not attempt to apply the results to the model
123 // If you'd like that to occur, please call update()
125 // TODO: how should we communicate TLK rolling when the update() call will remove a peer?
126 // <rdar://problem/46633449> Octagon: must be able to roll TLKs when a peer departs due to machine ID list
128 // listDifferences: False if the allowedMachineIDs list passed in exactly matches the previous state,
129 // True if there were any differences
130 - (void)setAllowedMachineIDsWithContainer
:(NSString
*)container
131 context
:(NSString
*)context
132 allowedMachineIDs
:(NSSet
<NSString
*> *)allowedMachineIDs
133 honorIDMSListChanges
:(BOOL
)honorIDMSListChanges
134 reply
:(void (^)(BOOL listDifferences
, NSError
* _Nullable error
))reply
;
136 - (void)addAllowedMachineIDsWithContainer
:(NSString
*)container
137 context
:(NSString
*)context
138 machineIDs
:(NSArray
<NSString
*> *)machineIDs
139 reply
:(void (^)(NSError
* _Nullable error
))reply
;
141 - (void)removeAllowedMachineIDsWithContainer
:(NSString
*)container
142 context
:(NSString
*)context
143 machineIDs
:(NSArray
<NSString
*> *)machineIDs
144 reply
:(void (^)(NSError
* _Nullable error
))reply
;
146 - (void)fetchAllowedMachineIDsWithContainer
:(NSString
*)container
147 context
:(NSString
*)context
148 reply
:(void (^)(NSSet
<NSString
*>* _Nullable machineIDs
, NSError
* _Nullable error
))reply
;
150 - (void)fetchEgoEpochWithContainer
:(NSString
*)container
151 context
:(NSString
*)context
152 reply
:(void (^)(unsigned long long epoch
,
153 NSError
* _Nullable error
))reply
;
155 - (void)prepareWithContainer
:(NSString
*)container
156 context
:(NSString
*)context
157 epoch
:(unsigned long long)epoch
158 machineID
:(NSString
*)machineID
159 bottleSalt
:(NSString
*)bottleSalt
160 bottleID
:(NSString
*)bottleID
161 modelID
:(NSString
*)modelID
162 deviceName
:(nullable NSString
*)deviceName
163 serialNumber
:(nullable NSString
*)serialNumber
164 osVersion
:(NSString
*)osVersion
165 policyVersion
:(nullable TPPolicyVersion
*)policyVersion
166 policySecrets
:(nullable NSDictionary
<NSString
*,NSData
*> *)policySecrets
167 syncUserControllableViews
:(TPPBPeerStableInfo_UserControllableViewStatus
)syncUserControllableViews
168 signingPrivKeyPersistentRef
:(nullable NSData
*)spkPr
169 encPrivKeyPersistentRef
:(nullable NSData
*)epkPr
170 reply
:(void (^)(NSString
* _Nullable peerID
,
171 NSData
* _Nullable permanentInfo
,
172 NSData
* _Nullable permanentInfoSig
,
173 NSData
* _Nullable stableInfo
,
174 NSData
* _Nullable stableInfoSig
,
175 TPSyncingPolicy
* _Nullable syncingPolicy
,
176 NSError
* _Nullable error
))reply
;
178 // If there already are existing CKKSViews, please pass in their key sets anyway.
179 // This function will create a self TLK Share for those TLKs.
180 - (void)establishWithContainer
:(NSString
*)container
181 context
:(NSString
*)context
182 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
183 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
184 preapprovedKeys
:(nullable NSArray
<NSData
*> *)preapprovedKeys
185 reply
:(void (^)(NSString
* _Nullable peerID
,
186 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
187 TPSyncingPolicy
* _Nullable syncingPolicy
,
188 NSError
* _Nullable error
))reply
;
190 // Returns a voucher for the given peer ID using our own identity
191 // If TLK CKKSViewKeys are given, TLKShares will be created and uploaded for this new peer before this call returns.
192 - (void)vouchWithContainer
:(NSString
*)container
193 context
:(NSString
*)context
194 peerID
:(NSString
*)peerID
195 permanentInfo
:(NSData
*)permanentInfo
196 permanentInfoSig
:(NSData
*)permanentInfoSig
197 stableInfo
:(NSData
*)stableInfo
198 stableInfoSig
:(NSData
*)stableInfoSig
199 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
200 reply
:(void (^)(NSData
* _Nullable voucher
,
201 NSData
* _Nullable voucherSig
,
202 NSError
* _Nullable error
))reply
;
204 // Preflighting a vouch will return the peer ID associated with the bottle you will be recovering, as well as
205 // the syncing policy used by that peer, and,
206 // You can then use that peer ID to filter the tlkshares provided to vouchWithBottle.
207 // If TPH had to refetch anything from the network, it will report that fact as refetchNeeded.
208 - (void)preflightVouchWithBottleWithContainer
:(NSString
*)container
209 context
:(NSString
*)context
210 bottleID
:(NSString
*)bottleID
211 reply
:(void (^)(NSString
* _Nullable peerID
,
212 TPSyncingPolicy
* _Nullable syncingPolicy
,
213 BOOL refetchWasNeeded
,
214 NSError
* _Nullable error
))reply
;
216 // Returns a voucher for our own identity, created by the identity inside this bottle
217 - (void)vouchWithBottleWithContainer
:(NSString
*)container
218 context
:(NSString
*)context
219 bottleID
:(NSString
*)bottleID
220 entropy
:(NSData
*)entropy
221 bottleSalt
:(NSString
*)bottleSalt
222 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
223 reply
:(void (^)(NSData
* _Nullable voucher
,
224 NSData
* _Nullable voucherSig
,
225 int64_t uniqueTLKsRecovered
,
226 int64_t totalTLKSharesRecovered
,
227 NSError
* _Nullable error
))reply
;
229 // Preflighting a vouch will return the RK ID, view list and policy associated with the RK you will be recovering.
230 // You can then use that peer ID to filter the tlkshares provided to vouchWithRecoveryKey.
231 - (void)preflightVouchWithRecoveryKeyWithContainer
:(NSString
*)container
232 context
:(NSString
*)context
233 recoveryKey
:(NSString
*)recoveryKey
235 reply
:(void (^)(NSString
* _Nullable recoveryKeyID
,
236 TPSyncingPolicy
* _Nullable syncingPolicy
,
237 NSError
* _Nullable error
))reply
;
239 // Returns a voucher for our own identity, using recovery key
240 - (void)vouchWithRecoveryKeyWithContainer
:(NSString
*)container
241 context
:(NSString
*)context
242 recoveryKey
:(NSString
*)recoveryKey
244 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
245 reply
:(void (^)(NSData
* _Nullable voucher
,
246 NSData
* _Nullable voucherSig
,
247 NSError
* _Nullable error
))reply
;
249 // As of right now, join and attemptPreapprovedJoin will upload TLKShares for any TLKs that this peer already has.
250 // Note that in The Future, a device might decide to join an existing Octagon set while introducing a new view.
251 // These interfaces will have to change...
252 - (void)joinWithContainer
:(NSString
*)container
253 context
:(NSString
*)context
254 voucherData
:(NSData
*)voucherData
255 voucherSig
:(NSData
*)voucherSig
256 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
257 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
258 preapprovedKeys
:(nullable NSArray
<NSData
*> *)preapprovedKeys
259 reply
:(void (^)(NSString
* _Nullable peerID
,
260 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
261 TPSyncingPolicy
* _Nullable syncingPolicy
,
262 NSError
* _Nullable error
))reply
;
264 // Preflighting a preapproved join suggests whether or not you expect to succeed in an immediate preapprovedJoin() call
265 // This only inspects the Octagon model, and ignores the trusted device list, so that you can preflight the preapprovedJoin()
266 // before fetching that list.
267 // This will return YES if there are no existing peers, or if the existing peers preapprove your prepared identity, and
268 // you are intending to trust at least one preapproving peer (so that you don't stomp all over everyone else at join time).
269 // This will return NO otherwise.
270 - (void)preflightPreapprovedJoinWithContainer
:(NSString
*)container
271 context
:(NSString
*)context
272 preapprovedKeys
:(nullable NSArray
<NSData
*> *)preapprovedKeys
273 reply
:(void (^)(BOOL launchOkay
,
274 NSError
* _Nullable error
))reply
;
276 // A preapproved join might do a join, but it also might do an establish.
277 // Therefore, it needs all the TLKs and TLKShares as establish does
278 - (void)attemptPreapprovedJoinWithContainer
:(NSString
*)container
279 context
:(NSString
*)context
280 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
281 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
282 preapprovedKeys
:(nullable NSArray
<NSData
*> *)preapprovedKeys
283 reply
:(void (^)(NSString
* _Nullable peerID
,
284 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
285 TPSyncingPolicy
* _Nullable syncingPolicy
,
286 NSError
* _Nullable error
))reply
;
288 // TODO: if the new policy causes someone to lose access to a view, how should this API work?
289 // syncUserControllableViews should contain the raw value of the TPPBPeerStableInfo_UserControllableViewStatus enum, or be nil
290 - (void)updateWithContainer
:(NSString
*)container
291 context
:(NSString
*)context
292 deviceName
:(nullable NSString
*)deviceName
293 serialNumber
:(nullable NSString
*)serialNumber
294 osVersion
:(nullable NSString
*)osVersion
295 policyVersion
:(nullable NSNumber
*)policyVersion
296 policySecrets
:(nullable NSDictionary
<NSString
*,NSData
*> *)policySecrets
297 syncUserControllableViews
:(nullable NSNumber
*)syncUserControllableViews
298 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable peerState
,
299 TPSyncingPolicy
* _Nullable syncingPolicy
,
300 NSError
* _Nullable error
))reply
;
302 - (void)setPreapprovedKeysWithContainer
:(NSString
*)container
303 context
:(NSString
*)context
304 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
305 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable peerState
, NSError
* _Nullable error
))reply
;
307 /* Rather thin pass-through for uploading new TLKs (for zones which may have disappeared) */
308 - (void)updateTLKsWithContainer
:(NSString
*)container
309 context
:(NSString
*)context
310 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
311 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
312 reply
:(void (^)(NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
, NSError
* _Nullable error
))reply
;
314 - (void)fetchViableBottlesWithContainer
:(NSString
*)container
315 context
:(NSString
*)context
316 reply
:(void (^)(NSArray
<NSString
*>* _Nullable sortedBottleIDs
, NSArray
<NSString
*>* _Nullable sortedPartialBottleIDs
, NSError
* _Nullable error
))reply
;
318 - (void)fetchViableEscrowRecordsWithContainer
:(NSString
*)container
319 context
:(NSString
*)context
320 forceFetch
:(BOOL
)forceFetch
321 reply
:(void (^)(NSArray
<NSData
*>* _Nullable records
, NSError
* _Nullable error
))reply
;
323 - (void)fetchEscrowContentsWithContainer
:(NSString
*)container
324 context
:(NSString
*)context
325 reply
:(void (^)(NSData
* _Nullable entropy
,
326 NSString
* _Nullable bottleID
,
327 NSData
* _Nullable signingPublicKey
,
328 NSError
* _Nullable error
))reply
;
330 - (void)fetchPolicyDocumentsWithContainer
:(NSString
*)container
331 context
:(NSString
*)context
332 versions
:(NSSet
<TPPolicyVersion
*>*)versions
333 reply
:(void (^)(NSDictionary
<TPPolicyVersion
*, NSData
*>* _Nullable entries
,
334 NSError
* _Nullable error
))reply
;
336 // Fetch the policy and view list for current peer.
337 // Note: userControllableViewStatusOfPeers is not our current peer's view of the world, but rather what
338 // our peers believe.
339 // If there is no prepared ego peer, the returned policy will be for a device with modelIDOverride
340 - (void)fetchCurrentPolicyWithContainer
:(NSString
*)container
341 context
:(NSString
*)context
342 modelIDOverride
:(NSString
* _Nullable
)modelID
343 reply
:(void (^)(TPSyncingPolicy
* _Nullable syncingPolicy
,
344 TPPBPeerStableInfo_UserControllableViewStatus userControllableViewStatusOfPeers
,
345 NSError
* _Nullable error
))reply
;
347 - (void)validatePeersWithContainer
:(NSString
*)container
348 context
:(NSString
*)context
349 reply
:(void (^)(NSDictionary
* _Nullable
, NSError
* _Nullable
))reply
;
352 // TODO: merge this and trustStatusWithContainer
353 - (void)fetchTrustStateWithContainer
:(NSString
*)container
354 context
:(NSString
*)context
355 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable selfPeerState
,
356 NSArray
<TrustedPeersHelperPeer
*>* _Nullable trustedPeers
,
357 NSError
* _Nullable error
))reply
;
359 - (void)setRecoveryKeyWithContainer
:(NSString
*)container
360 context
:(NSString
*)context
361 recoveryKey
:(NSString
*)recoveryKey
362 salt
:(NSString
*)salt
363 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
364 reply
:(void (^)(NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
365 NSError
* _Nullable error
))reply
;
367 - (void)reportHealthWithContainer
:(NSString
*)container
368 context
:(NSString
*)context
369 stateMachineState
:(NSString
*)state
370 trustState
:(NSString
*)trustState
371 reply
:(void (^)(NSError
* _Nullable error
))reply
;
373 - (void)pushHealthInquiryWithContainer
:(NSString
*)container
374 context
:(NSString
*)context
375 reply
:(void (^)(NSError
* _Nullable error
))reply
;
377 - (void)requestHealthCheckWithContainer
:(NSString
*)container
378 context
:(NSString
*)context
379 requiresEscrowCheck
:(BOOL
)requiresEscrowCheck
380 reply
:(void (^)(BOOL postRepairCFU
, BOOL postEscrowCFU
, BOOL resetOctagon
, BOOL leaveTrust
, NSError
* _Nullable
))reply
;
382 - (void)getSupportAppInfoWithContainer
:(NSString
*)container
383 context
:(NSString
*)context
384 reply
:(void (^)(NSData
* _Nullable
, NSError
* _Nullable
))reply
;
386 - (void)removeEscrowCacheWithContainer
:(NSString
*)container
387 context
:(NSString
*)context
388 reply
:(void (^)(NSError
* _Nullable
))reply
;
393 To use the service from an application or other process, use NSXPCConnection to establish a connection to the service by doing something like this:
395 _connectionToService = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.TrustedPeersHelper"];
396 _connectionToService.remoteObjectInterface = TrustedPeersHelperSetupProtocol([NSXPCInterface interfaceWithProtocol:@protocol(TrustedPeersHelperProtocol)]);
397 [_connectionToService resume];
399 Once you have a connection to the service, you can use it like this:
401 [[_connectionToService remoteObjectProxy] upperCaseString:@"hello" withReply:^(NSString *aString) {
402 // We have received a response. Update our text field, but do it on the main thread.
403 NSLog(@"Result string was: %@", aString);
406 And, when you are finished with the service, clean up the connection like this:
408 [_connectionToService invalidate];
412 // Use this at protocol creation time to tell NSXPC to do its job
413 NSXPCInterface
* TrustedPeersHelperSetupProtocol(NSXPCInterface
* interface
);
415 NS_ASSUME_NONNULL_END