]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OctagonCKKSPeerAdapter.m
Security-59306.41.2.tar.gz
[apple/security.git] / keychain / ot / OctagonCKKSPeerAdapter.m
1
2 #if OCTAGON
3
4 #import <SecurityFoundation/SecurityFoundation.h>
5 #import <SecurityFoundation/SFIdentity.h>
6
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"
13
14 #import "keychain/ot/ObjCImprovements.h"
15 #import "utilities/debugging.h"
16 #import "keychain/categories/NSError+UsefulConstructors.h"
17
18 @interface OctagonSelfPeer ()
19 @property SFIdentity* encryptionIdentity;
20 @property SFIdentity* signingIdentity;
21 @end
22
23 @implementation OctagonSelfPeer
24 @synthesize peerID = _peerID;
25
26 - (instancetype)initWithPeerID:(NSString*)peerID
27 signingIdentity:(SFIdentity*)signingIdentity
28 encryptionIdentity:(SFIdentity*)encryptionIdentity
29 {
30 if((self = [super init])) {
31 _peerID = peerID;
32 _signingIdentity = signingIdentity;
33 _encryptionIdentity = encryptionIdentity;
34 }
35 return self;
36 }
37
38 - (NSString*)description
39 {
40 return [NSString stringWithFormat:@"<OctagonSelfPeer: %@>", self.peerID];
41 }
42
43 - (SFECPublicKey*)publicEncryptionKey
44 {
45 return self.encryptionIdentity.publicKey;
46 }
47
48 - (SFECPublicKey*)publicSigningKey
49 {
50 return self.signingIdentity.publicKey;
51 }
52
53 - (SFECKeyPair*)encryptionKey
54 {
55 return self.encryptionIdentity.keyPair;
56 }
57
58 - (SFECKeyPair*)signingKey
59 {
60 return self.signingIdentity.keyPair;
61 }
62
63 - (bool)matchesPeer:(nonnull id<CKKSPeer>)peer {
64 NSString* otherPeerID = peer.peerID;
65
66 if(self.peerID == nil && otherPeerID == nil) {
67 return true;
68 }
69
70 return [self.peerID isEqualToString:otherPeerID];
71 }
72
73 @end
74
75 @interface OctagonCKKSPeerAdapter ()
76 @property CKKSListenerCollection* peerChangeListeners;
77 @end
78
79 @implementation OctagonCKKSPeerAdapter
80 @synthesize essential = _essential;
81 @synthesize providerID = _providerID;
82
83 - (instancetype)initWithPeerID:(NSString*)peerID operationDependencies:(OTOperationDependencies*)deps
84 {
85 if((self = [super init])) {
86 _providerID = [NSString stringWithFormat:@"[OctagonCKKSPeerAdapter:%@]", peerID];
87 _peerID = peerID;
88 _deps = deps;
89
90 _peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-sos"];
91
92 // Octagon is king.
93 _essential = YES;
94 }
95 return self;
96 }
97
98 - (NSString*)description
99 {
100 return [NSString stringWithFormat:@"<OctagonCKKSPeerAdapter: %@ e:%d>", self.peerID, self.essential];
101 }
102
103 - (SFIdentity*)fetchIdentity:(NSString*)identifier error:(NSError *__autoreleasing _Nullable * _Nullable)error
104 {
105 // Async to sync again! No other option.
106 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
107 SFKeychainManager* keychainManager = [SFKeychainManager defaultManager];
108
109 __block SFIdentity* identity = nil;
110 __block NSError* localError = nil;
111
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;
118 break;
119
120 case SFKeychainFetchResultTypeValueAvailable:
121 identity = result.value;
122 break;
123 }
124 dispatch_semaphore_signal(sema);
125 }];
126
127 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
128
129 if(error && localError) {
130 *error = localError;
131 }
132 return identity;
133 }
134
135 - (CKKSSelves * _Nullable)fetchSelfPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
136 {
137 if(self.peerID) {
138 // Shameless duplication of swift code in TPH. Thanks, perf team!
139 NSError* keychainError = nil;
140
141 SFIdentity* signingIdentity = [self fetchIdentity:[NSString stringWithFormat:@"signing-key %@", self.peerID] error:&keychainError];
142 if(!signingIdentity || keychainError) {
143 if(error) {
144 // TODO: ensure error exists
145 *error = keychainError;
146 }
147 return nil;
148 }
149
150 SFIdentity* encryptionIdentity = [self fetchIdentity:[NSString stringWithFormat:@"encryption-key %@", self.peerID] error:&keychainError];
151 if(!encryptionIdentity || keychainError) {
152 if(error) {
153 // TODO: ensure error exists
154 *error = keychainError;
155 }
156 return nil;
157 }
158
159 OctagonSelfPeer* selfPeer = [[OctagonSelfPeer alloc] initWithPeerID:self.peerID
160 signingIdentity:signingIdentity
161 encryptionIdentity:encryptionIdentity];
162
163 CKKSSelves* selves = [[CKKSSelves alloc] initWithCurrent:selfPeer allSelves:[NSSet set]];
164 return selves;
165 }
166
167 secnotice("octagon-ckks", "No peer ID; therefore no identity");
168 if(error) {
169 *error = [NSError errorWithDomain:OctagonErrorDomain
170 code:OTErrorNoIdentity
171 description:@"no peer ID present"];
172 }
173 return nil;
174 }
175
176 - (NSSet<id<CKKSRemotePeerProtocol>> * _Nullable)fetchTrustedPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
177 {
178 // TODO: make this memoized somehow, somewhere
179
180 __block NSError* localerror;
181 __block NSMutableSet<id<CKKSRemotePeerProtocol>> * peers = nil;
182
183 WEAKIFY(self);
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) {
189 STRONGIFY(self);
190 if(operror) {
191 secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror);
192 localerror = operror;
193
194 } else {
195 peers = [NSMutableSet set];
196
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];
201
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);
207
208 [peers addObject:ckkspeer];
209 }
210 }
211 }];
212
213 if(error && localerror) {
214 *error = localerror;
215 }
216
217 return peers;
218 }
219
220 - (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
221 [self.peerChangeListeners registerListener:listener];
222 }
223
224 - (void)sendSelfPeerChangedUpdate {
225 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
226 [listener selfPeerChanged: self];
227 }];
228 }
229
230 - (void)sendTrustedPeerSetChangedUpdate {
231 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
232 [listener trustedPeerSetChanged: self];
233 }];
234 }
235
236 - (nonnull CKKSPeerProviderState *)currentState {
237 return [CKKSPeerProviderState createFromProvider:self];
238 }
239
240
241 @end
242
243 #endif // OCTAGON