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