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