5 // Created by Richard Murphy on 1/26/15.
9 #include <AssertMacros.h>
10 #include "SOSPeerInfoV2.h"
11 #include <Security/SecureObjectSync/SOSInternal.h>
12 #include <Security/SecureObjectSync/SOSAccountPriv.h>
13 #include <utilities/der_plist.h>
14 #include <utilities/der_plist_internal.h>
15 #include <corecrypto/ccder.h>
16 #include <utilities/der_date.h>
19 // Description Dictionary Entries Added for V2
20 CFStringRef sV2DictionaryKey
= CFSTR("V2DictionaryData"); // CFData wrapper for V2 extensions
21 CFStringRef sViewsKey
= CFSTR("Views"); // Array of View labels
22 CFStringRef sSerialNumberKey
= CFSTR("SerialNumber");
23 CFStringRef sViewsPending
= CFSTR("ViewsPending"); // Array of View labels (pending)
25 CFStringRef sSecurityPropertiesKey
= CFSTR("SecurityProperties");
26 CFStringRef kSOSHsaCrKeyDictionary
= CFSTR("HSADictionary");
27 CFStringRef sRingState
= CFSTR("RingState");
28 CFStringRef sBackupKeyKey
= CFSTR("BackupKey");
29 CFStringRef sEscrowRecord
= CFSTR("EscrowRecord");
33 // need entitlement for this:
35 #include <MobileGestalt.h>
37 static CFStringRef
SOSCopySerialNumberAsString(CFErrorRef
*error
) {
38 CFTypeRef iosAnswer
= (CFStringRef
) MGCopyAnswer(kMGQSerialNumber
, NULL
);
40 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
);
42 return (CFStringRef
) iosAnswer
;
47 #include <CoreFoundation/CoreFoundation.h>
48 #include <IOKit/IOKitLib.h>
50 static CFStringRef
SOSCopySerialNumberAsString(CFErrorRef
*error
) {
51 CFStringRef serialNumber
= NULL
;
52 CFStringRef retval
= NULL
;
54 io_service_t platformExpert
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOServiceMatching("IOPlatformExpertDevice"));
55 require_action_quiet(platformExpert
, errOut
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
));
56 serialNumber
= IORegistryEntryCreateCFProperty(platformExpert
, CFSTR(kIOPlatformSerialNumberKey
), kCFAllocatorDefault
, 0);
57 if(serialNumber
) retval
= CFStringCreateCopy(kCFAllocatorDefault
, serialNumber
);
58 IOObjectRelease(platformExpert
);
59 CFReleaseNull(serialNumber
);
66 bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi
) {
67 CFStringRef serial
= SOSPeerInfoV2DictionaryCopyString(pi
, sSerialNumberKey
);
68 bool retval
= (serial
!= NULL
);
69 CFReleaseNull(serial
);
73 void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi
) {
74 CFStringRef serialNumber
= SOSCopySerialNumberAsString(NULL
);
75 if(serialNumber
) SOSPeerInfoV2DictionarySetValue(pi
, sSerialNumberKey
, serialNumber
);
76 CFReleaseNull(serialNumber
);
79 static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi
) {
83 if(!SOSPeerInfoVersionHasV2Data(pi
)) {
89 static CFDataRef
SOSPeerInfoGetV2Data(SOSPeerInfoRef pi
) {
90 if(SOSPeerInfoV2SanityCheck(pi
) == false) return NULL
;
91 return CFDictionaryGetValue(pi
->description
, sV2DictionaryKey
);
94 static CFMutableDictionaryRef
SOSCreateDictionaryFromDER(CFDataRef v2Data
, CFErrorRef
*error
) {
95 CFMutableDictionaryRef retval
= NULL
;
96 CFPropertyListRef pl
= NULL
;
99 secerror("Creating raw dictionary instead of creating from DER");
100 return CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
103 if(CFGetTypeID(v2Data
) != CFDataGetTypeID()) {
104 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Corrupted v2Data Item"), NULL
, error
);
108 const uint8_t *der_p
= CFDataGetBytePtr(v2Data
);
109 const uint8_t *der_end
= CFDataGetLength(v2Data
) + der_p
;
111 der_p
= der_decode_plist(NULL
, kCFPropertyListImmutable
, &pl
, error
, der_p
, der_end
);
113 if (der_p
== NULL
|| der_p
!= der_end
) {
114 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Format of Dictionary DER"), NULL
, error
);
118 if (CFGetTypeID(pl
) != CFDictionaryGetTypeID()) {
119 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(pl
));
120 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
121 CFSTR("Expected dictionary got %@"), description
);
122 CFReleaseSafe(description
);
127 retval
= (CFMutableDictionaryRef
) pl
;
131 CFReleaseNull(retval
);
136 static CFDataRef
SOSCreateDERFromDictionary(CFDictionaryRef di
, CFErrorRef
*error
) {
137 size_t size
= der_sizeof_plist(di
, error
);
138 if (size
== 0) return NULL
;
140 der_encode_plist(di
, error
, der
, der
+size
);
141 return CFDataCreate(kCFAllocatorDefault
, der
, size
);
145 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
147 CFDataRef v2data
= NULL
;
148 if(!pi
) return false;
150 SOSPeerInfoSetVersionNumber(pi
, PEERINFO_CURRENT_VERSION
);
151 CFMutableDictionaryRef v2Dictionary
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
152 CFStringRef serialNumber
= SOSCopySerialNumberAsString(error
);
153 if(serialNumber
== NULL
) {
154 secnotice("signing", "serialNumber was returned NULL\n");
156 CFMutableSetRef views
= SOSViewsCreateDefault(false, error
);
157 CFMutableSetRef secproperties
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
158 if(serialNumber
) CFDictionaryAddValue(v2Dictionary
, sSerialNumberKey
, serialNumber
);
159 CFDictionaryAddValue(v2Dictionary
, sViewsKey
, views
);
160 CFDictionaryAddValue(v2Dictionary
, sSecurityPropertiesKey
, secproperties
);
162 if (whichTransportType
== kSOSTransportFuture
|| whichTransportType
== kSOSTransportIDS
){
163 CFDictionaryAddValue(v2Dictionary
, sDeviceID
, CFSTR(""));
164 CFDictionaryAddValue(v2Dictionary
, sTransportType
, SOSTransportMessageTypeIDS
);
165 CFDictionaryAddValue(v2Dictionary
, sPreferIDS
, kCFBooleanTrue
);
168 CFDictionaryAddValue(v2Dictionary
, sDeviceID
, CFSTR(""));
169 CFDictionaryAddValue(v2Dictionary
, sTransportType
, SOSTransportMessageTypeKVS
);
170 CFDictionaryAddValue(v2Dictionary
, sPreferIDS
, kCFBooleanTrue
);
172 require_action_quiet((v2data
= SOSCreateDERFromDictionary(v2Dictionary
, error
)), out
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
));
173 CFDictionaryAddValue(pi
->description
, sV2DictionaryKey
, v2data
);
174 //SOSPeerInfoExpandV2Data(pi, error);
177 CFReleaseNull(views
);
178 CFReleaseNull(secproperties
);
179 CFReleaseNull(v2data
);
180 CFReleaseNull(v2Dictionary
);
181 CFReleaseNull(serialNumber
);
185 void SOSPeerInfoPackV2Data(SOSPeerInfoRef pi
) {
186 require(SOSPeerInfoV2SanityCheck(pi
), errOut
);
187 require_quiet(pi
->v2Dictionary
, errOut
);
188 CFDataRef v2der
= SOSCreateDERFromDictionary(pi
->v2Dictionary
, NULL
);
189 CFDictionarySetValue(pi
->description
, sV2DictionaryKey
, v2der
);
190 CFReleaseNull(v2der
);
195 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
196 CFDataRef v2data
= NULL
;
199 require_quiet(pi
, out
);
200 CFReleaseNull(pi
->v2Dictionary
);
201 require_action_quiet((v2data
= SOSPeerInfoGetV2Data(pi
)), out
, SOSCreateError(kSOSErrorDecodeFailure
, CFSTR("No V2 Data in description"), NULL
, error
));
202 require_action_quiet((pi
->v2Dictionary
= SOSCreateDictionaryFromDER(v2data
, error
)), out
, SOSCreateError(kSOSErrorDecodeFailure
, CFSTR("Can't expand V2 Dictionary"), NULL
, error
));
208 void SOSPeerInfoV2DictionarySetValue(SOSPeerInfoRef pi
, const void *key
, const void *value
) {
209 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
211 CFDictionaryRemoveValue(pi
->v2Dictionary
, key
);
213 CFDictionarySetValue(pi
->v2Dictionary
, key
, value
);
214 SOSPeerInfoPackV2Data(pi
);
219 void SOSPeerInfoV2DictionaryRemoveValue(SOSPeerInfoRef pi
, const void *key
) {
220 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
221 CFDictionaryRemoveValue(pi
->v2Dictionary
, key
);
222 SOSPeerInfoPackV2Data(pi
);
227 bool SOSPeerInfoV2DictionaryHasBoolean(SOSPeerInfoRef pi
, const void *key
) {
228 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
229 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
230 if(asBoolean(value
,NULL
) != NULL
)
237 bool SOSPeerInfoV2DictionaryHasString(SOSPeerInfoRef pi
, const void *key
) {
238 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
239 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
240 if(asString(value
,NULL
) != NULL
)
246 bool SOSPeerInfoV2DictionaryHasSet(SOSPeerInfoRef pi
, const void *key
) {
247 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
248 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
249 if(asSet(value
,NULL
) != NULL
)
255 bool SOSPeerInfoV2DictionaryHasData(SOSPeerInfoRef pi
, const void *key
) {
256 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
257 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
258 if(asData(value
,NULL
) != NULL
)
264 const CFMutableStringRef
SOSPeerInfoV2DictionaryCopyString(SOSPeerInfoRef pi
, const void *key
) {
265 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
266 CFStringRef value
= asString(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
268 return CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(value
), value
);
273 static void SOSPeerInfoV2DictionaryWithValue(SOSPeerInfoRef pi
, const void *key
, void(^operation
)(CFTypeRef value
)) {
274 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
275 CFTypeRef value
= CFRetainSafe(CFDictionaryGetValue(pi
->v2Dictionary
, key
));
277 CFReleaseNull(value
);
282 void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi
, const void *key
, void(^operation
)(CFSetRef set
)) {
283 SOSPeerInfoV2DictionaryWithValue(pi
, key
, ^(CFTypeRef value
) {
284 CFSetRef set
= asSet(value
, NULL
);
291 const CFMutableSetRef
SOSPeerInfoV2DictionaryCopySet(SOSPeerInfoRef pi
, const void *key
) {
292 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
293 CFSetRef value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
295 return CFSetCreateMutableCopy(kCFAllocatorDefault
, CFSetGetCount(value
), value
);
300 void SOSPeerInfoV2DictionaryForEachSetValue(SOSPeerInfoRef pi
, const void *key
, void (^action
)(const void* value
)) {
301 CFSetRef value
= NULL
;
302 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
303 value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
307 CFSetForEach(value
, action
);
311 bool SOSPeerInfoV2DictionaryHasSetContaining(SOSPeerInfoRef pi
, const void *key
, const void* member
) {
312 CFSetRef value
= NULL
;
313 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
314 value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
316 return value
&& CFSetContainsValue(value
, member
);
319 const CFMutableDataRef
SOSPeerInfoV2DictionaryCopyData(SOSPeerInfoRef pi
, const void *key
) {
320 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
321 CFDataRef value
= asData(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
323 return CFDataCreateMutableCopy(kCFAllocatorDefault
, CFDataGetLength(value
), value
);
328 const CFBooleanRef
SOSPeerInfoV2DictionaryCopyBoolean(SOSPeerInfoRef pi
, const void *key
) {
329 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
330 CFBooleanRef value
= asBoolean(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
332 return CFRetainSafe(value
);
337 const CFMutableDictionaryRef
SOSPeerInfoV2DictionaryCopyDictionary(SOSPeerInfoRef pi
, const void *key
) {
338 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
339 CFDictionaryRef value
= asDictionary(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
341 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(value
), value
);