]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OctagonCKKSPeerAdapter.m
Security-59754.41.1.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
84 - (instancetype)initWithPeerID:(NSString*)peerID
85 containerName:(NSString*)containerName
86 contextID:(NSString*)contextID
87 cuttlefishXPC:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper
88 {
89 if((self = [super init])) {
90 _providerID = [NSString stringWithFormat:@"[OctagonCKKSPeerAdapter:%@]", peerID];
91 _peerID = peerID;
92
93 _containerName = containerName;
94 _contextID = contextID;
95 _cuttlefishXPCWrapper = cuttlefishXPCWrapper;
96
97 _peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-sos"];
98
99 // Octagon is king.
100 _essential = YES;
101 }
102 return self;
103 }
104
105 - (NSString*)description
106 {
107 return [NSString stringWithFormat:@"<OctagonCKKSPeerAdapter: %@ e:%d>", self.peerID, self.essential];
108 }
109
110 - (SFIdentity*)fetchIdentity:(NSString*)identifier error:(NSError *__autoreleasing _Nullable * _Nullable)error
111 {
112 // Async to sync again! No other option.
113 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
114 SFKeychainManager* keychainManager = [SFKeychainManager defaultOverCommitManager];
115
116 __block SFIdentity* identity = nil;
117 __block NSError* localError = nil;
118
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;
125 break;
126
127 case SFKeychainFetchResultTypeValueAvailable:
128 identity = result.value;
129 break;
130 }
131 dispatch_semaphore_signal(sema);
132 }];
133
134 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
135
136 if(error && localError) {
137 *error = localError;
138 }
139 return identity;
140 }
141
142 - (CKKSSelves * _Nullable)fetchSelfPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
143 {
144 if(self.peerID) {
145 // Shameless duplication of swift code in TPH. Thanks, perf team!
146 NSError* keychainError = nil;
147
148 SFIdentity* signingIdentity = [self fetchIdentity:[NSString stringWithFormat:@"signing-key %@", self.peerID] error:&keychainError];
149 if(!signingIdentity || keychainError) {
150 if(error) {
151 // TODO: ensure error exists
152 *error = keychainError;
153 }
154 return nil;
155 }
156
157 SFIdentity* encryptionIdentity = [self fetchIdentity:[NSString stringWithFormat:@"encryption-key %@", self.peerID] error:&keychainError];
158 if(!encryptionIdentity || keychainError) {
159 if(error) {
160 // TODO: ensure error exists
161 *error = keychainError;
162 }
163 return nil;
164 }
165
166 OctagonSelfPeer* selfPeer = [[OctagonSelfPeer alloc] initWithPeerID:self.peerID
167 signingIdentity:signingIdentity
168 encryptionIdentity:encryptionIdentity];
169
170 CKKSSelves* selves = [[CKKSSelves alloc] initWithCurrent:selfPeer allSelves:[NSSet set]];
171 return selves;
172 }
173
174 secnotice("octagon-ckks", "No peer ID; therefore no identity");
175 if(error) {
176 *error = [NSError errorWithDomain:OctagonErrorDomain
177 code:OTErrorNoIdentity
178 description:@"no peer ID present"];
179 }
180 return nil;
181 }
182
183 - (NSSet<id<CKKSRemotePeerProtocol>> * _Nullable)fetchTrustedPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
184 {
185 // TODO: make this memoized somehow, somewhere
186
187 __block NSError* localerror;
188 __block NSMutableSet<id<CKKSRemotePeerProtocol>> * peers = nil;
189
190 WEAKIFY(self);
191 [self.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.containerName
192 context:self.contextID
193 reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState,
194 NSArray<TrustedPeersHelperPeer *> * _Nullable trustedPeers,
195 NSError * _Nullable operror) {
196 STRONGIFY(self);
197 if(operror) {
198 secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.containerName, self.contextID, operror);
199 localerror = operror;
200
201 } else {
202 peers = [NSMutableSet set];
203
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];
208
209 CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID
210 encryptionPublicKey:encryptionKey
211 signingPublicKey:signingKey
212 viewList:peer.viewList];
213 [peers addObject:ckkspeer];
214 }
215 }
216 }];
217
218 if(error && localerror) {
219 *error = localerror;
220 }
221
222 return peers;
223 }
224
225 - (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
226 [self.peerChangeListeners registerListener:listener];
227 }
228
229 - (void)sendSelfPeerChangedUpdate {
230 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
231 [listener selfPeerChanged: self];
232 }];
233 }
234
235 - (void)sendTrustedPeerSetChangedUpdate {
236 [self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
237 [listener trustedPeerSetChanged: self];
238 }];
239 }
240
241 - (nonnull CKKSPeerProviderState *)currentState {
242 return [CKKSPeerProviderState createFromProvider:self];
243 }
244
245
246 @end
247
248 #endif // OCTAGON