2 #import "keychain/ckks/CKKS.h"
3 #import "keychain/ckks/CKKSKey.h"
4 #import "keychain/ckks/CKKSPeerProvider.h"
5 #import "keychain/ckks/CKKSTLKShareRecord.h"
6 #import "keychain/categories/NSError+UsefulConstructors.h"
8 @implementation CKKSPeerProviderState
9 - (instancetype)initWithPeerProviderID:(NSString*)providerID
10 essential:(BOOL)essential
11 selfPeers:(CKKSSelves* _Nullable)selfPeers
12 selfPeersError:(NSError* _Nullable)selfPeersError
13 trustedPeers:(NSSet<id<CKKSRemotePeerProtocol>>* _Nullable)currentTrustedPeers
14 trustedPeersError:(NSError* _Nullable)trustedPeersError
16 if((self = [super init])) {
17 _peerProviderID = providerID;
18 _essential = essential;
19 _currentSelfPeers = selfPeers;
20 _currentSelfPeersError = selfPeersError;
21 _currentTrustedPeers = currentTrustedPeers;
22 _currentTrustedPeersError = trustedPeersError;
24 if(_currentTrustedPeers) {
25 NSMutableSet<NSString*>* trustedPeerIDs = [NSMutableSet set];
26 for(id<CKKSPeer> peer in _currentTrustedPeers) {
27 [trustedPeerIDs addObject:peer.peerID];
29 _currentTrustedPeerIDs = trustedPeerIDs;
35 - (NSString*)description
37 return [NSString stringWithFormat:@"<CKKSPeerProviderState(%@): %@%@ %@%@>",
39 self.currentSelfPeers,
40 self.currentSelfPeersError ?: @"",
41 self.currentTrustedPeers,
42 self.currentTrustedPeersError ?: @""];
45 + (CKKSPeerProviderState*)noPeersState:(id<CKKSPeerProvider>)provider
47 return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID
48 essential:provider.essential
50 selfPeersError:[NSError errorWithDomain:CKKSErrorDomain
51 code:CKKSNoPeersAvailable
52 description:@"No current self peer available"]
54 trustedPeersError:[NSError errorWithDomain:CKKSErrorDomain
55 code:CKKSNoPeersAvailable
56 description:@"No current trusted peers available"]];
60 + (CKKSPeerProviderState*)createFromProvider:(id<CKKSPeerProvider>)provider
62 NSError* selfPeersError = nil;
63 CKKSSelves* currentSelfPeers = [provider fetchSelfPeers:&selfPeersError];
65 NSError* trustedPeersError = nil;
66 NSSet<id<CKKSRemotePeerProtocol>>* currentTrustedPeers = [provider fetchTrustedPeers:&trustedPeersError];
68 return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID
69 essential:provider.essential
70 selfPeers:currentSelfPeers
71 selfPeersError:selfPeersError
72 trustedPeers:currentTrustedPeers
73 trustedPeersError:trustedPeersError];
76 // For this key, who doesn't yet have a valid CKKSTLKShare for it?
77 // Note that we really want a record sharing the TLK to ourselves, so this function might return
78 // a non-empty set even if all peers have the TLK: it wants us to make a record for ourself.
79 - (NSSet<id<CKKSPeer>>* _Nullable)findPeersMissingTLKSharesFor:(CKKSCurrentKeySet*)keyset
80 error:(NSError**)error
82 if(self.currentTrustedPeersError) {
83 ckkserror("ckksshare", keyset.tlk, "Couldn't find missing shares because trusted peers aren't available: %@", self.currentTrustedPeersError);
85 *error = self.currentTrustedPeersError;
89 if(self.currentSelfPeersError) {
90 ckkserror("ckksshare", keyset.tlk, "Couldn't find missing shares because self peers aren't available: %@", self.currentSelfPeersError);
92 *error = self.currentSelfPeersError;
97 NSArray<CKKSTLKShareRecord*>* tlkShares = [keyset.tlkShares arrayByAddingObjectsFromArray:keyset.pendingTLKShares ?: @[]];
99 NSMutableSet<id<CKKSPeer>>* peersMissingShares = [NSMutableSet set];
101 // Ensure that the 'self peer' is one of the current trusted peers. Otherwise, any TLKShare we create
102 // won't be considered trusted the next time through...
103 if(![self.currentTrustedPeerIDs containsObject:self.currentSelfPeers.currentSelf.peerID]) {
104 ckkserror("ckksshare", keyset.tlk, "current self peer (%@) is not in the set of trusted peers: %@",
105 self.currentSelfPeers.currentSelf.peerID,
106 self.currentTrustedPeerIDs);
109 *error = [NSError errorWithDomain:CKKSErrorDomain
110 code:CKKSLackingTrust
111 description:[NSString stringWithFormat:@"current self peer (%@) is not in the set of trusted peers",
112 self.currentSelfPeers.currentSelf.peerID]];
118 for(id<CKKSRemotePeerProtocol> peer in self.currentTrustedPeers) {
119 if(![peer shouldHaveView:keyset.tlk.zoneName]) {
120 ckkserror("ckksshare", keyset.tlk.keycore.zoneID, "Peer (%@) is not supposed to have view, skipping", peer);
124 // Determine if we think this peer has enough things shared to them
125 bool alreadyShared = false;
126 for(CKKSTLKShareRecord* existingShare in tlkShares) {
127 // Ensure this share is to this peer...
128 if(![existingShare.share.receiverPeerID isEqualToString:peer.peerID]) {
132 // If an SOS Peer sent this share, is its signature still valid? Or did the signing key change?
133 if([existingShare.senderPeerID hasPrefix:CKKSSOSPeerPrefix]) {
134 NSError* signatureError = nil;
135 if(![existingShare signatureVerifiesWithPeerSet:self.currentTrustedPeers error:&signatureError]) {
136 ckksnotice("ckksshare", keyset.tlk, "Existing TLKShare's signature doesn't verify with current peer set: %@ %@", signatureError, existingShare);
141 if([existingShare.tlkUUID isEqualToString:keyset.tlk.uuid] && [self.currentTrustedPeerIDs containsObject:existingShare.senderPeerID]) {
142 // Was this shared to us?
143 if([peer.peerID isEqualToString:self.currentSelfPeers.currentSelf.peerID]) {
144 // We only count this as 'found' if we did the sharing and it's to our current keys
145 NSData* currentKey = self.currentSelfPeers.currentSelf.publicEncryptionKey.keyData;
147 if([existingShare.senderPeerID isEqualToString:self.currentSelfPeers.currentSelf.peerID] &&
148 [existingShare.share.receiverPublicEncryptionKeySPKI isEqual:currentKey]) {
149 ckksnotice("ckksshare", keyset.tlk, "Local peer %@ is shared %@ via self: %@", peer, keyset.tlk, existingShare);
150 alreadyShared = true;
153 ckksnotice("ckksshare", keyset.tlk, "Local peer %@ is shared %@ via trusted %@, but that's not good enough", peer, keyset.tlk, existingShare);
157 // Was this shared to the remote peer's current keys?
158 NSData* currentKeySPKI = peer.publicEncryptionKey.keyData;
160 if([existingShare.share.receiverPublicEncryptionKeySPKI isEqual:currentKeySPKI]) {
161 // Some other peer has a trusted share. Cool!
162 ckksnotice("ckksshare", keyset.tlk, "Peer %@ is shared %@ via trusted %@", peer, keyset.tlk, existingShare);
163 alreadyShared = true;
166 ckksnotice("ckksshare", keyset.tlk, "Peer %@ has a share for %@, but to old keys: %@", peer, keyset.tlk, existingShare);
173 // Add this peer to our set, if it has an encryption key to receive the share
174 if(peer.publicEncryptionKey) {
175 [peersMissingShares addObject:peer];
180 if(peersMissingShares.count > 0u) {
181 // Log each and every one of the things
182 ckksnotice("ckksshare", keyset.tlk, "Missing TLK shares for %lu peers: %@", (unsigned long)peersMissingShares.count, peersMissingShares);
183 ckksnotice("ckksshare", keyset.tlk, "Self peers are (%@) %@", self.currentSelfPeersError ?: @"no error", self.currentSelfPeers);
184 ckksnotice("ckksshare", keyset.tlk, "Trusted peers are (%@) %@", self.currentTrustedPeersError ?: @"no error", self.currentTrustedPeers);
187 return peersMissingShares;
190 - (BOOL)unwrapKey:(CKKSKey*)proposedTLK
191 fromShares:(NSArray<CKKSTLKShareRecord*>*)tlkShares
192 error:(NSError**)error
194 if(!self.currentSelfPeers.currentSelf || self.currentSelfPeersError) {
195 ckkserror("ckksshare", proposedTLK, "Don't have self peers for %@: %@", self.peerProviderID, self.currentSelfPeersError);
197 *error = [NSError errorWithDomain:CKKSErrorDomain
198 code:CKKSNoEncryptionKey
199 description:@"Key unwrap failed"
200 underlying:self.currentSelfPeersError];;
205 if(!self.currentTrustedPeers || self.currentTrustedPeersError) {
206 ckkserror("ckksshare", proposedTLK, "Don't have trusted peers: %@", self.currentTrustedPeersError);
208 *error = [NSError errorWithDomain:CKKSErrorDomain
209 code:CKKSNoPeersAvailable
210 description:@"No trusted peers"
211 underlying:self.currentTrustedPeersError];
216 NSError* lastShareError = nil;
218 for(id<CKKSSelfPeer> selfPeer in self.currentSelfPeers.allSelves) {
219 NSMutableArray<CKKSTLKShareRecord*>* possibleShares = [NSMutableArray array];
221 for(CKKSTLKShareRecord* share in tlkShares) {
222 if([share.share.receiverPeerID isEqualToString:selfPeer.peerID]) {
223 [possibleShares addObject:share];
227 if(possibleShares.count == 0) {
228 ckksnotice("ckksshare", proposedTLK, "No CKKSTLKShares to %@ for %@", selfPeer, proposedTLK);
232 for(CKKSTLKShareRecord* possibleShare in possibleShares) {
233 NSError* possibleShareError = nil;
234 ckksnotice("ckksshare", proposedTLK, "Checking possible TLK share %@ as %@", possibleShare, selfPeer);
236 CKKSKey* possibleKey = [possibleShare recoverTLK:selfPeer
237 trustedPeers:self.currentTrustedPeers
238 error:&possibleShareError];
240 if(!possibleKey || possibleShareError) {
241 ckkserror("ckksshare", proposedTLK, "Unable to unwrap TLKShare(%@) as %@: %@",
242 possibleShare, selfPeer, possibleShareError);
243 ckkserror("ckksshare", proposedTLK, "Current trust set: %@", self.currentTrustedPeers);
244 lastShareError = possibleShareError;
248 bool result = [proposedTLK trySelfWrappedKeyCandidate:possibleKey.aessivkey error:&possibleShareError];
249 if(!result || possibleShareError) {
250 ckkserror("ckksshare", proposedTLK, "Unwrapped TLKShare(%@) does not unwrap proposed TLK(%@) as %@: %@",
251 possibleShare, proposedTLK, self.currentSelfPeers.currentSelf, possibleShareError);
252 lastShareError = possibleShareError;
256 ckksnotice("ckksshare", proposedTLK, "TLKShare(%@) unlocked TLK(%@) as %@",
257 possibleShare, proposedTLK, selfPeer);
264 *error = [NSError errorWithDomain:CKKSErrorDomain
265 code:CKKSNoTrustedTLKShares
266 description:[NSString stringWithFormat:@"No trusted TLKShares for %@", proposedTLK]
267 underlying:lastShareError];