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>
27 #import "keychain/ckks/CKKSKeychainBackedKey.h"
28 #import "keychain/ckks/CKKSTLKShare.h"
30 #import "keychain/ot/OTConstants.h"
32 NS_ASSUME_NONNULL_BEGIN
34 // Any client hoping to use the TrustedPeersHelperProtocol should have an entitlement
35 // 'com.apple.private.trustedpeershelper.client' set to boolean YES.
37 @interface TrustedPeersHelperPeerState
: NSObject
<NSSecureCoding
>
38 @
property (nullable
) NSString
* peerID
;
39 @property BOOL identityIsPreapproved
;
40 @property TPPeerStatus peerStatus
;
41 @property BOOL memberChanges
;
42 @property BOOL unknownMachineIDsPresent
;
43 @
property (nullable
) NSString
* osVersion
;
45 - (instancetype
)initWithPeerID
:(NSString
* _Nullable
)peerID
46 isPreapproved
:(BOOL
)isPreapproved
47 status
:(TPPeerStatus
)peerStatus
48 memberChanges
:(BOOL
)memberChanges
49 unknownMachineIDs
:(BOOL
)unknownMachineIDs
50 osVersion
:(NSString
* _Nullable
)osVersion
;
53 @interface TrustedPeersHelperPeer
: NSObject
<NSSecureCoding
>
54 @
property (nullable
) NSString
* peerID
;
55 @
property (nullable
) NSData
* signingSPKI
;
56 @
property (nullable
) NSData
* encryptionSPKI
;
57 @
property (nullable
) NSSet
<NSString
*>* viewList
;
59 - (instancetype
)initWithPeerID
:(NSString
*)peerID
60 signingSPKI
:(NSData
*)signingSPKI
61 encryptionSPKI
:(NSData
*)encryptionSPKI
62 viewList
:(NSSet
<NSString
*>*)viewList
;
65 @interface TrustedPeersHelperEgoPeerStatus
: NSObject
<NSSecureCoding
>
66 @property TPPeerStatus egoStatus
;
67 @property NSString
* _Nullable egoPeerID
;
68 @
property (assign
) uint64_t numberOfPeersInOctagon
;
70 // Note: this field does not include untrusted peers
71 @property NSDictionary
<NSString
*, NSNumber
*>* viablePeerCountsByModelID
;
73 // Note: this field does include untrusted peers
74 @property NSDictionary
<NSString
*, NSNumber
*>* peerCountsByMachineID
;
76 @property BOOL isExcluded
;
77 @property BOOL isLocked
;
79 - (instancetype
)initWithEgoPeerID
:(NSString
* _Nullable
)egoPeerID
80 status
:(TPPeerStatus
)egoStatus
81 viablePeerCountsByModelID
:(NSDictionary
<NSString
*, NSNumber
*>*)viablePeerCountsByModelID
82 peerCountsByMachineID
:(NSDictionary
<NSString
*, NSNumber
*>*)peerCountsByMachineID
83 isExcluded
:(BOOL
)isExcluded
84 isLocked
:(BOOL
)isLocked
;
88 // This protocol describes the interface of the TrustedPeersHelper XPC service.
89 @protocol TrustedPeersHelperProtocol
91 // This is used by a unit test which exercises the XPC-service plumbing.
92 - (void)pingWithReply
:(void (^)(void))reply
;
94 - (void)dumpWithContainer
:(NSString
*)container
95 context
:(NSString
*)context
96 reply
:(void (^)(NSDictionary
* _Nullable
, NSError
* _Nullable
))reply
;
98 - (void)departByDistrustingSelfWithContainer
:(NSString
*)container
99 context
:(NSString
*)context
100 reply
:(void (^)(NSError
* _Nullable
))reply
;
102 - (void)distrustPeerIDsWithContainer
:(NSString
*)container
103 context
:(NSString
*)context
104 peerIDs
:(NSSet
<NSString
*>*)peerIDs
105 reply
:(void (^)(NSError
* _Nullable
))reply
;
107 - (void)trustStatusWithContainer
:(NSString
*)container
108 context
:(NSString
*)context
109 reply
:(void (^)(TrustedPeersHelperEgoPeerStatus
*status
,
110 NSError
* _Nullable error
))reply
;
112 - (void)resetWithContainer
:(NSString
*)container
113 context
:(NSString
*)context
114 resetReason
:(CuttlefishResetReason
)reason
115 reply
:(void (^)(NSError
* _Nullable error
))reply
;
117 - (void)localResetWithContainer
:(NSString
*)container
118 context
:(NSString
*)context
119 reply
:(void (^)(NSError
* _Nullable error
))reply
;
121 // The following three machine ID list manipulation functions do not attempt to apply the results to the model
122 // If you'd like that to occur, please call update()
124 // TODO: how should we communicate TLK rolling when the update() call will remove a peer?
125 // <rdar://problem/46633449> Octagon: must be able to roll TLKs when a peer departs due to machine ID list
127 // listDifferences: False if the allowedMachineIDs list passed in exactly matches the previous state,
128 // True if there were any differences
129 - (void)setAllowedMachineIDsWithContainer
:(NSString
*)container
130 context
:(NSString
*)context
131 allowedMachineIDs
:(NSSet
<NSString
*> *)allowedMachineIDs
132 reply
:(void (^)(BOOL listDifferences
, NSError
* _Nullable error
))reply
;
134 - (void)addAllowedMachineIDsWithContainer
:(NSString
*)container
135 context
:(NSString
*)context
136 machineIDs
:(NSArray
<NSString
*> *)machineIDs
137 reply
:(void (^)(NSError
* _Nullable error
))reply
;
139 - (void)removeAllowedMachineIDsWithContainer
:(NSString
*)container
140 context
:(NSString
*)context
141 machineIDs
:(NSArray
<NSString
*> *)machineIDs
142 reply
:(void (^)(NSError
* _Nullable error
))reply
;
144 - (void)fetchAllowedMachineIDsWithContainer
:(NSString
*)container
145 context
:(NSString
*)context
146 reply
:(void (^)(NSSet
<NSString
*>* _Nullable machineIDs
, NSError
* _Nullable error
))reply
;
148 - (void)fetchEgoEpochWithContainer
:(NSString
*)container
149 context
:(NSString
*)context
150 reply
:(void (^)(unsigned long long epoch
,
151 NSError
* _Nullable error
))reply
;
153 - (void)prepareWithContainer
:(NSString
*)container
154 context
:(NSString
*)context
155 epoch
:(unsigned long long)epoch
156 machineID
:(NSString
*)machineID
157 bottleSalt
:(NSString
*)bottleSalt
158 bottleID
:(NSString
*)bottleID
159 modelID
:(NSString
*)modelID
160 deviceName
:(nullable NSString
*)deviceName
161 serialNumber
:(NSString
*)serialNumber
162 osVersion
:(NSString
*)osVersion
163 policyVersion
:(nullable NSNumber
*)policyVersion
164 policySecrets
:(nullable NSDictionary
<NSString
*,NSData
*> *)policySecrets
165 signingPrivKeyPersistentRef
:(nullable NSData
*)spkPr
166 encPrivKeyPersistentRef
:(nullable NSData
*)epkPr
167 reply
:(void (^)(NSString
* _Nullable peerID
,
168 NSData
* _Nullable permanentInfo
,
169 NSData
* _Nullable permanentInfoSig
,
170 NSData
* _Nullable stableInfo
,
171 NSData
* _Nullable stableInfoSig
,
172 NSError
* _Nullable error
))reply
;
174 // If there already are existing CKKSViews, please pass in their key sets anyway.
175 // This function will create a self TLK Share for those TLKs.
176 - (void)establishWithContainer
:(NSString
*)container
177 context
:(NSString
*)context
178 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
179 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
180 preapprovedKeys
:(nullable NSArray
<NSData
*> *)preapprovedKeys
181 reply
:(void (^)(NSString
* _Nullable peerID
,
182 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
183 NSError
* _Nullable error
))reply
;
185 // Returns a voucher for the given peer ID using our own identity
186 // If TLK CKKSViewKeys are given, TLKShares will be created and uploaded for this new peer before this call returns.
187 - (void)vouchWithContainer
:(NSString
*)container
188 context
:(NSString
*)context
189 peerID
:(NSString
*)peerID
190 permanentInfo
:(NSData
*)permanentInfo
191 permanentInfoSig
:(NSData
*)permanentInfoSig
192 stableInfo
:(NSData
*)stableInfo
193 stableInfoSig
:(NSData
*)stableInfoSig
194 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
195 reply
:(void (^)(NSData
* _Nullable voucher
,
196 NSData
* _Nullable voucherSig
,
197 NSError
* _Nullable error
))reply
;
199 // Preflighting a vouch will return the peer ID associated with the bottle you will be recovering.
200 // You can then use that peer ID to filter the tlkshares provided to vouchWithBottle.
201 - (void)preflightVouchWithBottleWithContainer
:(NSString
*)container
202 context
:(NSString
*)context
203 bottleID
:(NSString
*)bottleID
204 reply
:(void (^)(NSString
* _Nullable peerID
,
205 NSError
* _Nullable error
))reply
;
207 // Returns a voucher for our own identity, created by the identity inside this bottle
208 - (void)vouchWithBottleWithContainer
:(NSString
*)container
209 context
:(NSString
*)context
210 bottleID
:(NSString
*)bottleID
211 entropy
:(NSData
*)entropy
212 bottleSalt
:(NSString
*)bottleSalt
213 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
214 reply
:(void (^)(NSData
* _Nullable voucher
,
215 NSData
* _Nullable voucherSig
,
216 NSError
* _Nullable error
))reply
;
218 // Returns a voucher for our own identity, using recovery key
219 - (void)vouchWithRecoveryKeyWithContainer
:(NSString
*)container
220 context
:(NSString
*)context
221 recoveryKey
:(NSString
*)recoveryKey
223 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
224 reply
:(void (^)(NSData
* _Nullable voucher
,
225 NSData
* _Nullable voucherSig
,
226 NSError
* _Nullable error
))reply
;
228 // As of right now, join and attemptPreapprovedJoin will upload TLKShares for any TLKs that this peer already has.
229 // Note that in The Future, a device might decide to join an existing Octagon set while introducing a new view.
230 // These interfaces will have to change...
231 - (void)joinWithContainer
:(NSString
*)container
232 context
:(NSString
*)context
233 voucherData
:(NSData
*)voucherData
234 voucherSig
:(NSData
*)voucherSig
235 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
236 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
237 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
238 reply
:(void (^)(NSString
* _Nullable peerID
,
239 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
240 NSError
* _Nullable error
))reply
;
242 // Preflighting a preapproved join suggests whether or not you expect to succeed in an immediate preapprovedJoin() call
243 // This only inspects the Octagon model, and ignores the trusted device list, so that you can preflight the preapprovedJoin()
244 // before fetching that list.
245 // This will return YES if there are no existing peers, or if the existing peers preapprove your prepared identity.
246 // This will return NO otherwise.
247 - (void)preflightPreapprovedJoinWithContainer
:(NSString
*)container
248 context
:(NSString
*)context
249 reply
:(void (^)(BOOL launchOkay
,
250 NSError
* _Nullable error
))reply
;
252 // A preapproved join might do a join, but it also might do an establish.
253 // Therefore, it needs all the TLKs and TLKShares as establish does
254 - (void)attemptPreapprovedJoinWithContainer
:(NSString
*)container
255 context
:(NSString
*)context
256 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
257 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
258 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
259 reply
:(void (^)(NSString
* _Nullable peerID
,
260 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
261 NSError
* _Nullable error
))reply
;
263 // TODO: if the new policy causes someone to lose access to a view, how should this API work?
264 - (void)updateWithContainer
:(NSString
*)container
265 context
:(NSString
*)context
266 deviceName
:(nullable NSString
*)deviceName
267 serialNumber
:(nullable NSString
*)serialNumber
268 osVersion
:(nullable NSString
*)osVersion
269 policyVersion
:(nullable NSNumber
*)policyVersion
270 policySecrets
:(nullable NSDictionary
<NSString
*,NSData
*> *)policySecrets
271 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable peerState
, NSError
* _Nullable error
))reply
;
273 - (void)setPreapprovedKeysWithContainer
:(NSString
*)container
274 context
:(NSString
*)context
275 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
276 reply
:(void (^)(NSError
* _Nullable error
))reply
;
278 /* Rather thin pass-through for uploading new TLKs (for zones which may have disappeared) */
279 - (void)updateTLKsWithContainer
:(NSString
*)container
280 context
:(NSString
*)context
281 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
282 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
283 reply
:(void (^)(NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
, NSError
* _Nullable error
))reply
;
285 - (void)fetchViableBottlesWithContainer
:(NSString
*)container
286 context
:(NSString
*)context
287 reply
:(void (^)(NSArray
<NSString
*>* _Nullable sortedBottleIDs
, NSArray
<NSString
*>* _Nullable sortedPartialBottleIDs
, NSError
* _Nullable error
))reply
;
289 - (void)fetchEscrowContentsWithContainer
:(NSString
*)container
290 context
:(NSString
*)context
291 reply
:(void (^)(NSData
* _Nullable entropy
,
292 NSString
* _Nullable bottleID
,
293 NSData
* _Nullable signingPublicKey
,
294 NSError
* _Nullable error
))reply
;
296 // The argument contains N [version:hash] keys,
297 // the reply block contains 0<=N [version:[hash, data]] entries.
298 - (void)fetchPolicyDocumentsWithContainer
:(NSString
*)container
299 context
:(NSString
*)context
300 keys
:(NSDictionary
<NSNumber
*,NSString
*>*)keys
301 reply
:(void (^)(NSDictionary
<NSNumber
*,NSArray
<NSString
*>*>* _Nullable entries
,
302 NSError
* _Nullable error
))reply
;
304 // Fetch the policy for current peer.
305 - (void)fetchPolicyWithContainer
:(NSString
*)container
306 context
:(NSString
*)context
307 reply
:(void (^)(TPPolicy
* _Nullable policy
,
308 NSError
* _Nullable error
))reply
;
310 - (void)validatePeersWithContainer
:(NSString
*)container
311 context
:(NSString
*)context
312 reply
:(void (^)(NSDictionary
* _Nullable
, NSError
* _Nullable
))reply
;
315 // TODO: merge this and trustStatusWithContainer
316 - (void)fetchTrustStateWithContainer
:(NSString
*)container
317 context
:(NSString
*)context
318 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable selfPeerState
,
319 NSArray
<TrustedPeersHelperPeer
*>* _Nullable trustedPeers
,
320 NSError
* _Nullable error
))reply
;
322 - (void)setRecoveryKeyWithContainer
:(NSString
*)container
323 context
:(NSString
*)context
324 recoveryKey
:(NSString
*)recoveryKey
325 salt
:(NSString
*)salt
326 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
327 reply
:(void (^)(NSError
* _Nullable error
))reply
;
329 - (void)reportHealthWithContainer
:(NSString
*)container
330 context
:(NSString
*)context
331 stateMachineState
:(NSString
*)state
332 trustState
:(NSString
*)trustState
333 reply
:(void (^)(NSError
* _Nullable error
))reply
;
335 - (void)pushHealthInquiryWithContainer
:(NSString
*)container
336 context
:(NSString
*)context
337 reply
:(void (^)(NSError
* _Nullable error
))reply
;
339 - (void)getViewsWithContainer
:(NSString
*)container
340 context
:(NSString
*)context
341 inViews
:(NSArray
<NSString
*>*)inViews
342 reply
:(void (^)(NSArray
<NSString
*>* _Nullable
, NSError
* _Nullable
))reply
;
344 - (void)requestHealthCheckWithContainer
:(NSString
*)container
345 context
:(NSString
*)context
346 requiresEscrowCheck
:(BOOL
)requiresEscrowCheck
347 reply
:(void (^)(BOOL postRepairCFU
, BOOL postEscrowCFU
, BOOL resetOctagon
, NSError
* _Nullable
))reply
;
349 - (void)getSupportAppInfoWithContainer
:(NSString
*)container
350 context
:(NSString
*)context
351 reply
:(void (^)(NSData
* _Nullable
, NSError
* _Nullable
))reply
;
356 To use the service from an application or other process, use NSXPCConnection to establish a connection to the service by doing something like this:
358 _connectionToService = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.TrustedPeersHelper"];
359 _connectionToService.remoteObjectInterface = TrustedPeersHelperSetupProtocol([NSXPCInterface interfaceWithProtocol:@protocol(TrustedPeersHelperProtocol)]);
360 [_connectionToService resume];
362 Once you have a connection to the service, you can use it like this:
364 [[_connectionToService remoteObjectProxy] upperCaseString:@"hello" withReply:^(NSString *aString) {
365 // We have received a response. Update our text field, but do it on the main thread.
366 NSLog(@"Result string was: %@", aString);
369 And, when you are finished with the service, clean up the connection like this:
371 [_connectionToService invalidate];
375 // Use this at protocol creation time to tell NSXPC to do its job
376 NSXPCInterface
* TrustedPeersHelperSetupProtocol(NSXPCInterface
* interface
);
378 NS_ASSUME_NONNULL_END