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