4 #import <SecurityFoundation/SecurityFoundation.h>
5 #import <SecurityFoundation/SFIdentity.h>
7 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
8 #import "keychain/ot/OctagonCKKSPeerAdapter.h"
9 #import "keychain/ot/OTDefines.h"
10 #import "keychain/ot/OTConstants.h"
11 #import "keychain/ckks/CKKSPeer.h"
12 #import "keychain/ckks/CKKSListenerCollection.h"
14 #import "keychain/ot/ObjCImprovements.h"
15 #import "utilities/debugging.h"
16 #import "keychain/categories/NSError+UsefulConstructors.h"
18 @interface OctagonSelfPeer ()
19 @property SFIdentity* encryptionIdentity;
20 @property SFIdentity* signingIdentity;
23 @implementation OctagonSelfPeer
24 @synthesize peerID = _peerID;
26 - (instancetype)initWithPeerID:(NSString*)peerID
27 signingIdentity:(SFIdentity*)signingIdentity
28 encryptionIdentity:(SFIdentity*)encryptionIdentity
30 if((self = [super init])) {
32 _signingIdentity = signingIdentity;
33 _encryptionIdentity = encryptionIdentity;
38 - (NSString*)description
40 return [NSString stringWithFormat:@"<OctagonSelfPeer: %@>", self.peerID];
43 - (SFECPublicKey*)publicEncryptionKey
45 return self.encryptionIdentity.publicKey;
48 - (SFECPublicKey*)publicSigningKey
50 return self.signingIdentity.publicKey;
53 - (SFECKeyPair*)encryptionKey
55 return self.encryptionIdentity.keyPair;
58 - (SFECKeyPair*)signingKey
60 return self.signingIdentity.keyPair;
63 - (bool)matchesPeer:(nonnull id<CKKSPeer>)peer {
64 NSString* otherPeerID = peer.peerID;
66 if(self.peerID == nil && otherPeerID == nil) {
70 return [self.peerID isEqualToString:otherPeerID];
75 @interface OctagonCKKSPeerAdapter ()
76 @property CKKSListenerCollection* peerChangeListeners;
79 @implementation OctagonCKKSPeerAdapter
80 @synthesize essential = _essential;
81 @synthesize providerID = _providerID;
84 - (instancetype)initWithPeerID:(NSString*)peerID
85 containerName:(NSString*)containerName
86 contextID:(NSString*)contextID
87 cuttlefishXPC:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper
89 if((self = [super init])) {
90 _providerID = [NSString stringWithFormat:@"[OctagonCKKSPeerAdapter:%@]", peerID];
93 _containerName = containerName;
94 _contextID = contextID;
95 _cuttlefishXPCWrapper = cuttlefishXPCWrapper;
97 _peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-sos"];
105 - (NSString*)description
107 return [NSString stringWithFormat:@"<OctagonCKKSPeerAdapter: %@ e:%d>", self.peerID, self.essential];
110 - (SFIdentity*)fetchIdentity:(NSString*)identifier error:(NSError *__autoreleasing _Nullable * _Nullable)error
112 // Async to sync again! No other option.
113 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
114 SFKeychainManager* keychainManager = [SFKeychainManager defaultOverCommitManager];
116 __block SFIdentity* identity = nil;
117 __block NSError* localError = nil;
119 [keychainManager identityForIdentifier:identifier resultHandler:^(SFKeychainIdentityFetchResult * _Nonnull result) {
120 switch(result.resultType) {
121 case SFKeychainFetchResultTypeError:
122 case SFKeychainFetchResultTypeNeedsAuthentication:
123 secnotice("octagon-ckks", "Unable to fetch identity '%@' from keychain: %@", identifier, result.error);
124 localError = result.error;
127 case SFKeychainFetchResultTypeValueAvailable:
128 identity = result.value;
131 dispatch_semaphore_signal(sema);
134 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
136 if(error && localError) {
142 - (CKKSSelves * _Nullable)fetchSelfPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
145 // Shameless duplication of swift code in TPH. Thanks, perf team!
146 NSError* keychainError = nil;
148 SFIdentity* signingIdentity = [self fetchIdentity:[NSString stringWithFormat:@"signing-key %@", self.peerID] error:&keychainError];
149 if(!signingIdentity || keychainError) {
151 // TODO: ensure error exists
152 *error = keychainError;
157 SFIdentity* encryptionIdentity = [self fetchIdentity:[NSString stringWithFormat:@"encryption-key %@", self.peerID] error:&keychainError];
158 if(!encryptionIdentity || keychainError) {
160 // TODO: ensure error exists
161 *error = keychainError;
166 OctagonSelfPeer* selfPeer = [[OctagonSelfPeer alloc] initWithPeerID:self.peerID
167 signingIdentity:signingIdentity
168 encryptionIdentity:encryptionIdentity];
170 CKKSSelves* selves = [[CKKSSelves alloc] initWithCurrent:selfPeer allSelves:[NSSet set]];
174 secnotice("octagon-ckks", "No peer ID; therefore no identity");
176 *error = [NSError errorWithDomain:OctagonErrorDomain
177 code:OTErrorNoIdentity
178 description:@"no peer ID present"];
183 - (NSSet<id<CKKSRemotePeerProtocol>> * _Nullable)fetchTrustedPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
185 // TODO: make this memoized somehow, somewhere
187 __block NSError* localerror;
188 __block NSMutableSet<id<CKKSRemotePeerProtocol>> * peers = nil;
191 [self.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.containerName
192 context:self.contextID
193 reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState,
194 NSArray<TrustedPeersHelperPeer *> * _Nullable trustedPeers,
195 NSError * _Nullable operror) {
198 secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.containerName, self.contextID, operror);
199 localerror = operror;
202 peers = [NSMutableSet set];
204 // Turn these peers into CKKSPeers
205 for(TrustedPeersHelperPeer* peer in trustedPeers) {
206 SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI];
207 SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI];
209 CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID
210 encryptionPublicKey:encryptionKey
211 signingPublicKey:signingKey
212 viewList:peer.viewList];
213 [peers addObject:ckkspeer];
218 if(error && localerror) {
225 - (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
226 [self.peerChangeListeners registerListener:listener];
229 - (void)sendSelfPeerChangedUpdate {
230 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
231 [listener selfPeerChanged: self];
235 - (void)sendTrustedPeerSetChangedUpdate {
236 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
237 [listener trustedPeerSetChanged: self];
241 - (nonnull CKKSPeerProviderState *)currentState {
242 return [CKKSPeerProviderState createFromProvider:self];