]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.m
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSPeerInfoV2.m
1 //
2 // SOSPeerInfoV2.c
3 // sec
4 //
5 // Created by Richard Murphy on 1/26/15.
6 //
7 //
8
9 #include <AssertMacros.h>
10 #include "SOSPeerInfoV2.h"
11 #include <Security/SecureObjectSync/SOSInternal.h>
12 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
13 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
14 #include <Security/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>
19
20
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)
27
28 CFStringRef kSOSHsaCrKeyDictionary = CFSTR("HSADictionary");
29 CFStringRef sRingState = CFSTR("RingState");
30 CFStringRef sBackupKeyKey = CFSTR("BackupKey");
31 CFStringRef sEscrowRecord = CFSTR("EscrowRecord");
32
33 CFStringRef SOSGestaltSerial = NULL;
34
35 #if TARGET_OS_IPHONE
36
37 // need entitlement for this:
38
39 #include <MobileGestalt.h>
40
41 static CFStringRef SOSCopySerialNumberAsString(CFErrorRef *error) {
42 if (SOSGestaltSerial)
43 return CFRetain(SOSGestaltSerial);
44
45 CFTypeRef iosAnswer = (CFStringRef) MGCopyAnswer(kMGQSerialNumber, NULL);
46 if(!iosAnswer) {
47 SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error);
48 }
49 return (CFStringRef) iosAnswer;
50 }
51
52 #else
53
54 #include <CoreFoundation/CoreFoundation.h>
55 #include <IOKit/IOKitLib.h>
56
57 static CFStringRef SOSCopySerialNumberAsString(CFErrorRef *error) {
58 if (SOSGestaltSerial)
59 return CFRetain(SOSGestaltSerial);
60 CFStringRef serialNumber = NULL;
61 CFStringRef retval = NULL;
62
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);
69 errOut:
70 return retval;
71 }
72
73 #endif
74
75 bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi) {
76 CFStringRef serial = SOSPeerInfoV2DictionaryCopyString(pi, sSerialNumberKey);
77 bool retval = (serial != NULL);
78 CFReleaseNull(serial);
79 return retval;
80 }
81
82 void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi) {
83 CFStringRef serialNumber = SOSCopySerialNumberAsString(NULL);
84 if(serialNumber) SOSPeerInfoV2DictionarySetValue(pi, sSerialNumberKey, serialNumber);
85 CFReleaseNull(serialNumber);
86 }
87
88 const CFStringRef SOSSerialUnknown = CFSTR("Unknown");
89
90 void SOSPeerInfoSetTestSerialNumber(SOSPeerInfoRef pi, CFStringRef serialNumber) {
91 if(serialNumber) SOSPeerInfoV2DictionarySetValue(pi, sSerialNumberKey, serialNumber);
92 }
93
94 CFStringRef SOSPeerInfoCopySerialNumber(SOSPeerInfoRef pi) {
95 CFStringRef retval = SOSPeerInfoV2DictionaryCopyString(pi, sSerialNumberKey);
96 return (retval ? retval : CFRetain(SOSSerialUnknown));
97 }
98
99 CFStringRef SOSPeerInfoCopyOSVersion(SOSPeerInfoRef pi) {
100 return SOSPeerInfoV2DictionaryCopyString(pi, kPIOSVersionKey);
101 }
102
103
104 static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi) {
105 if(!pi) {
106 return false;
107 }
108 if(!SOSPeerInfoVersionHasV2Data(pi)) {
109 return false;
110 }
111 return true;
112 }
113
114 static CFDataRef SOSPeerInfoGetV2Data(SOSPeerInfoRef pi) {
115 if(SOSPeerInfoV2SanityCheck(pi) == false) return NULL;
116 return asData(CFDictionaryGetValue(pi->description, sV2DictionaryKey), NULL);
117 }
118
119 static CFMutableDictionaryRef SOSCreateDictionaryFromDER(CFDataRef v2Data, CFErrorRef *error) {
120 CFPropertyListRef pl = NULL;
121
122 if(!v2Data) {
123 secerror("Creating raw dictionary instead of creating from DER");
124 return CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
125 }
126
127 if(CFGetTypeID(v2Data) != CFDataGetTypeID()) {
128 SOSCreateError(kSOSErrorBadFormat, CFSTR("Corrupted v2Data Item"), NULL, error);
129 goto fail;
130 }
131
132 const uint8_t *der_p = CFDataGetBytePtr(v2Data);
133 const uint8_t *der_end = CFDataGetLength(v2Data) + der_p;
134
135 der_p = der_decode_plist(NULL, kCFPropertyListImmutable, &pl, error, der_p, der_end);
136
137 if (der_p == NULL || der_p != der_end) {
138 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Dictionary DER"), NULL, error);
139 goto fail;
140 }
141
142 if (CFGetTypeID(pl) != CFDictionaryGetTypeID()) {
143 CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(pl));
144 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
145 CFSTR("Expected dictionary got %@"), description);
146 CFReleaseNull(description);
147 CFReleaseNull(pl);
148 goto fail;
149 }
150
151 return (CFMutableDictionaryRef) pl;
152
153 fail:
154 CFReleaseNull(pl);
155 return NULL;
156 }
157
158
159 static CFDataRef SOSCreateDERFromDictionary(CFDictionaryRef di, CFErrorRef *error) {
160 size_t size = der_sizeof_plist(di, error);
161 if (size == 0) {
162 return NULL;
163 }
164 uint8_t *der = malloc(size);
165 if (der == NULL) {
166 return NULL;
167 }
168 if (der_encode_plist(di, error, der, der+size) == NULL) {
169 free(der);
170 return NULL;
171 }
172 return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, der, size, kCFAllocatorMalloc);
173 }
174
175
176 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi, CFErrorRef *error) {
177 bool retval = false;
178 CFDataRef v2data = NULL;
179 if(!pi) return false;
180
181 SOSPeerInfoSetVersionNumber(pi, PEERINFO_CURRENT_VERSION);
182 CFMutableDictionaryRef v2Dictionary = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
183 CFMutableSetRef views = SOSViewCopyViewSet(kViewSetDefault);
184 CFMutableSetRef secproperties = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
185 CFDictionaryAddValue(v2Dictionary, sViewsKey, views);
186
187 require_action_quiet((v2data = SOSCreateDERFromDictionary(v2Dictionary, error)), out, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error));
188 CFDictionaryAddValue(pi->description, sV2DictionaryKey, v2data);
189 // To use the central serial number setting routine this must be done after the V2 dictionary is installed.
190 SOSPeerInfoSetSerialNumber(pi);
191 SOSPeerInfoExpandV2Data(pi, error);
192 retval = true;
193 out:
194 CFReleaseNull(views);
195 CFReleaseNull(v2data);
196 CFReleaseNull(v2Dictionary);
197 CFReleaseNull(secproperties);
198 return retval;
199 }
200
201 void SOSPeerInfoPackV2Data(SOSPeerInfoRef pi) {
202 require(SOSPeerInfoV2SanityCheck(pi), errOut);
203 require_quiet(pi->v2Dictionary, errOut);
204 CFDataRef v2der = SOSCreateDERFromDictionary(pi->v2Dictionary, NULL);
205 CFDictionarySetValue(pi->description, sV2DictionaryKey, v2der);
206 CFReleaseNull(v2der);
207 errOut:
208 return;
209 }
210
211 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi, CFErrorRef *error) {
212 CFDataRef v2data = NULL;
213 CFMutableDictionaryRef v2Dictionary = NULL;
214
215 require_action_quiet((v2data = SOSPeerInfoGetV2Data(pi)), out, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("No V2 Data in description"), NULL, error));
216 require_action_quiet((v2Dictionary = SOSCreateDictionaryFromDER(v2data, error)), out, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Can't expand V2 Dictionary"), NULL, error));
217 CFReleaseNull(pi->v2Dictionary);
218 pi->v2Dictionary = v2Dictionary;
219 return true;
220
221 out:
222 CFReleaseNull(v2Dictionary);
223 return false;
224
225 }
226
227 void SOSPeerInfoV2DictionarySetValue(SOSPeerInfoRef pi, const void *key, const void *value) {
228 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
229 if (value == NULL)
230 CFDictionaryRemoveValue(pi->v2Dictionary, key);
231 else
232 CFDictionarySetValue(pi->v2Dictionary, key, value);
233 SOSPeerInfoPackV2Data(pi);
234 errOut:
235 return;
236 }
237
238 void SOSPeerInfoV2DictionaryRemoveValue(SOSPeerInfoRef pi, const void *key) {
239 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
240 CFDictionaryRemoveValue(pi->v2Dictionary, key);
241 SOSPeerInfoPackV2Data(pi);
242 errOut:
243 return;
244 }
245
246 bool SOSPeerInfoV2DictionaryHasBoolean(SOSPeerInfoRef pi, const void *key) {
247 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
248 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
249 if(asBoolean(value,NULL) != NULL)
250 return true;
251 errOut:
252 return false;
253 }
254
255 // Not API to prevent owenership confusion
256 static CFStringRef SOSPeerInfoV2DictionaryGetAsString(SOSPeerInfoRef pi, const void *key) {
257 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
258 return asString(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
259 errOut:
260 return NULL;
261
262 }
263
264 bool SOSPeerInfoV2DictionaryHasStringValue(SOSPeerInfoRef pi, const void *key, CFStringRef value) {
265 return CFEqualSafe(SOSPeerInfoV2DictionaryGetAsString(pi, key), value);
266 }
267
268 bool SOSPeerInfoV2DictionaryHasString(SOSPeerInfoRef pi, const void *key) {
269 CFStringRef possibleID = SOSPeerInfoV2DictionaryGetAsString(pi, key);
270 return possibleID != NULL && CFStringGetLength(possibleID) > 0;
271 }
272
273 bool SOSPeerInfoV2DictionaryHasSet(SOSPeerInfoRef pi, const void *key) {
274 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
275 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
276 if(asSet(value,NULL) != NULL)
277 return true;
278 errOut:
279 return false;
280 }
281
282 bool SOSPeerInfoV2DictionaryHasData(SOSPeerInfoRef pi, const void *key) {
283 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
284 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
285 if(asData(value,NULL) != NULL)
286 return true;
287 errOut:
288 return false;
289 }
290
291 CFMutableStringRef SOSPeerInfoV2DictionaryCopyString(SOSPeerInfoRef pi, const void *key) {
292 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
293 CFStringRef value = asString(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
294 if(value != NULL)
295 return CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(value), value);
296 errOut:
297 return NULL;
298 }
299
300 static void SOSPeerInfoV2DictionaryWithValue(SOSPeerInfoRef pi, const void *key, void(^operation)(CFTypeRef value)) {
301 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
302 CFTypeRef value = CFRetainSafe(CFDictionaryGetValue(pi->v2Dictionary, key));
303 operation(value);
304 CFReleaseNull(value);
305 errOut:
306 return;
307 }
308
309 void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi, const void *key, void(^operation)(CFSetRef set)) {
310 SOSPeerInfoV2DictionaryWithValue(pi, key, ^(CFTypeRef value) {
311 CFSetRef set = asSet(value, NULL);
312 if (set) {
313 operation(set);
314 }
315 });
316 }
317
318 CFMutableSetRef SOSPeerInfoV2DictionaryCopySet(SOSPeerInfoRef pi, const void *key) {
319 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
320 CFSetRef value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
321 if(value != NULL)
322 return CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(value), value);
323 errOut:
324 return NULL;
325 }
326
327 void SOSPeerInfoV2DictionaryForEachSetValue(SOSPeerInfoRef pi, const void *key, void (^action)(const void* value)) {
328 CFSetRef value = NULL;
329 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
330 value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
331
332 errOut:
333 if (value) {
334 CFSetForEach(value, action);
335 }
336 }
337
338 bool SOSPeerInfoV2DictionaryHasSetContaining(SOSPeerInfoRef pi, const void *key, const void* member) {
339 CFSetRef value = NULL;
340 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
341 value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
342 errOut:
343 return value && CFSetContainsValue(value, member);
344 }
345
346 CFMutableDataRef SOSPeerInfoV2DictionaryCopyData(SOSPeerInfoRef pi, const void *key) {
347 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
348 CFDataRef value = asData(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
349 if(value != NULL)
350 return CFDataCreateMutableCopy(kCFAllocatorDefault, CFDataGetLength(value), value);
351 errOut:
352 return NULL;
353 }
354
355 CFBooleanRef SOSPeerInfoV2DictionaryCopyBoolean(SOSPeerInfoRef pi, const void *key) {
356 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
357 CFBooleanRef value = asBoolean(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
358 if(value != NULL)
359 return CFRetainSafe(value);
360 errOut:
361 return NULL;
362 }
363
364 CFMutableDictionaryRef SOSPeerInfoV2DictionaryCopyDictionary(SOSPeerInfoRef pi, const void *key) {
365 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
366 CFDictionaryRef value = asDictionary(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
367 if(value != NULL)
368 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(value), value);
369 errOut:
370 return NULL;
371 }
372
373
374 SOSPeerInfoRef SOSPeerInfoCopyWithV2DictionaryUpdate(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFDictionaryRef newv2dict, SecKeyRef signingKey, CFErrorRef* error) {
375 SOSPeerInfoRef retval = SOSPeerInfoCreateCopy(kCFAllocatorDefault, toCopy, error);
376 require_quiet(retval, errOut);
377 require_action_quiet(SOSPeerInfoExpandV2Data(retval, error), errOut, CFReleaseNull(retval));
378 CFDictionaryForEach(newv2dict, ^(const void *key, const void *value) {
379 CFDictionarySetValue(retval->v2Dictionary, key, value);
380 });
381 SOSPeerInfoPackV2Data(retval);
382 require_action_quiet(SOSPeerInfoSign(signingKey, retval, error), errOut, CFReleaseNull(retval));
383 errOut:
384 return retval;
385 }