2 // SOSRingConcordanceTrust.c
5 // Created by Richard Murphy on 3/15/15.
9 #include <AssertMacros.h>
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>
18 #include <Security/SecKey.h>
19 #include <Security/SecKeyPriv.h>
20 #include <CoreFoundation/CoreFoundation.h>
22 #include <utilities/SecCFWrappers.h>
24 //#include "ckdUtilities.h"
26 #include <corecrypto/ccder.h>
27 #include <corecrypto/ccdigest.h>
28 #include <corecrypto/ccsha2.h>
31 #include <utilities/der_plist.h>
32 #include <utilities/der_plist_internal.h>
33 #include <corecrypto/ccder.h>
34 #include <utilities/der_date.h>
39 #include "SOSRingUtils.h"
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
);
50 static inline SOSConcordanceStatus
CheckPeerStatus(CFStringRef peerID
, SOSPeerInfoRef peer
, SOSRingRef ring
, SecKeyRef userPub
, CFErrorRef
*error
) {
51 SOSConcordanceStatus result
= kSOSConcordanceNoPeer
;
52 SecKeyRef pubKey
= NULL
;
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
);
62 result
= kSOSConcordanceTrusted
;
65 CFReleaseNull(pubKey
);
69 static inline SOSConcordanceStatus
CombineStatus(SOSConcordanceStatus status1
, SOSConcordanceStatus status2
)
71 if (status1
== kSOSConcordanceTrusted
|| status2
== kSOSConcordanceTrusted
)
72 return kSOSConcordanceTrusted
;
74 if (status1
== kSOSConcordanceBadPeerSig
|| status2
== kSOSConcordanceBadPeerSig
)
75 return kSOSConcordanceBadPeerSig
;
77 if (status1
== kSOSConcordanceNoPeerSig
|| status2
== kSOSConcordanceNoPeerSig
)
78 return kSOSConcordanceNoPeerSig
;
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
);
91 secnotice("ring", "concordance-signer-status: %@ -> %d", peerID
, peerStatus
);
93 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
94 (CFEqualSafe(SOSPeerInfoGetPeerID(pi
), excludePeerID
) || SOSPeerInfoIsCloudIdentity(pi
)))
95 peerStatus
= kSOSConcordanceNoPeer
;
97 status
= CombineStatus(status
, peerStatus
);
104 SOSConcordanceStatus
GetSignersStatus_Transitive(CFSetRef peers
, SOSRingRef signersRing
, SOSRingRef statusRing
,
105 SecKeyRef userPubkey
, CFStringRef excludePeerID
, CFErrorRef
*error
) {
106 __block SOSConcordanceStatus status
= kSOSConcordanceNoPeer
;
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
);
114 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
115 (CFEqualSafe(SOSPeerInfoGetPeerID(pi
), excludePeerID
) || SOSPeerInfoIsCloudIdentity(pi
)))
116 peerStatus
= kSOSConcordanceNoPeer
;
118 status
= CombineStatus(status
, peerStatus
);
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
;
134 if (SOSRingIsEmpty_Internal(proposedRing
)) {
135 return kSOSConcordanceTrusted
;
138 if(!SOSRingVerifySignatureExists(proposedRing
, userPubkey
, error
)) {
139 SOSCreateError(kSOSErrorBadSignature
, CFSTR("No public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
140 return kSOSConcordanceNoUserSig
;
143 if(!SOSRingVerify(proposedRing
, userPubkey
, error
)) {
144 SOSCreateError(kSOSErrorBadSignature
, CFSTR("Bad public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
145 return kSOSConcordanceBadUserSig
;
148 if (SOSRingIsEmpty_Internal(knownRing
) || SOSRingIsOffering_Internal(proposedRing
)) {
149 return GetSignersStatus(peers
, proposedRing
, proposedRing
, userPubkey
, NULL
, error
);
152 if(SOSRingIsOlderGeneration(proposedRing
, knownRing
)) {
153 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
154 return kSOSConcordanceGenOld
;
157 if(knownPubkey
== NULL
) knownPubkey
= userPubkey
;
158 if(!SOSRingVerify(knownRing
, knownPubkey
, error
)) knownPubkey
= userPubkey
;
159 return GetSignersStatus(peers
, knownRing
, proposedRing
, knownPubkey
, CFSTR("novalue"), error
);
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
;
171 if (SOSRingIsEmpty_Internal(proposedRing
)) {
172 secnotice("ring", "ring empty -> trusted");
173 return kSOSConcordanceTrusted
;
176 if (SOSRingIsEmpty_Internal(knownRing
) || SOSRingIsOffering_Internal(proposedRing
)) {
177 return GetSignersStatus(peers
, proposedRing
, proposedRing
, userPubkey
, NULL
, error
);
180 if(SOSRingIsOlderGeneration(proposedRing
, knownRing
)) {
181 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
182 return kSOSConcordanceGenOld
;
184 return GetSignersStatus(peers
, knownRing
, proposedRing
, userPubkey
, excludePeerID
, error
);