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>
40 #include "SOSRingUtils.h"
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
);
51 static inline SOSConcordanceStatus
CheckPeerStatus(CFStringRef peerID
, SOSPeerInfoRef peer
, SOSRingRef ring
, SecKeyRef userPub
, CFErrorRef
*error
) {
52 SOSConcordanceStatus result
= kSOSConcordanceNoPeer
;
53 SecKeyRef pubKey
= NULL
;
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
);
63 result
= kSOSConcordanceTrusted
;
66 CFReleaseNull(pubKey
);
70 static inline SOSConcordanceStatus
CombineStatus(SOSConcordanceStatus status1
, SOSConcordanceStatus status2
)
72 if (status1
== kSOSConcordanceTrusted
|| status2
== kSOSConcordanceTrusted
)
73 return kSOSConcordanceTrusted
;
75 if (status1
== kSOSConcordanceBadPeerSig
|| status2
== kSOSConcordanceBadPeerSig
)
76 return kSOSConcordanceBadPeerSig
;
78 if (status1
== kSOSConcordanceNoPeerSig
|| status2
== kSOSConcordanceNoPeerSig
)
79 return kSOSConcordanceNoPeerSig
;
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
);
92 secnotice("ring", "concordance-signer-status: %@ -> %d", peerID
, peerStatus
);
94 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
95 (CFEqualSafe(SOSPeerInfoGetPeerID(pi
), excludePeerID
) || SOSPeerInfoIsCloudIdentity(pi
)))
96 peerStatus
= kSOSConcordanceNoPeer
;
98 status
= CombineStatus(status
, peerStatus
);
105 SOSConcordanceStatus
GetSignersStatus_Transitive(CFSetRef peers
, SOSRingRef signersRing
, SOSRingRef statusRing
,
106 SecKeyRef userPubkey
, CFStringRef excludePeerID
, CFErrorRef
*error
) {
107 __block SOSConcordanceStatus status
= kSOSConcordanceNoPeer
;
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
);
115 if (peerStatus
== kSOSConcordanceNoPeerSig
&&
116 (CFEqualSafe(SOSPeerInfoGetPeerID(pi
), excludePeerID
) || SOSPeerInfoIsCloudIdentity(pi
)))
117 peerStatus
= kSOSConcordanceNoPeer
;
119 status
= CombineStatus(status
, peerStatus
);
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
;
135 if (SOSRingIsEmpty_Internal(proposedRing
)) {
136 return kSOSConcordanceTrusted
;
139 if(!SOSRingVerifySignatureExists(proposedRing
, userPubkey
, error
)) {
140 SOSCreateError(kSOSErrorBadSignature
, CFSTR("No public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
141 return kSOSConcordanceNoUserSig
;
144 if(!SOSRingVerify(proposedRing
, userPubkey
, error
)) {
145 SOSCreateError(kSOSErrorBadSignature
, CFSTR("Bad public signature"), (error
!= NULL
) ? *error
: NULL
, error
);
146 return kSOSConcordanceBadUserSig
;
149 if (SOSRingIsEmpty_Internal(knownRing
) || SOSRingIsOffering_Internal(proposedRing
)) {
150 return GetSignersStatus(peers
, proposedRing
, proposedRing
, userPubkey
, NULL
, error
);
153 if(SOSRingIsOlderGeneration(proposedRing
, knownRing
)) {
154 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
155 return kSOSConcordanceGenOld
;
158 if(knownPubkey
== NULL
) knownPubkey
= userPubkey
;
159 if(!SOSRingVerify(knownRing
, knownPubkey
, error
)) knownPubkey
= userPubkey
;
160 return GetSignersStatus(peers
, knownRing
, proposedRing
, knownPubkey
, CFSTR("novalue"), error
);
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
;
172 if (SOSRingIsEmpty_Internal(proposedRing
)) {
173 secnotice("ring", "ring empty -> trusted");
174 return kSOSConcordanceTrusted
;
177 if (SOSRingIsEmpty_Internal(knownRing
) || SOSRingIsOffering_Internal(proposedRing
)) {
178 return GetSignersStatus(peers
, proposedRing
, proposedRing
, userPubkey
, NULL
, error
);
181 if(SOSRingIsOlderGeneration(proposedRing
, knownRing
)) {
182 SOSCreateError(kSOSErrorReplay
, CFSTR("Bad generation"), NULL
, error
);
183 return kSOSConcordanceGenOld
;
185 return GetSignersStatus(peers
, knownRing
, proposedRing
, userPubkey
, excludePeerID
, error
);