OctagonCKKSPeerAdapter.m [plain text]
#if OCTAGON
#import <SecurityFoundation/SecurityFoundation.h>
#import <SecurityFoundation/SFIdentity.h>
#import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
#import "keychain/ot/OctagonCKKSPeerAdapter.h"
#import "keychain/ot/OTDefines.h"
#import "keychain/ot/OTConstants.h"
#import "keychain/ckks/CKKSPeer.h"
#import "keychain/ckks/CKKSListenerCollection.h"
#import "keychain/ot/ObjCImprovements.h"
#import "utilities/debugging.h"
#import "keychain/categories/NSError+UsefulConstructors.h"
@interface OctagonSelfPeer ()
@property SFIdentity* encryptionIdentity;
@property SFIdentity* signingIdentity;
@end
@implementation OctagonSelfPeer
@synthesize peerID = _peerID;
- (instancetype)initWithPeerID:(NSString*)peerID
signingIdentity:(SFIdentity*)signingIdentity
encryptionIdentity:(SFIdentity*)encryptionIdentity
{
if((self = [super init])) {
_peerID = peerID;
_signingIdentity = signingIdentity;
_encryptionIdentity = encryptionIdentity;
}
return self;
}
- (NSString*)description
{
return [NSString stringWithFormat:@"<OctagonSelfPeer: }
- (SFECPublicKey*)publicEncryptionKey
{
return self.encryptionIdentity.publicKey;
}
- (SFECPublicKey*)publicSigningKey
{
return self.signingIdentity.publicKey;
}
- (SFECKeyPair*)encryptionKey
{
return self.encryptionIdentity.keyPair;
}
- (SFECKeyPair*)signingKey
{
return self.signingIdentity.keyPair;
}
- (bool)matchesPeer:(nonnull id<CKKSPeer>)peer {
NSString* otherPeerID = peer.peerID;
if(self.peerID == nil && otherPeerID == nil) {
return true;
}
return [self.peerID isEqualToString:otherPeerID];
}
@end
@interface OctagonCKKSPeerAdapter ()
@property CKKSListenerCollection* peerChangeListeners;
@end
@implementation OctagonCKKSPeerAdapter
@synthesize essential = _essential;
@synthesize providerID = _providerID;
- (instancetype)initWithPeerID:(NSString*)peerID
containerName:(NSString*)containerName
contextID:(NSString*)contextID
cuttlefishXPC:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper
{
if((self = [super init])) {
_providerID = [NSString stringWithFormat:@"[OctagonCKKSPeerAdapter: _peerID = peerID;
_containerName = containerName;
_contextID = contextID;
_cuttlefishXPCWrapper = cuttlefishXPCWrapper;
_peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-sos"];
// Octagon is king.
_essential = YES;
}
return self;
}
- (NSString*)description
{
return [NSString stringWithFormat:@"<OctagonCKKSPeerAdapter: }
- (SFIdentity*)fetchIdentity:(NSString*)identifier error:(NSError *__autoreleasing _Nullable * _Nullable)error
{
// Async to sync again! No other option.
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
SFKeychainManager* keychainManager = [SFKeychainManager defaultOverCommitManager];
__block SFIdentity* identity = nil;
__block NSError* localError = nil;
[keychainManager identityForIdentifier:identifier resultHandler:^(SFKeychainIdentityFetchResult * _Nonnull result) {
switch(result.resultType) {
case SFKeychainFetchResultTypeError:
case SFKeychainFetchResultTypeNeedsAuthentication:
secnotice("octagon-ckks", "Unable to fetch identity '%@' from keychain: localError = result.error;
break;
case SFKeychainFetchResultTypeValueAvailable:
identity = result.value;
break;
}
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
if(error && localError) {
*error = localError;
}
return identity;
}
- (CKKSSelves * _Nullable)fetchSelfPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
{
if(self.peerID) {
// Shameless duplication of swift code in TPH. Thanks, perf team!
NSError* keychainError = nil;
SFIdentity* signingIdentity = [self fetchIdentity:[NSString stringWithFormat:@"signing-key if(!signingIdentity || keychainError) {
if(error) {
// TODO: ensure error exists
*error = keychainError;
}
return nil;
}
SFIdentity* encryptionIdentity = [self fetchIdentity:[NSString stringWithFormat:@"encryption-key if(!encryptionIdentity || keychainError) {
if(error) {
// TODO: ensure error exists
*error = keychainError;
}
return nil;
}
OctagonSelfPeer* selfPeer = [[OctagonSelfPeer alloc] initWithPeerID:self.peerID
signingIdentity:signingIdentity
encryptionIdentity:encryptionIdentity];
CKKSSelves* selves = [[CKKSSelves alloc] initWithCurrent:selfPeer allSelves:[NSSet set]];
return selves;
}
secnotice("octagon-ckks", "No peer ID; therefore no identity");
if(error) {
*error = [NSError errorWithDomain:OctagonErrorDomain
code:OTErrorNoIdentity
description:@"no peer ID present"];
}
return nil;
}
- (NSSet<id<CKKSRemotePeerProtocol>> * _Nullable)fetchTrustedPeers:(NSError *__autoreleasing _Nullable * _Nullable)error
{
// TODO: make this memoized somehow, somewhere
__block NSError* localerror;
__block NSMutableSet<id<CKKSRemotePeerProtocol>> * peers = nil;
WEAKIFY(self);
[self.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.containerName
context:self.contextID
reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState,
NSArray<TrustedPeersHelperPeer *> * _Nullable trustedPeers,
NSError * _Nullable operror) {
STRONGIFY(self);
if(operror) {
secnotice("octagon", "Unable to fetch trusted peers for ( localerror = operror;
} else {
peers = [NSMutableSet set];
// Turn these peers into CKKSPeers
for(TrustedPeersHelperPeer* peer in trustedPeers) {
SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI];
SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI];
CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID
encryptionPublicKey:encryptionKey
signingPublicKey:signingKey
viewList:peer.viewList];
[peers addObject:ckkspeer];
}
}
}];
if(error && localerror) {
*error = localerror;
}
return peers;
}
- (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
[self.peerChangeListeners registerListener:listener];
}
- (void)sendSelfPeerChangedUpdate {
[self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
[listener selfPeerChanged: self];
}];
}
- (void)sendTrustedPeerSetChangedUpdate {
[self.peerChangeListeners iterateListeners: ^(id<CKKSPeerUpdateListener> listener) {
[listener trustedPeerSetChanged: self];
}];
}
- (nonnull CKKSPeerProviderState *)currentState {
return [CKKSPeerProviderState createFromProvider:self];
}
@end
#endif // OCTAGON