SOSTransportKeyParameterKVS.c   [plain text]


#include <Security/SecureObjectSync/SOSAccountPriv.h>
#include <Security/SecureObjectSync/SOSTransport.h>
#include <Security/SecureObjectSync/SOSTransportKeyParameter.h>
#include <Security/SecureObjectSync/SOSTransportKeyParameterKVS.h>
#include <Security/SecureObjectSync/SOSKVSKeys.h>
#include <SOSCloudKeychainClient.h>
#include <utilities/SecCFWrappers.h>
#include <SOSCloudCircleServer.h>

static bool SOSTransportKeyParameterKVSPublishCloudParameters(SOSTransportKeyParameterKVSRef transport, CFDataRef newParameters, CFErrorRef *error);
static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error);
static bool SOSTransportKeyParameterKVSUpdateKVS(CFDictionaryRef changes, CFErrorRef *error);
static void destroy(SOSTransportKeyParameterRef transport);
static inline CFIndex getTransportType(SOSTransportKeyParameterRef transport, CFErrorRef *error);

struct __OpaqueSOSTransportKeyParameterKVS{
    struct __OpaqueSOSTransportKeyParameter     k;
};

static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){
    SOSAccountRef account = transport->account;
    return SOSAccountHandleParametersChange(account, data, &error);
    
}

static inline CFIndex getTransportType(SOSTransportKeyParameterRef transport, CFErrorRef *error){
    return kKVS;
}


static bool setToNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef account){
    SOSAccountSetToNew(account);
    return true;
}

SOSTransportKeyParameterKVSRef SOSTransportKeyParameterKVSCreate(SOSAccountRef account, CFErrorRef *error) {
    SOSTransportKeyParameterKVSRef tkvs = (SOSTransportKeyParameterKVSRef) SOSTransportKeyParameterCreateForSubclass(sizeof(struct __OpaqueSOSTransportKeyParameterKVS) - sizeof(CFRuntimeBase), account, error);
    if(tkvs){
        tkvs->k.publishCloudParameters = publishCloudParameters;
        tkvs->k.handleKeyParameterChanges = handleKeyParameterChanges;
        tkvs->k.setToNewAccount = setToNewAccount;
        tkvs->k.destroy = destroy;
        tkvs->k.getTransportType = getTransportType;
        SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef)tkvs);
    }
    return tkvs;
}

static void destroy(SOSTransportKeyParameterRef transport){
    SOSUnregisterTransportKeyParameter(transport);
}

bool SOSTransportKeyParameterKVSHandleCloudParameterChange(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error){
    SOSTransportKeyParameterKVSRef tkvs = (SOSTransportKeyParameterKVSRef)transport;
    SOSAccountRef account = tkvs->k.account;
    
    return SOSAccountHandleParametersChange(account, data, error);
}


bool SOSTransportKeyParameterKVSAppendKeyInterests(SOSTransportKeyParameterKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef*error){
    CFArrayAppendValue(alwaysKeys, kSOSKVSKeyParametersKey);
    
    return true;
}

static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error)
{
    return SOSTransportKeyParameterKVSPublishCloudParameters((SOSTransportKeyParameterKVSRef)transport, data, error);
}

static bool SOSTransportKeyParameterKVSUpdateKVS(CFDictionaryRef changes, CFErrorRef *error){
    CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) {
        if (block_error) {
            secerror("Error putting: %@", block_error);
        }
    };
    
    SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
    return true;
}

static bool SOSTransportKeyParameterKVSPublishCloudParameters(SOSTransportKeyParameterKVSRef transport, CFDataRef newParameters, CFErrorRef *error)
{
    SOSAccountRef a = SOSTransportKeyParameterGetAccount((SOSTransportKeyParameterRef)transport);
    CFDictionaryRef changes = NULL;
    CFDataRef timeData = NULL;
    bool waitForeverForSynchronization = true;
    
    CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
    CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();

    withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
        CFStringAppend(timeDescription, decription);
    });
    CFStringAppend(timeDescription, CFSTR("]"));

    timeData = CFStringCreateExternalRepresentation(NULL,timeDescription,
        kCFStringEncodingUTF8, '?');

    CFMutableDataRef timeAndKeyParametersMutable = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(timeData) + CFDataGetLength(newParameters)); 
    CFDataAppend(timeAndKeyParametersMutable, timeData);
    CFDataAppend(timeAndKeyParametersMutable, newParameters);
    CFDataRef timeAndKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, timeAndKeyParametersMutable);

    CFStringRef ourPeerID = SOSAccountGetMyPeerID(a);

    if(ourPeerID != NULL){
        CFStringRef keyParamKey = SOSLastKeyParametersPushedKeyCreateWithPeerID(ourPeerID);
        
        changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                               kSOSKVSKeyParametersKey, newParameters,
                                               keyParamKey, timeAndKeyParameters,
                                               NULL);
        CFReleaseNull(keyParamKey);
    }
    else
    {
        CFStringRef keyParamKeyWithAccount = SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(a);
        changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                               kSOSKVSKeyParametersKey, newParameters,
                                               keyParamKeyWithAccount, timeAndKeyParameters,
                                               NULL);
        CFReleaseNull(keyParamKeyWithAccount);
        
    }
    bool success = SOSTransportKeyParameterKVSUpdateKVS(changes, error);
    
    sync_the_last_data_to_kvs(a, waitForeverForSynchronization);
    
    CFReleaseNull(changes);
    CFReleaseNull(timeAndKeyParametersMutable);
    CFReleaseNull(timeAndKeyParameters);
    CFReleaseNull(timeData);
    CFReleaseNull(timeDescription);
    return success;
}