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
;
72 @property BOOL isExcluded
;
73 @property BOOL isLocked
;
75 - (instancetype
)initWithEgoPeerID
:(NSString
* _Nullable
)egoPeerID
76 status
:(TPPeerStatus
)egoStatus
77 viablePeerCountsByModelID
:(NSDictionary
<NSString
*, NSNumber
*>*)viablePeerCountsByModelID
78 isExcluded
:(BOOL
)isExcluded
79 isLocked
:(BOOL
)isLocked
;
83 // This protocol describes the interface of the TrustedPeersHelper XPC service.
84 @protocol TrustedPeersHelperProtocol
86 // This is used by a unit test which exercises the XPC-service plumbing.
87 - (void)pingWithReply
:(void (^)(void))reply
;
89 - (void)dumpWithContainer
:(NSString
*)container
90 context
:(NSString
*)context
91 reply
:(void (^)(NSDictionary
* _Nullable
, NSError
* _Nullable
))reply
;
93 - (void)departByDistrustingSelfWithContainer
:(NSString
*)container
94 context
:(NSString
*)context
95 reply
:(void (^)(NSError
* _Nullable
))reply
;
97 - (void)distrustPeerIDsWithContainer
:(NSString
*)container
98 context
:(NSString
*)context
99 peerIDs
:(NSSet
<NSString
*>*)peerIDs
100 reply
:(void (^)(NSError
* _Nullable
))reply
;
102 - (void)trustStatusWithContainer
:(NSString
*)container
103 context
:(NSString
*)context
104 reply
:(void (^)(TrustedPeersHelperEgoPeerStatus
*status
,
105 NSError
* _Nullable error
))reply
;
107 - (void)resetWithContainer
:(NSString
*)container
108 context
:(NSString
*)context
109 resetReason
:(CuttlefishResetReason
)reason
110 reply
:(void (^)(NSError
* _Nullable error
))reply
;
112 - (void)localResetWithContainer
:(NSString
*)container
113 context
:(NSString
*)context
114 reply
:(void (^)(NSError
* _Nullable error
))reply
;
116 // The following three machine ID list manipulation functions do not attempt to apply the results to the model
117 // If you'd like that to occur, please call update()
119 // TODO: how should we communicate TLK rolling when the update() call will remove a peer?
120 // <rdar://problem/46633449> Octagon: must be able to roll TLKs when a peer departs due to machine ID list
122 // listDifferences: False if the allowedMachineIDs list passed in exactly matches the previous state,
123 // True if there were any differences
124 - (void)setAllowedMachineIDsWithContainer
:(NSString
*)container
125 context
:(NSString
*)context
126 allowedMachineIDs
:(NSSet
<NSString
*> *)allowedMachineIDs
127 reply
:(void (^)(BOOL listDifferences
, NSError
* _Nullable error
))reply
;
129 - (void)addAllowedMachineIDsWithContainer
:(NSString
*)container
130 context
:(NSString
*)context
131 machineIDs
:(NSArray
<NSString
*> *)machineIDs
132 reply
:(void (^)(NSError
* _Nullable error
))reply
;
134 - (void)removeAllowedMachineIDsWithContainer
:(NSString
*)container
135 context
:(NSString
*)context
136 machineIDs
:(NSArray
<NSString
*> *)machineIDs
137 reply
:(void (^)(NSError
* _Nullable error
))reply
;
139 - (void)fetchEgoEpochWithContainer
:(NSString
*)container
140 context
:(NSString
*)context
141 reply
:(void (^)(unsigned long long epoch
,
142 NSError
* _Nullable error
))reply
;
144 - (void)prepareWithContainer
:(NSString
*)container
145 context
:(NSString
*)context
146 epoch
:(unsigned long long)epoch
147 machineID
:(NSString
*)machineID
148 bottleSalt
:(NSString
*)bottleSalt
149 bottleID
:(NSString
*)bottleID
150 modelID
:(NSString
*)modelID
151 deviceName
:(nullable NSString
*)deviceName
152 serialNumber
:(NSString
*)serialNumber
153 osVersion
:(NSString
*)osVersion
154 policyVersion
:(nullable NSNumber
*)policyVersion
155 policySecrets
:(nullable NSDictionary
<NSString
*,NSData
*> *)policySecrets
156 signingPrivKeyPersistentRef
:(nullable NSData
*)spkPr
157 encPrivKeyPersistentRef
:(nullable NSData
*)epkPr
158 reply
:(void (^)(NSString
* _Nullable peerID
,
159 NSData
* _Nullable permanentInfo
,
160 NSData
* _Nullable permanentInfoSig
,
161 NSData
* _Nullable stableInfo
,
162 NSData
* _Nullable stableInfoSig
,
163 NSError
* _Nullable error
))reply
;
165 // If there already are existing CKKSViews, please pass in their key sets anyway.
166 // This function will create a self TLK Share for those TLKs.
167 - (void)establishWithContainer
:(NSString
*)container
168 context
:(NSString
*)context
169 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
170 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
171 preapprovedKeys
:(nullable NSArray
<NSData
*> *)preapprovedKeys
172 reply
:(void (^)(NSString
* _Nullable peerID
,
173 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
174 NSError
* _Nullable error
))reply
;
176 // Returns a voucher for the given peer ID using our own identity
177 // If TLK CKKSViewKeys are given, TLKShares will be created and uploaded for this new peer before this call returns.
178 - (void)vouchWithContainer
:(NSString
*)container
179 context
:(NSString
*)context
180 peerID
:(NSString
*)peerID
181 permanentInfo
:(NSData
*)permanentInfo
182 permanentInfoSig
:(NSData
*)permanentInfoSig
183 stableInfo
:(NSData
*)stableInfo
184 stableInfoSig
:(NSData
*)stableInfoSig
185 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
186 reply
:(void (^)(NSData
* _Nullable voucher
,
187 NSData
* _Nullable voucherSig
,
188 NSError
* _Nullable error
))reply
;
190 // Preflighting a vouch will return the peer ID associated with the bottle you will be recovering.
191 // You can then use that peer ID to filter the tlkshares provided to vouchWithBottle.
192 - (void)preflightVouchWithBottleWithContainer
:(NSString
*)container
193 context
:(NSString
*)context
194 bottleID
:(NSString
*)bottleID
195 reply
:(void (^)(NSString
* _Nullable peerID
,
196 NSError
* _Nullable error
))reply
;
198 // Returns a voucher for our own identity, created by the identity inside this bottle
199 - (void)vouchWithBottleWithContainer
:(NSString
*)container
200 context
:(NSString
*)context
201 bottleID
:(NSString
*)bottleID
202 entropy
:(NSData
*)entropy
203 bottleSalt
:(NSString
*)bottleSalt
204 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
205 reply
:(void (^)(NSData
* _Nullable voucher
,
206 NSData
* _Nullable voucherSig
,
207 NSError
* _Nullable error
))reply
;
209 // Returns a voucher for our own identity, using recovery key
210 - (void)vouchWithRecoveryKeyWithContainer
:(NSString
*)container
211 context
:(NSString
*)context
212 recoveryKey
:(NSString
*)recoveryKey
214 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
215 reply
:(void (^)(NSData
* _Nullable voucher
,
216 NSData
* _Nullable voucherSig
,
217 NSError
* _Nullable error
))reply
;
219 // As of right now, join and attemptPreapprovedJoin will upload TLKShares for any TLKs that this peer already has.
220 // Note that in The Future, a device might decide to join an existing Octagon set while introducing a new view.
221 // These interfaces will have to change...
222 - (void)joinWithContainer
:(NSString
*)container
223 context
:(NSString
*)context
224 voucherData
:(NSData
*)voucherData
225 voucherSig
:(NSData
*)voucherSig
226 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)viewKeySets
227 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
228 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
229 reply
:(void (^)(NSString
* _Nullable peerID
,
230 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
231 NSError
* _Nullable error
))reply
;
233 // Preflighting a preapproved join suggests whether or not you expect to succeed in an immediate preapprovedJoin() call
234 // This only inspects the Octagon model, and ignores the trusted device list, so that you can preflight the preapprovedJoin()
235 // before fetching that list.
236 // This will return YES if there are no existing peers, or if the existing peers preapprove your prepared identity.
237 // This will return NO otherwise.
238 - (void)preflightPreapprovedJoinWithContainer
:(NSString
*)container
239 context
:(NSString
*)context
240 reply
:(void (^)(BOOL launchOkay
,
241 NSError
* _Nullable error
))reply
;
243 // A preapproved join might do a join, but it also might do an establish.
244 // Therefore, it needs all the TLKs and TLKShares as establish does
245 - (void)attemptPreapprovedJoinWithContainer
:(NSString
*)container
246 context
:(NSString
*)context
247 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
248 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
249 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
250 reply
:(void (^)(NSString
* _Nullable peerID
,
251 NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
,
252 NSError
* _Nullable error
))reply
;
254 // TODO: if the new policy causes someone to lose access to a view, how should this API work?
255 - (void)updateWithContainer
:(NSString
*)container
256 context
:(NSString
*)context
257 deviceName
:(nullable NSString
*)deviceName
258 serialNumber
:(nullable NSString
*)serialNumber
259 osVersion
:(nullable NSString
*)osVersion
260 policyVersion
:(nullable NSNumber
*)policyVersion
261 policySecrets
:(nullable NSDictionary
<NSString
*,NSData
*> *)policySecrets
262 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable peerState
, NSError
* _Nullable error
))reply
;
264 - (void)setPreapprovedKeysWithContainer
:(NSString
*)container
265 context
:(NSString
*)context
266 preapprovedKeys
:(NSArray
<NSData
*> *)preapprovedKeys
267 reply
:(void (^)(NSError
* _Nullable error
))reply
;
269 /* Rather thin pass-through for uploading new TLKs (for zones which may have disappeared) */
270 - (void)updateTLKsWithContainer
:(NSString
*)container
271 context
:(NSString
*)context
272 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
273 tlkShares
:(NSArray
<CKKSTLKShare
*> *)tlkShares
274 reply
:(void (^)(NSArray
<CKRecord
*>* _Nullable keyHierarchyRecords
, NSError
* _Nullable error
))reply
;
276 - (void)fetchViableBottlesWithContainer
:(NSString
*)container
277 context
:(NSString
*)context
278 reply
:(void (^)(NSArray
<NSString
*>* _Nullable sortedBottleIDs
, NSArray
<NSString
*>* _Nullable sortedPartialBottleIDs
, NSError
* _Nullable error
))reply
;
280 - (void)fetchEscrowContentsWithContainer
:(NSString
*)container
281 context
:(NSString
*)context
282 reply
:(void (^)(NSData
* _Nullable entropy
,
283 NSString
* _Nullable bottleID
,
284 NSData
* _Nullable signingPublicKey
,
285 NSError
* _Nullable error
))reply
;
287 // The argument contains N [version:hash] keys,
288 // the reply block contains 0<=N [version:[hash, data]] entries.
289 - (void)fetchPolicyDocumentsWithContainer
:(NSString
*)container
290 context
:(NSString
*)context
291 keys
:(NSDictionary
<NSNumber
*,NSString
*>*)keys
292 reply
:(void (^)(NSDictionary
<NSNumber
*,NSArray
<NSString
*>*>* _Nullable entries
,
293 NSError
* _Nullable error
))reply
;
295 // Fetch the policy for current peer.
296 - (void)fetchPolicyWithContainer
:(NSString
*)container
297 context
:(NSString
*)context
298 reply
:(void (^)(TPPolicy
* _Nullable policy
,
299 NSError
* _Nullable error
))reply
;
301 - (void)validatePeersWithContainer
:(NSString
*)container
302 context
:(NSString
*)context
303 reply
:(void (^)(NSDictionary
* _Nullable
, NSError
* _Nullable
))reply
;
306 // TODO: merge this and trustStatusWithContainer
307 - (void)fetchTrustStateWithContainer
:(NSString
*)container
308 context
:(NSString
*)context
309 reply
:(void (^)(TrustedPeersHelperPeerState
* _Nullable selfPeerState
,
310 NSArray
<TrustedPeersHelperPeer
*>* _Nullable trustedPeers
,
311 NSError
* _Nullable error
))reply
;
313 - (void)setRecoveryKeyWithContainer
:(NSString
*)container
314 context
:(NSString
*)context
315 recoveryKey
:(NSString
*)recoveryKey
316 salt
:(NSString
*)salt
317 ckksKeys
:(NSArray
<CKKSKeychainBackedKeySet
*> *)ckksKeys
318 reply
:(void (^)(NSError
* _Nullable error
))reply
;
320 - (void)reportHealthWithContainer
:(NSString
*)container
321 context
:(NSString
*)context
322 stateMachineState
:(NSString
*)state
323 trustState
:(NSString
*)trustState
324 reply
:(void (^)(NSError
* _Nullable error
))reply
;
326 - (void)pushHealthInquiryWithContainer
:(NSString
*)container
327 context
:(NSString
*)context
328 reply
:(void (^)(NSError
* _Nullable error
))reply
;
330 - (void)getViewsWithContainer
:(NSString
*)container
331 context
:(NSString
*)context
332 inViews
:(NSArray
<NSString
*>*)inViews
333 reply
:(void (^)(NSArray
<NSString
*>* _Nullable
, NSError
* _Nullable
))reply
;
335 - (void)requestHealthCheckWithContainer
:(NSString
*)container
336 context
:(NSString
*)context
337 requiresEscrowCheck
:(BOOL
)requiresEscrowCheck
338 reply
:(void (^)(BOOL postRepairCFU
, BOOL postEscrowCFU
, BOOL resetOctagon
, NSError
* _Nullable
))reply
;
342 To use the service from an application or other process, use NSXPCConnection to establish a connection to the service by doing something like this:
344 _connectionToService = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.TrustedPeersHelper"];
345 _connectionToService.remoteObjectInterface = TrustedPeersHelperSetupProtocol([NSXPCInterface interfaceWithProtocol:@protocol(TrustedPeersHelperProtocol)]);
346 [_connectionToService resume];
348 Once you have a connection to the service, you can use it like this:
350 [[_connectionToService remoteObjectProxy] upperCaseString:@"hello" withReply:^(NSString *aString) {
351 // We have received a response. Update our text field, but do it on the main thread.
352 NSLog(@"Result string was: %@", aString);
355 And, when you are finished with the service, clean up the connection like this:
357 [_connectionToService invalidate];
361 // Use this at protocol creation time to tell NSXPC to do its job
362 NSXPCInterface
* TrustedPeersHelperSetupProtocol(NSXPCInterface
* interface
);
364 NS_ASSUME_NONNULL_END