]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountRingUpdate.c
diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c
deleted file mode 100644 (file)
index 0e6fe98..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-//
-//  SOSAccountRingUpdate.c
-//  sec
-//
-//
-
-#include <stdio.h>
-
-#include "SOSAccountPriv.h"
-#include <Security/SecureObjectSync/SOSTransportCircle.h>
-#include <Security/SecureObjectSync/SOSTransport.h>
-#include <Security/SecureObjectSync/SOSViews.h>
-#include <Security/SecureObjectSync/SOSRing.h>
-#include <Security/SecureObjectSync/SOSRingUtils.h>
-#include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
-
-#if 0
-static inline bool SOSAccountHasLeft(SOSAccountRef account) {
-    switch(account->departure_code) {
-        case kSOSWithdrewMembership: /* Fallthrough */
-        case kSOSMembershipRevoked: /* Fallthrough */
-        case kSOSLeftUntrustedCircle:
-            return true;
-        case kSOSNeverAppliedToCircle: /* Fallthrough */
-        case kSOSNeverLeftCircle: /* Fallthrough */
-        default:
-            return false;
-    }
-}
-#endif
-
-static const char * __unused concordstring[] = {
-    "kSOSConcordanceTrusted",
-    "kSOSConcordanceGenOld",     // kSOSErrorReplay
-    "kSOSConcordanceNoUserSig",  // kSOSErrorBadSignature
-    "kSOSConcordanceNoUserKey",  // kSOSErrorNoKey
-    "kSOSConcordanceNoPeer",     // kSOSErrorPeerNotFound
-    "kSOSConcordanceBadUserSig", // kSOSErrorBadSignature
-    "kSOSConcordanceBadPeerSig", // kSOSErrorBadSignature
-    "kSOSConcordanceNoPeerSig",
-    "kSOSConcordanceWeSigned",
-    "kSOSConcordanceInvalidMembership",
-    "kSOSConcordanceMissingMe",
-    "kSOSConcordanceImNotWorthy",
-};
-
-
-static bool SOSAccountIsPeerRetired(SOSAccountRef account, CFSetRef peers){
-    CFMutableArrayRef peerInfos = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-    bool result = false;
-    
-    CFSetForEach(peers, ^(const void *value) {
-        SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
-        if(SOSPeerInfoIsRetirementTicket(peer))
-            CFArrayAppendValue(peerInfos, peer);
-    });
-    if(CFArrayGetCount(peerInfos) > 0){
-        if(!SOSAccountRemoveBackupPeers(account, peerInfos, NULL))
-            secerror("Could not remove peers: %@, from the backup", peerInfos);
-        else
-            return true;
-    }
-    else
-        result = true;
-    
-    CFReleaseNull(peerInfos);
-    
-    return result;
-}
-
-static bool SOSAccountBackupSliceKeyBagNeedsFix(SOSAccountRef account, SOSBackupSliceKeyBagRef bskb) {
-
-    if (SOSBSKBIsDirect(bskb) || account->backup_key == NULL)
-        return false;
-
-    CFSetRef peers = SOSBSKBGetPeers(bskb);
-    
-    /* first scan for retired peers, and kick'em out!*/
-    SOSAccountIsPeerRetired(account, peers);
-    
-    SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
-    bool needsFix = true;
-
-    if (myPeer) {
-        SOSPeerInfoRef meInBag = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
-        CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
-        CFDataRef meInBagBK = SOSPeerInfoCopyBackupKey(meInBag);
-        needsFix = !(meInBag && CFEqualSafe(myBK,
-                                            meInBagBK));
-        CFReleaseNull(myBK);
-        CFReleaseNull(meInBagBK);
-    }
-    
-    CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
-    if(rkbg) needsFix |= !SOSBKSBPrefixedKeyIsInKeyBag(bskb, bskbRkbgPrefix, rkbg);
-    else needsFix |= SOSBSKBHasRecoveryKey(bskb); // if we don't have a recovery key - the bskb shouldn't
-    CFReleaseNull(rkbg);
-
-    return needsFix;
-}
-
-
-typedef enum {
-    accept,
-    countersign,
-    leave,
-    revert,
-    modify,
-    ignore
-} ringAction_t;
-
-static const char * __unused actionstring[] = {
-    "accept", "countersign", "leave", "revert", "modify", "ignore",
-};
-
-bool SOSAccountHandleUpdateRing(SOSAccountRef account, SOSRingRef prospectiveRing, bool writeUpdate, CFErrorRef *error) {
-    bool success = true;
-    bool haveOldRing = true;
-    const char * __unused localRemote = writeUpdate ? "local": "remote";
-    SOSFullPeerInfoRef fpi = account->my_identity;
-    SOSPeerInfoRef     pi = SOSFullPeerInfoGetPeerInfo(fpi);
-    CFStringRef        peerID = SOSPeerInfoGetPeerID(pi);
-    bool               peerActive = (fpi && pi && peerID && SOSAccountIsInCircle(account, NULL));
-    
-
-    secdebug("ringSigning", "start:[%s] %@", localRemote, prospectiveRing);
-
-    require_quiet(SOSAccountHasPublicKey(account, error), errOut);
-
-    require_action_quiet(prospectiveRing, errOut,
-                         SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("No Ring to work with"), NULL, error));
-
-    require_action_quiet(SOSRingIsStable(prospectiveRing), errOut, SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("You give rings a bad name"), NULL, error));
-
-    // We should at least have a sane ring system in the account object
-    require_quiet(SOSAccountCheckForRings(account, error), errOut);
-
-    CFStringRef ringName = SOSRingGetName(prospectiveRing);
-    SOSRingRef oldRing = SOSAccountCopyRing(account, ringName, NULL);
-
-    SOSTransportCircleRef transport = account->circle_transport;
-    
-    SOSRingRef newRing = CFRetainSafe(prospectiveRing); // TODO:  SOSAccountCloneRingWithRetirement(account, prospectiveRing, error);
-
-    ringAction_t ringAction = ignore;
-
-    bool userTrustedoldRing = true;
-
-    SOSCircleRef circle = SOSAccountGetCircle(account, NULL);
-    CFSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault);
-
-    SecKeyRef oldKey = account->user_public;
-
-#if 0
-    // for now user keys aren't explored.
-    // we should ask the ring if it cares about it and then do the magic to find the right user keys.
-    SecKeyRef oldKey = account->user_public;
-
-    if(SOSRingPKTrusted(oldRing, account->user_public, NULL)) oldKey = account->user_public;
-    else if(account->previous_public && SOSRingPKTrusted(oldRing, account->previous_public, NULL)) oldKey = account->previous_public;
-    bool userTrustedoldRing = (oldKey != NULL) && haveOldRing;
-
-#endif
-
-    if (!oldRing) {
-        oldRing = CFRetainSafe(newRing);
-    }
-
-    SOSConcordanceStatus concstat = SOSRingConcordanceTrust(fpi, peers, oldRing, newRing, oldKey, account->user_public, peerID, error);
-    CFReleaseNull(peers);
-
-    CFStringRef concStr = NULL;
-    switch(concstat) {
-        case kSOSConcordanceTrusted:
-            ringAction = countersign;
-            concStr = CFSTR("Trusted");
-            break;
-        case kSOSConcordanceGenOld:
-            ringAction = userTrustedoldRing ? revert : ignore;
-            concStr = CFSTR("Generation Old");
-            break;
-        case kSOSConcordanceBadUserSig:
-        case kSOSConcordanceBadPeerSig:
-            ringAction = userTrustedoldRing ? revert : accept;
-            concStr = CFSTR("Bad Signature");
-            break;
-        case kSOSConcordanceNoUserSig:
-            ringAction = userTrustedoldRing ? revert : accept;
-            concStr = CFSTR("No User Signature");
-            break;
-        case kSOSConcordanceNoPeerSig:
-            ringAction = accept; // We might like this one eventually but don't countersign.
-            concStr = CFSTR("No trusted peer signature");
-            secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later %@", newRing);
-            break;
-        case kSOSConcordanceNoPeer:
-            ringAction = leave;
-            concStr = CFSTR("No trusted peer left");
-            break;
-        case kSOSConcordanceNoUserKey:
-            secerror("##### No User Public Key Available, this shouldn't ever happen!!!");
-            ringAction = ignore;
-            break;
-            
-        case kSOSConcordanceMissingMe:
-        case kSOSConcordanceImNotWorthy:
-            ringAction = modify;
-            concStr = CFSTR("Incorrect membership for me");
-            break;
-        case kSOSConcordanceInvalidMembership:
-            ringAction = userTrustedoldRing ? revert : ignore;
-            concStr = CFSTR("Invalid Ring Membership");
-            break;
-        default:
-            secerror("##### Bad Error Return from ConcordanceTrust");
-            ringAction = ignore;
-            break;
-    }
-
-    (void)concStr;
-    
-    secdebug("ringSigning", "Decided on action [%s] based on concordance state [%s] and [%s] circle.", actionstring[ringAction], concordstring[concstat], userTrustedoldRing ? "trusted" : "untrusted");
-
-    SOSRingRef ringToPush = NULL;
-    bool iWasInOldRing = peerID && SOSRingHasPeerID(oldRing, peerID);
-    bool iAmInNewRing = peerID && SOSRingHasPeerID(newRing, peerID);
-    bool ringIsBackup = SOSRingGetType(newRing) == kSOSRingBackup;
-    bool ringIsRecovery = SOSRingGetType(newRing) == kSOSRingRecovery;
-
-    if (ringIsBackup && peerActive) {
-        if (ringAction == accept || ringAction == countersign) {
-            CFErrorRef localError = NULL;
-            SOSBackupSliceKeyBagRef bskb = SOSRingCopyBackupSliceKeyBag(newRing, &localError);
-
-            if(!bskb) {
-                secnotice("ringSigning", "Backup ring with no backup slice keybag (%@)", localError);
-            } else if (SOSAccountBackupSliceKeyBagNeedsFix(account, bskb)) {
-                ringAction = modify;
-            }
-            CFReleaseSafe(localError);
-            CFReleaseSafe(bskb);
-        }
-
-        if (ringAction == modify) {
-            CFErrorRef updateError = NULL;
-            SOSAccountSetRing(account, newRing, ringName, error);
-
-            if(SOSAccountUpdateOurPeerInBackup(account, newRing, &updateError)) {
-                secdebug("signing", "Modified backup ring to include us");
-            } else {
-                secerror("Could not add ourselves to the backup: (%@)", updateError);
-            }
-            CFReleaseSafe(updateError);
-
-            // Fall through to normal modify handling.
-        }
-    }
-    
-    if (ringIsRecovery && peerActive && (ringAction == modify)) {
-        SOSAccountSetRing(account, newRing, ringName, error);
-    }
-
-
-    if (ringAction == modify) {
-        ringAction = ignore;
-    }
-
-    if (ringAction == leave) {
-        if (iWasInOldRing) {
-            if (sosAccountLeaveRing(account, newRing, error)) {
-                ringToPush = newRing;
-            } else {
-                secdebug("ringSigning", "Can't leave ring %@", oldRing);
-                success = false;
-            }
-            ringAction = accept;
-        } else {
-            // We are not in this ring, but we need to update account with it, since we got it from cloud
-            ringAction = accept;
-        }
-    }
-
-    if (ringAction == countersign) {
-        if (iAmInNewRing) {
-            if (SOSRingPeerTrusted(newRing, fpi, NULL)) {
-                secdebug("ringSigning", "Already concur with: %@", newRing);
-            } else {
-                CFErrorRef signingError = NULL;
-
-                if (fpi && SOSRingConcordanceSign(newRing, fpi, &signingError)) {
-                    ringToPush = newRing;
-                } else {
-                    secerror("Failed to concordance sign, error: %@  Old: %@ New: %@", signingError, oldRing, newRing);
-                    success = false;
-                }
-                CFReleaseSafe(signingError);
-            }
-        } else {
-            secdebug("ringSigning", "Not countersigning, not in ring: %@", newRing);
-        }
-        ringAction = accept;
-    }
-
-    if (ringAction == accept) {
-        if (iWasInOldRing && !iAmInNewRing) {
-
-            //  Don't destroy evidence of other code determining reason for leaving.
-            //if(!SOSAccountHasLeft(account)) account->departure_code = kSOSMembershipRevoked;
-            // TODO: LeaveReason for rings
-        }
-
-        if (pi && SOSRingHasRejection(newRing, peerID)) {
-            // TODO: ReasonForLeaving for rings
-            SOSRingRemoveRejection(newRing, peerID);
-        }
-
-        SOSAccountSetRing(account, newRing, ringName, error);
-
-        if (pi && account->user_public_trusted
-            && SOSRingHasApplicant(oldRing, peerID)
-            && SOSRingCountPeers(newRing) > 0
-            && !iAmInNewRing && !SOSRingHasApplicant(newRing, peerID)) {
-            // We weren't rejected (above would have set me to NULL.
-            // We were applying and we weren't accepted.
-            // Our application is declared lost, let us reapply.
-
-            if (SOSRingApply(newRing, account->user_public, fpi, NULL))
-                if(peerActive) writeUpdate = true;
-        }
-
-        if (pi && SOSRingHasPeerID(oldRing, peerID)) {
-            SOSAccountCleanupRetirementTickets(account, RETIREMENT_FINALIZATION_SECONDS, NULL);
-        }
-
-
-        account->circle_rings_retirements_need_attention = true;
-
-        if (writeUpdate)
-            ringToPush = newRing;
-        account->key_interests_need_updating = true;
-    }
-
-    /*
-     * In the revert section we'll guard the KVS idea of circles by rejecting "bad" new rings
-     * and pushing our current view of the ring (oldRing).  We'll only do this if we actually
-     * are a member of oldRing - never for an empty ring.
-     */
-
-    if (ringAction == revert) {
-        if(haveOldRing && peerActive && SOSRingHasPeerID(oldRing, peerID)) {
-            secdebug("ringSigning", "%@, Rejecting: %@ re-publishing %@", concStr, newRing, oldRing);
-            ringToPush = oldRing;
-        } else {
-            secdebug("ringSigning", "%@, Rejecting: %@ Have no old circle - would reset", concStr, newRing);
-        }
-    }
-
-
-    if (ringToPush != NULL) {
-        secdebug("ringSigning", "Pushing:[%s] %@", localRemote, ringToPush);
-        CFDataRef ringData = SOSRingCopyEncodedData(ringToPush, error);
-        if (ringData) {
-            success &= SOSTransportCircleRingPostRing(transport, SOSRingGetName(ringToPush), ringData, error);
-        } else {
-            success = false;
-        }
-        CFReleaseNull(ringData);
-    }
-    CFReleaseNull(oldRing);
-    CFReleaseSafe(newRing);
-    return success;
-errOut:
-    return false;
-}