]> git.saurik.com Git - apple/security.git/blobdiff - keychain/SecureObjectSync/SOSRingBackup.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSRingBackup.m
diff --git a/keychain/SecureObjectSync/SOSRingBackup.m b/keychain/SecureObjectSync/SOSRingBackup.m
new file mode 100644 (file)
index 0000000..26582d4
--- /dev/null
@@ -0,0 +1,144 @@
+//
+//  SOSRingBasic.c
+//  sec
+//
+//  Created by Richard Murphy on 3/3/15.
+//
+//
+
+#include "SOSRingBackup.h"
+
+#include <AssertMacros.h>
+
+#include "keychain/SecureObjectSync/SOSInternal.h"
+#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
+#include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
+#include "keychain/SecureObjectSync/SOSCircle.h"
+#include <Security/SecureObjectSync/SOSViews.h>
+#include <Security/SecFramework.h>
+
+#include <Security/SecKey.h>
+#include <Security/SecKeyPriv.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <utilities/SecCFWrappers.h>
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "SOSRingUtils.h"
+#include "SOSRingTypes.h"
+#include "SOSRingBasic.h"
+
+// MARK: Backup Ring Ops
+
+static SOSRingRef SOSRingCreate_Backup(CFStringRef name, CFStringRef myPeerID, CFErrorRef *error) {
+    return SOSRingCreate_ForType(name, kSOSRingBackup, myPeerID, error);
+}
+
+
+// Make sure all the peers in the ring have access to the ring views
+static bool SOSBackupRingPeersInViews(CFSetRef peers, SOSRingRef ring) {
+    CFSetRef ringViews = SOSBackupRingGetViews(ring, NULL);
+    if(!ringViews) return false;
+    __block bool retval = true;
+    SOSRingForEachPeerID(ring, ^(CFStringRef peerID) {
+        SOSPeerInfoRef peerInfo = SOSPeerInfoSetFindByID(peers, peerID);
+        if(peerInfo) {
+            CFSetForEach(ringViews, ^(const void *value) {
+                if(!SOSPeerInfoIsViewPermitted(peerInfo, (CFStringRef) value)) retval = false;
+            });
+        } else {
+            retval = false;
+        }
+    });
+    return retval;
+}
+
+// Make sure that the ring includes me if I'm enabled for its view.
+static SOSConcordanceStatus SOSBackupRingEvaluateMyInclusion(SOSRingRef ring, SOSFullPeerInfoRef me) {
+    bool shouldBeInRing = false;
+    bool amInThisRing = false;
+
+    if (me) {
+        SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(me);
+        CFStringRef peerID = SOSPeerInfoGetPeerID(pi);
+        CFSetRef ringViews = SOSRingGetBackupViewset_Internal(ring);
+        CFSetRef piViews = SOSPeerInfoGetPermittedViews(pi);
+        shouldBeInRing = CFSetIsSubset(ringViews, piViews);
+        amInThisRing = SOSRingHasPeerWithID(ring, peerID, NULL);
+    }
+
+    if(shouldBeInRing && !amInThisRing) return kSOSConcordanceMissingMe;
+    if(!shouldBeInRing && amInThisRing) return kSOSConcordanceImNotWorthy;
+    return kSOSConcordanceTrusted;
+}
+
+static SOSConcordanceStatus SOSRingPeerKeyConcordanceTrust_Backup(SOSFullPeerInfoRef me, CFSetRef peers, SOSRingRef knownRing, SOSRingRef proposedRing,
+                                                    __unused SecKeyRef knownPubkey, SecKeyRef userPubkey,
+                                                    CFStringRef excludePeerID, CFErrorRef *error) {
+    if(userPubkey == NULL) {
+        SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key - need to validate application"), NULL, error);
+        return kSOSConcordanceNoUserKey;
+    }
+    
+    if(SOSRingIsOlderGeneration(proposedRing, knownRing)) {
+        SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error);
+        return kSOSConcordanceGenOld;
+    }
+    
+    
+    if (SOSRingIsEmpty_Internal(proposedRing)) {
+        return kSOSConcordanceTrusted;
+    }
+
+    SOSConcordanceStatus localstatus = SOSBackupRingEvaluateMyInclusion(proposedRing, me);
+    if(localstatus == kSOSConcordanceMissingMe) {
+        SOSCreateError(kSOSErrorReplay, CFSTR("Improper exclusion of this peer"), NULL, error);
+        return localstatus;
+    }
+    
+    if(localstatus == kSOSConcordanceImNotWorthy) {
+        SOSCreateError(kSOSErrorReplay, CFSTR("Improper inclusion of this peer"), NULL, error);
+        return localstatus;
+    }
+    
+    if(!SOSBackupRingPeersInViews(peers, proposedRing)) {
+        return kSOSConcordanceInvalidMembership;
+    }
+
+    return GetSignersStatus_Transitive(peers, knownRing, proposedRing, userPubkey, excludePeerID, error);
+}
+
+bool SOSBackupRingSetViews(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFSetRef viewSet, CFErrorRef *error) {
+    CFStringRef myPeerID = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(requestor));
+    SecKeyRef priv = SOSFullPeerInfoCopyDeviceKey(requestor, error);
+    bool retval = priv && myPeerID &&
+    SOSRingSetLastModifier(ring, myPeerID) &&
+    SOSRingSetBackupViewset_Internal(ring, viewSet) &&
+    SOSRingGenerationSign_Internal(ring, priv, error);
+    CFReleaseNull(priv);
+    return retval;
+}
+
+CFSetRef SOSBackupRingGetViews(SOSRingRef ring, CFErrorRef *error) {
+    return SOSRingGetBackupViewset_Internal(ring);
+}
+
+ringFuncStruct backup = {
+    "Backup",
+    1,
+    SOSRingCreate_Backup,
+    SOSRingResetToEmpty_Basic,
+    SOSRingResetToOffering_Basic,
+    SOSRingDeviceIsInRing_Basic,
+    SOSRingApply_Basic,
+    SOSRingWithdraw_Basic,
+    SOSRingGenerationSign_Basic,
+    SOSRingConcordanceSign_Basic,
+    SOSRingPeerKeyConcordanceTrust_Backup,
+    NULL,
+    NULL,
+    SOSRingSetPayload_Basic,
+    SOSRingGetPayload_Basic,
+};