SOSRingConcordanceTrust.c
1 // 2 // SOSRingConcordanceTrust.c 3 // sec 4 // 5 // Created by Richard Murphy on 3/15/15. 6 // 7 // 8 9 #include <AssertMacros.h> 10 11 #include "keychain/SecureObjectSync/SOSInternal.h" 12 #include "keychain/SecureObjectSync/SOSPeer.h" 13 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h" 14 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h" 15 #include "keychain/SecureObjectSync/SOSCircle.h" 16 #include <Security/SecFramework.h> 17 18 #include <Security/SecKey.h> 19 #include <Security/SecKeyPriv.h> 20 #include <CoreFoundation/CoreFoundation.h> 21 22 #include <utilities/SecCFWrappers.h> 23 24 //#include "ckdUtilities.h" 25 26 #include <corecrypto/ccder.h> 27 #include <corecrypto/ccdigest.h> 28 #include <corecrypto/ccsha2.h> 29 30 31 #include <utilities/der_plist.h> 32 #include <utilities/der_plist_internal.h> 33 #include <corecrypto/ccder.h> 34 #include <utilities/der_date.h> 35 36 #include <stdlib.h> 37 38 #include "SOSRing.h" 39 #include "SOSRingUtils.h" 40 41 static inline CFDictionaryRef SOSPeerInfoDictionaryCreate(CFSetRef peers) { 42 size_t n = CFSetGetCount(peers); 43 SOSPeerInfoRef peerInfos[n]; 44 CFStringRef peerIDs[n]; 45 CFSetGetValues(peers, (const void **) peerInfos); 46 for(size_t i = 0; i < n; i++) peerIDs[i] = SOSPeerInfoGetPeerID(peerInfos[i]); 47 return CFDictionaryCreate(NULL, (const void **)peerIDs, (const void **)peerInfos, n, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 48 } 49 50 static inline SOSConcordanceStatus CheckPeerStatus(CFStringRef peerID, SOSPeerInfoRef peer, SOSRingRef ring, SecKeyRef userPub, CFErrorRef *error) { 51 SOSConcordanceStatus result = kSOSConcordanceNoPeer; 52 SecKeyRef pubKey = NULL; 53 54 require_action_quiet(peer, exit, result = kSOSConcordanceNoPeer); 55 pubKey = SOSPeerInfoCopyPubKey(peer, error); 56 require_quiet(pubKey, exit); 57 require_action_quiet(SOSRingHasPeerID(ring, peerID), exit, result = kSOSConcordanceNoPeer); 58 require_action_quiet(SOSPeerInfoApplicationVerify(peer, userPub, NULL), exit, result = kSOSConcordanceNoPeer); 59 require_action_quiet(SOSRingVerifySignatureExists(ring, pubKey, error), exit, result = kSOSConcordanceNoPeerSig); 60 require_action_quiet(SOSRingVerify(ring, pubKey, error), exit, result = kSOSConcordanceBadPeerSig); 61 62 result = kSOSConcordanceTrusted; 63 64 exit: 65 CFReleaseNull(pubKey); 66 return result; 67 } 68 69 static inline SOSConcordanceStatus CombineStatus(SOSConcordanceStatus status1, SOSConcordanceStatus status2) 70 { 71 if (status1 == kSOSConcordanceTrusted || status2 == kSOSConcordanceTrusted) 72 return kSOSConcordanceTrusted; 73 74 if (status1 == kSOSConcordanceBadPeerSig || status2 == kSOSConcordanceBadPeerSig) 75 return kSOSConcordanceBadPeerSig; 76 77 if (status1 == kSOSConcordanceNoPeerSig || status2 == kSOSConcordanceNoPeerSig) 78 return kSOSConcordanceNoPeerSig; 79 80 return status1; 81 } 82 83 SOSConcordanceStatus GetSignersStatus(CFSetRef peers, SOSRingRef signersRing, SOSRingRef statusRing, 84 SecKeyRef userPubkey, CFStringRef excludePeerID, CFErrorRef *error) { 85 CFDictionaryRef ringPeerInfos = SOSPeerInfoDictionaryCreate(peers); 86 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer; 87 SOSRingForEachPeerID(signersRing, ^(CFStringRef peerID) { 88 SOSPeerInfoRef pi = (SOSPeerInfoRef) CFDictionaryGetValue(ringPeerInfos, peerID); 89 SOSConcordanceStatus peerStatus = CheckPeerStatus(peerID, pi, statusRing, userPubkey, error); 90 91 secnotice("ring", "concordance-signer-status: %@ -> %d", peerID, peerStatus); 92 93 if (peerStatus == kSOSConcordanceNoPeerSig && 94 (CFEqualSafe(SOSPeerInfoGetPeerID(pi), excludePeerID) || SOSPeerInfoIsCloudIdentity(pi))) 95 peerStatus = kSOSConcordanceNoPeer; 96 97 status = CombineStatus(status, peerStatus); 98 }); 99 100 return status; 101 } 102 103 104 SOSConcordanceStatus GetSignersStatus_Transitive(CFSetRef peers, SOSRingRef signersRing, SOSRingRef statusRing, 105 SecKeyRef userPubkey, CFStringRef excludePeerID, CFErrorRef *error) { 106 __block SOSConcordanceStatus status = kSOSConcordanceNoPeer; 107 108 CFSetForEach(peers, ^(const void *value) { 109 SOSPeerInfoRef pi = (SOSPeerInfoRef) value; 110 CFStringRef peerID = SOSPeerInfoGetPeerID(pi); 111 if(SOSRingHasPeerWithID(statusRing, peerID, NULL)) { 112 SOSConcordanceStatus peerStatus = CheckPeerStatus(peerID, pi, statusRing, userPubkey, error); 113 114 if (peerStatus == kSOSConcordanceNoPeerSig && 115 (CFEqualSafe(SOSPeerInfoGetPeerID(pi), excludePeerID) || SOSPeerInfoIsCloudIdentity(pi))) 116 peerStatus = kSOSConcordanceNoPeer; 117 118 status = CombineStatus(status, peerStatus); 119 } 120 }); 121 122 return status; 123 } 124 125 126 SOSConcordanceStatus SOSRingUserKeyConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef peers, SOSRingRef knownRing, SOSRingRef proposedRing, 127 SecKeyRef knownPubkey, SecKeyRef userPubkey, 128 CFStringRef excludePeerID, CFErrorRef *error) { 129 if(userPubkey == NULL) { 130 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key"), NULL, error); 131 return kSOSConcordanceNoUserKey; 132 } 133 134 if (SOSRingIsEmpty_Internal(proposedRing)) { 135 return kSOSConcordanceTrusted; 136 } 137 138 if(!SOSRingVerifySignatureExists(proposedRing, userPubkey, error)) { 139 SOSCreateError(kSOSErrorBadSignature, CFSTR("No public signature"), (error != NULL) ? *error : NULL, error); 140 return kSOSConcordanceNoUserSig; 141 } 142 143 if(!SOSRingVerify(proposedRing, userPubkey, error)) { 144 SOSCreateError(kSOSErrorBadSignature, CFSTR("Bad public signature"), (error != NULL) ? *error : NULL, error); 145 return kSOSConcordanceBadUserSig; 146 } 147 148 if (SOSRingIsEmpty_Internal(knownRing) || SOSRingIsOffering_Internal(proposedRing)) { 149 return GetSignersStatus(peers, proposedRing, proposedRing, userPubkey, NULL, error); 150 } 151 152 if(SOSRingIsOlderGeneration(proposedRing, knownRing)) { 153 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error); 154 return kSOSConcordanceGenOld; 155 } 156 157 if(knownPubkey == NULL) knownPubkey = userPubkey; 158 if(!SOSRingVerify(knownRing, knownPubkey, error)) knownPubkey = userPubkey; 159 return GetSignersStatus(peers, knownRing, proposedRing, knownPubkey, CFSTR("novalue"), error); 160 } 161 162 163 SOSConcordanceStatus SOSRingPeerKeyConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef peers, SOSRingRef knownRing, SOSRingRef proposedRing, 164 __unused SecKeyRef knownPubkey, SecKeyRef userPubkey, 165 CFStringRef excludePeerID, CFErrorRef *error) { 166 if(userPubkey == NULL) { 167 SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Concordance with no public key - need to validate application"), NULL, error); 168 return kSOSConcordanceNoUserKey; 169 } 170 171 if (SOSRingIsEmpty_Internal(proposedRing)) { 172 secnotice("ring", "ring empty -> trusted"); 173 return kSOSConcordanceTrusted; 174 } 175 176 if (SOSRingIsEmpty_Internal(knownRing) || SOSRingIsOffering_Internal(proposedRing)) { 177 return GetSignersStatus(peers, proposedRing, proposedRing, userPubkey, NULL, error); 178 } 179 180 if(SOSRingIsOlderGeneration(proposedRing, knownRing)) { 181 SOSCreateError(kSOSErrorReplay, CFSTR("Bad generation"), NULL, error); 182 return kSOSConcordanceGenOld; 183 } 184 return GetSignersStatus(peers, knownRing, proposedRing, userPubkey, excludePeerID, error); 185 }