SOSAccountHSAJoin.c   [plain text]


//
//  SOSAccountHSAJoin.c
//  sec
//
//  Created by Richard Murphy on 3/23/15.
//
//

#include "SOSAccountHSAJoin.h"
#include "SOSAccountPriv.h"
#include <Security/SecureObjectSync/SOSPeerInfo.h>
#include <Security/SecureObjectSync/SOSPeerInfoV2.h>
#include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
#include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
#include <Security/SecureObjectSync/SOSTransportCircle.h>
#include <Security/SecureObjectSync/SOSTransportMessage.h>
#include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
#include <Security/SecureObjectSync/SOSKVSKeys.h>
#include <Security/SecureObjectSync/SOSTransport.h>
#include <Security/SecureObjectSync/SOSTransportKeyParameter.h>
#include <Security/SecureObjectSync/SOSTransportKeyParameterKVS.h>
#include <Security/SecureObjectSync/SOSEngine.h>
#include <Security/SecureObjectSync/SOSPeerCoder.h>
#include <Security/SecureObjectSync/SOSInternal.h>
#include <sys/unistd.h>

const CFStringRef kSOSHsaPreApprovedPeerKeyInfo = CFSTR("HSAPreApprovedPeer");

const CFStringRef kSOSHsaCrKeyUUID = CFSTR("HSAUUID");
const CFStringRef kSOSHsaCrKeyDescription = CFSTR("HSADESC");

CFMutableSetRef SOSAccountCopyPreApprovedHSA2Info(SOSAccountRef account) {
    CFMutableSetRef preApprovedPeers = (CFMutableSetRef) SOSAccountGetValue(account, kSOSHsaPreApprovedPeerKeyInfo, NULL);
    if(preApprovedPeers) {
        preApprovedPeers = CFSetCreateMutableCopy(NULL, 0, preApprovedPeers);
    } else {
        preApprovedPeers = CFSetCreateMutableForCFTypes(NULL);
    }
    return preApprovedPeers;
}

static bool sosAccountSetPreApprovedInfo(SOSAccountRef account, CFStringRef peerID, CFErrorRef *error) {
    bool retval = false;
    CFMutableSetRef preApprovedPeers = SOSAccountCopyPreApprovedHSA2Info(account);
    require_action_quiet(preApprovedPeers, errOut, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("Can't Alloc Pre-Approved Peers Set"), NULL, error));
    CFSetSetValue(preApprovedPeers, peerID);
    require(SOSAccountSetValue(account, kSOSHsaPreApprovedPeerKeyInfo, preApprovedPeers, error), errOut);
    retval = true;
errOut:
    CFReleaseNull(preApprovedPeers);
    return retval;
}

bool SOSAccountSetHSAPubKeyExpected(SOSAccountRef account, CFDataRef pubKeyBytes, CFErrorRef *error) {
    bool retval = false;
    SecKeyRef publicKey = SecKeyCreateFromPublicBytes(NULL, kSecECDSAAlgorithmID, CFDataGetBytePtr(pubKeyBytes), CFDataGetLength(pubKeyBytes));
    CFStringRef peerID = SOSCopyIDOfKey(publicKey, error);
    require(sosAccountSetPreApprovedInfo(account, peerID, error), errOut);
    retval = true;
errOut:
    CFReleaseNull(publicKey);
    CFReleaseNull(peerID);
    return retval;
}

bool SOSAccountVerifyAndAcceptHSAApplicants(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) {
    SOSFullPeerInfoRef fpi = account->my_identity;
    __block bool circleChanged = false;
    CFMutableSetRef approvals = SOSAccountCopyPreApprovedHSA2Info(account);
    if(approvals && CFSetGetCount(approvals) > 0) {
        SOSCircleForEachApplicant(newCircle, ^(SOSPeerInfoRef peer) {
            CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
            if(CFSetContainsValue(approvals, peerID)) {
                SOSPeerInfoRef copypi = SOSPeerInfoCreateCopy(NULL, peer, NULL);
                circleChanged = SOSCircleAcceptRequest(newCircle, SOSAccountGetPrivateCredential(account, NULL), fpi, copypi, error);
                CFSetRemoveValue(approvals, peerID);
            }
        });
    }
    if(circleChanged) {
        bool local = SOSAccountSetValue(account, kSOSHsaPreApprovedPeerKeyInfo, approvals, error);
        if(!local) secnotice("hsa2approval", "Couldn't clean pre-approved peer list");
    }
    CFReleaseNull(approvals);
    return circleChanged;
}

bool SOSAccountClientPing(SOSAccountRef account) {
    if (account->trusted_circle && account->my_identity
        && SOSFullPeerInfoPing(account->my_identity, NULL)) {
        SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) {
            secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change");
            return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(account->my_identity));
        });
    }
    
    return true;
}