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