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;
83 - (instancetype)initWithPeerID:(NSString*)peerID operationDependencies:(OTOperationDependencies*)deps
85 if((self = [super init])) {
86 _providerID = [NSString stringWithFormat:@"[OctagonCKKSPeerAdapter:%@]", peerID];
90 _peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-sos"];
98 - (NSString*)description
100 return [NSString stringWithFormat:@"<OctagonCKKSPeerAdapter: %@ e:%d>", self.peerID, self.essential];
103 - (SFIdentity*)fetchIdentity:(NSString*)identifier error:(NSError *__autoreleasing _Nullable * _Nullable)error
105 // Async to sync again! No other option.
106 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
107 SFKeychainManager* keychainManager = [SFKeychainManager defaultOverCommitManager];
109 __block SFIdentity* identity = nil;
110 __block NSError* localError = nil;
112 [keychainManager identityForIdentifier:identifier resultHandler:^(SFKeychainIdentityFetchResult * _Nonnull result) {
113 switch(result.resultType) {
114 case SFKeychainFetchResultTypeError:
115 case SFKeychainFetchResultTypeNeedsAuthentication:
116 secnotice("octagon-ckks", "Unable to fetch identity '%@' from keychain: %@", identifier, result.error);
117 localError = result.error;
120 case SFKeychainFetchResultTypeValueAvailable:
121 identity = result.value;
124 dispatch_semaphore_signal(sema);
127 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
129 if(error && localError) {
135 - (CKKSSelves * _Nullable)fetchSelfPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
138 // Shameless duplication of swift code in TPH. Thanks, perf team!
139 NSError* keychainError = nil;
141 SFIdentity* signingIdentity = [self fetchIdentity:[NSString stringWithFormat:@"signing-key %@", self.peerID] error:&keychainError];
142 if(!signingIdentity || keychainError) {
144 // TODO: ensure error exists
145 *error = keychainError;
150 SFIdentity* encryptionIdentity = [self fetchIdentity:[NSString stringWithFormat:@"encryption-key %@", self.peerID] error:&keychainError];
151 if(!encryptionIdentity || keychainError) {
153 // TODO: ensure error exists
154 *error = keychainError;
159 OctagonSelfPeer* selfPeer = [[OctagonSelfPeer alloc] initWithPeerID:self.peerID
160 signingIdentity:signingIdentity
161 encryptionIdentity:encryptionIdentity];
163 CKKSSelves* selves = [[CKKSSelves alloc] initWithCurrent:selfPeer allSelves:[NSSet set]];
167 secnotice("octagon-ckks", "No peer ID; therefore no identity");
169 *error = [NSError errorWithDomain:OctagonErrorDomain
170 code:OTErrorNoIdentity
171 description:@"no peer ID present"];
176 - (NSSet<id<CKKSRemotePeerProtocol>> * _Nullable)fetchTrustedPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
178 // TODO: make this memoized somehow, somewhere
180 __block NSError* localerror;
181 __block NSMutableSet<id<CKKSRemotePeerProtocol>> * peers = nil;
184 [self.deps.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.deps.containerName
185 context:self.deps.contextID
186 reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState,
187 NSArray<TrustedPeersHelperPeer *> * _Nullable trustedPeers,
188 NSError * _Nullable operror) {
191 secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror);
192 localerror = operror;
195 peers = [NSMutableSet set];
197 // Turn these peers into CKKSPeers
198 for(TrustedPeersHelperPeer* peer in trustedPeers) {
199 SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI];
200 SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI];
202 CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID
203 encryptionPublicKey:encryptionKey
204 signingPublicKey:signingKey
205 viewList:peer.viewList];
206 secnotice("octagon", "Have trusted peer %@", ckkspeer);
208 [peers addObject:ckkspeer];
213 if(error && localerror) {
220 - (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
221 [self.peerChangeListeners registerListener:listener];
224 - (void)sendSelfPeerChangedUpdate {
225 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
226 [listener selfPeerChanged: self];
230 - (void)sendTrustedPeerSetChangedUpdate {
231 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
232 [listener trustedPeerSetChanged: self];
236 - (nonnull CKKSPeerProviderState *)currentState {
237 return [CKKSPeerProviderState createFromProvider:self];