5 // Created by Richard Murphy on 1/26/15.
9 #include <AssertMacros.h>
10 #include "SOSPeerInfoV2.h"
11 #include "keychain/SecureObjectSync/SOSInternal.h"
12 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
13 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
14 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
15 #include <utilities/der_plist.h>
16 #include <utilities/der_plist_internal.h>
17 #include <corecrypto/ccder.h>
18 #include <utilities/der_date.h>
21 // Description Dictionary Entries Added for V2
22 CFStringRef sV2DictionaryKey = CFSTR("V2DictionaryData"); // CFData wrapper for V2 extensions
23 CFStringRef sViewsKey = CFSTR("Views"); // Array of View labels
24 CFStringRef sSerialNumberKey = CFSTR("SerialNumber");
25 CFStringRef sMachineIDKey = CFSTR("MachineIDKey");
26 CFStringRef sViewsPending = CFSTR("ViewsPending"); // Array of View labels (pending)
28 CFStringRef kSOSHsaCrKeyDictionary = CFSTR("HSADictionary");
29 CFStringRef sRingState = CFSTR("RingState");
30 CFStringRef sBackupKeyKey = CFSTR("BackupKey");
31 CFStringRef sEscrowRecord = CFSTR("EscrowRecord");
33 CFStringRef SOSGestaltSerial = NULL;
37 // need entitlement for this:
39 #include <MobileGestalt.h>
41 static CFStringRef SOSCopySerialNumberAsString(CFErrorRef *error) {
43 return CFRetain(SOSGestaltSerial);
45 CFTypeRef iosAnswer = (CFStringRef) MGCopyAnswer(kMGQSerialNumber, NULL);
47 SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error);
49 return (CFStringRef) iosAnswer;
54 #include <CoreFoundation/CoreFoundation.h>
55 #include <IOKit/IOKitLib.h>
57 static CFStringRef SOSCopySerialNumberAsString(CFErrorRef *error) {
59 return CFRetain(SOSGestaltSerial);
60 CFStringRef serialNumber = NULL;
61 CFStringRef retval = NULL;
63 io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
64 require_action_quiet(platformExpert, errOut, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error));
65 serialNumber = IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
66 if(serialNumber) retval = CFStringCreateCopy(kCFAllocatorDefault, serialNumber);
67 IOObjectRelease(platformExpert);
68 CFReleaseNull(serialNumber);
75 bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi) {
76 CFStringRef serial = SOSPeerInfoV2DictionaryCopyString(pi, sSerialNumberKey);
77 bool retval = (serial != NULL);
78 CFReleaseNull(serial);
82 void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi) {
83 CFStringRef serialNumber = SOSCopySerialNumberAsString(NULL);
84 if(serialNumber) SOSPeerInfoV2DictionarySetValue(pi, sSerialNumberKey, serialNumber);
85 CFReleaseNull(serialNumber);
88 const CFStringRef SOSSerialUnknown = CFSTR("Unknown");
90 void SOSPeerInfoSetTestSerialNumber(SOSPeerInfoRef pi, CFStringRef serialNumber) {
91 if(serialNumber) SOSPeerInfoV2DictionarySetValue(pi, sSerialNumberKey, serialNumber);
94 CFStringRef SOSPeerInfoCopySerialNumber(SOSPeerInfoRef pi) {
95 CFStringRef retval = SOSPeerInfoV2DictionaryCopyString(pi, sSerialNumberKey);
96 return (retval ? retval : CFRetain(SOSSerialUnknown));
99 static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi) {
103 if(!SOSPeerInfoVersionHasV2Data(pi)) {
109 static CFDataRef SOSPeerInfoGetV2Data(SOSPeerInfoRef pi) {
110 if(SOSPeerInfoV2SanityCheck(pi) == false) return NULL;
111 return asData(CFDictionaryGetValue(pi->description, sV2DictionaryKey), NULL);
114 static CFMutableDictionaryRef SOSCreateDictionaryFromDER(CFDataRef v2Data, CFErrorRef *error) {
115 CFPropertyListRef pl = NULL;
118 secerror("Creating raw dictionary instead of creating from DER");
119 return CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
122 if(CFGetTypeID(v2Data) != CFDataGetTypeID()) {
123 SOSCreateError(kSOSErrorBadFormat, CFSTR("Corrupted v2Data Item"), NULL, error);
127 const uint8_t *der_p = CFDataGetBytePtr(v2Data);
128 const uint8_t *der_end = CFDataGetLength(v2Data) + der_p;
130 der_p = der_decode_plist(NULL, &pl, error, der_p, der_end);
132 if (der_p == NULL || der_p != der_end) {
133 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Dictionary DER"), NULL, error);
137 if (CFGetTypeID(pl) != CFDictionaryGetTypeID()) {
138 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(pl));
139 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
140 CFSTR("Expected dictionary got %@"), description);
141 CFReleaseNull(description);
146 return (CFMutableDictionaryRef) pl;
154 static CFDataRef SOSCreateDERFromDictionary(CFDictionaryRef di, CFErrorRef *error) {
155 size_t size = der_sizeof_plist(di, error);
159 uint8_t *der = malloc(size);
163 if (der_encode_plist(di, error, der, der+size) == NULL) {
167 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, size, kCFAllocatorMalloc);
171 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi, CFErrorRef *error) {
173 CFDataRef v2data = NULL;
174 if(!pi) return false;
176 SOSPeerInfoSetVersionNumber(pi, PEERINFO_CURRENT_VERSION);
177 CFMutableDictionaryRef v2Dictionary = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
178 CFMutableSetRef views = SOSViewCopyViewSet(kViewSetDefault);
179 CFMutableSetRef secproperties = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
180 CFDictionaryAddValue(v2Dictionary, sViewsKey, views);
182 require_action_quiet((v2data = SOSCreateDERFromDictionary(v2Dictionary, error)), out, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error));
183 CFDictionaryAddValue(pi->description, sV2DictionaryKey, v2data);
184 // To use the central serial number setting routine this must be done after the V2 dictionary is installed.
185 SOSPeerInfoSetSerialNumber(pi);
186 SOSPeerInfoExpandV2Data(pi, error);
189 CFReleaseNull(views);
190 CFReleaseNull(v2data);
191 CFReleaseNull(v2Dictionary);
192 CFReleaseNull(secproperties);
196 void SOSPeerInfoPackV2Data(SOSPeerInfoRef pi) {
197 require(SOSPeerInfoV2SanityCheck(pi), errOut);
198 require_quiet(pi->v2Dictionary, errOut);
199 CFDataRef v2der = SOSCreateDERFromDictionary(pi->v2Dictionary, NULL);
200 CFDictionarySetValue(pi->description, sV2DictionaryKey, v2der);
201 CFReleaseNull(v2der);
206 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi, CFErrorRef *error) {
207 CFDataRef v2data = NULL;
208 CFMutableDictionaryRef v2Dictionary = NULL;
210 require_action_quiet((v2data = SOSPeerInfoGetV2Data(pi)), out, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("No V2 Data in description"), NULL, error));
211 require_action_quiet((v2Dictionary = SOSCreateDictionaryFromDER(v2data, error)), out, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Can't expand V2 Dictionary"), NULL, error));
212 CFReleaseNull(pi->v2Dictionary);
213 pi->v2Dictionary = v2Dictionary;
217 CFReleaseNull(v2Dictionary);
222 void SOSPeerInfoV2DictionarySetValue(SOSPeerInfoRef pi, const void *key, const void *value) {
223 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
225 CFDictionaryRemoveValue(pi->v2Dictionary, key);
227 CFDictionarySetValue(pi->v2Dictionary, key, value);
228 SOSPeerInfoPackV2Data(pi);
233 void SOSPeerInfoV2DictionaryRemoveValue(SOSPeerInfoRef pi, const void *key) {
234 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
235 CFDictionaryRemoveValue(pi->v2Dictionary, key);
236 SOSPeerInfoPackV2Data(pi);
241 bool SOSPeerInfoV2DictionaryHasBoolean(SOSPeerInfoRef pi, const void *key) {
242 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
243 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
244 if(asBoolean(value,NULL) != NULL)
250 // Not API to prevent owenership confusion
251 static CFStringRef SOSPeerInfoV2DictionaryGetAsString(SOSPeerInfoRef pi, const void *key) {
252 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
253 return asString(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
259 bool SOSPeerInfoV2DictionaryHasStringValue(SOSPeerInfoRef pi, const void *key, CFStringRef value) {
260 return CFEqualSafe(SOSPeerInfoV2DictionaryGetAsString(pi, key), value);
263 bool SOSPeerInfoV2DictionaryHasString(SOSPeerInfoRef pi, const void *key) {
264 CFStringRef possibleID = SOSPeerInfoV2DictionaryGetAsString(pi, key);
265 return possibleID != NULL && CFStringGetLength(possibleID) > 0;
268 bool SOSPeerInfoV2DictionaryHasSet(SOSPeerInfoRef pi, const void *key) {
269 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
270 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
271 if(asSet(value,NULL) != NULL)
277 bool SOSPeerInfoV2DictionaryHasData(SOSPeerInfoRef pi, const void *key) {
278 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
279 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
280 if(asData(value,NULL) != NULL)
286 CFMutableStringRef SOSPeerInfoV2DictionaryCopyString(SOSPeerInfoRef pi, const void *key) {
287 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
288 CFStringRef value = asString(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
290 return CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(value), value);
295 static void SOSPeerInfoV2DictionaryWithValue(SOSPeerInfoRef pi, const void *key, void(^operation)(CFTypeRef value)) {
296 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
297 CFTypeRef value = CFRetainSafe(CFDictionaryGetValue(pi->v2Dictionary, key));
299 CFReleaseNull(value);
304 void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi, const void *key, void(^operation)(CFSetRef set)) {
305 SOSPeerInfoV2DictionaryWithValue(pi, key, ^(CFTypeRef value) {
306 CFSetRef set = asSet(value, NULL);
313 CFMutableSetRef SOSPeerInfoV2DictionaryCopySet(SOSPeerInfoRef pi, const void *key) {
314 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
315 CFSetRef value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
317 return CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(value), value);
322 void SOSPeerInfoV2DictionaryForEachSetValue(SOSPeerInfoRef pi, const void *key, void (^action)(const void* value)) {
323 CFSetRef value = NULL;
324 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
325 value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
329 CFSetForEach(value, action);
333 bool SOSPeerInfoV2DictionaryHasSetContaining(SOSPeerInfoRef pi, const void *key, const void* member) {
334 CFSetRef value = NULL;
335 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
336 value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
338 return value && CFSetContainsValue(value, member);
341 CFMutableDataRef SOSPeerInfoV2DictionaryCopyData(SOSPeerInfoRef pi, const void *key) {
342 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
343 CFDataRef value = asData(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
345 return CFDataCreateMutableCopy(kCFAllocatorDefault, CFDataGetLength(value), value);
350 CFBooleanRef SOSPeerInfoV2DictionaryCopyBoolean(SOSPeerInfoRef pi, const void *key) {
351 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
352 CFBooleanRef value = asBoolean(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
354 return CFRetainSafe(value);
359 CFMutableDictionaryRef SOSPeerInfoV2DictionaryCopyDictionary(SOSPeerInfoRef pi, const void *key) {
360 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
361 CFDictionaryRef value = asDictionary(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
363 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(value), value);
369 SOSPeerInfoRef SOSPeerInfoCopyWithV2DictionaryUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef newv2dict, SecKeyRef signingKey, CFErrorRef* error) {
370 SOSPeerInfoRef retval = SOSPeerInfoCreateCopy(kCFAllocatorDefault, toCopy, error);
371 require_quiet(retval, errOut);
372 require_action_quiet(SOSPeerInfoExpandV2Data(retval, error), errOut, CFReleaseNull(retval));
373 CFDictionaryForEach(newv2dict, ^(const void *key, const void *value) {
374 CFDictionarySetValue(retval->v2Dictionary, key, value);
376 SOSPeerInfoPackV2Data(retval);
377 require_action_quiet(SOSPeerInfoSign(signingKey, retval, error), errOut, CFReleaseNull(retval));