]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSRingConcordanceTrust.c
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / 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 "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 }