]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.c
b17d478d9e4c8d3386c979be22982bb5757c139b
[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 <utilities/der_plist.h>
14 #include <utilities/der_plist_internal.h>
15 #include <corecrypto/ccder.h>
16 #include <utilities/der_date.h>
17
18
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)
24
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");
30
31 #if TARGET_OS_IPHONE
32
33 // need entitlement for this:
34
35 #include <MobileGestalt.h>
36
37 static CFStringRef SOSCopySerialNumberAsString(CFErrorRef *error) {
38 CFTypeRef iosAnswer = (CFStringRef) MGCopyAnswer(kMGQSerialNumber, NULL);
39 if(!iosAnswer) {
40 SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error);
41 }
42 return (CFStringRef) iosAnswer;
43 }
44
45 #else
46
47 #include <CoreFoundation/CoreFoundation.h>
48 #include <IOKit/IOKitLib.h>
49
50 static CFStringRef SOSCopySerialNumberAsString(CFErrorRef *error) {
51 CFStringRef serialNumber = NULL;
52 CFStringRef retval = NULL;
53
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);
60 errOut:
61 return retval;
62 }
63
64 #endif
65
66 bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi) {
67 CFStringRef serial = SOSPeerInfoV2DictionaryCopyString(pi, sSerialNumberKey);
68 bool retval = (serial != NULL);
69 CFReleaseNull(serial);
70 return retval;
71 }
72
73 void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi) {
74 CFStringRef serialNumber = SOSCopySerialNumberAsString(NULL);
75 if(serialNumber) SOSPeerInfoV2DictionarySetValue(pi, sSerialNumberKey, serialNumber);
76 CFReleaseNull(serialNumber);
77 }
78
79 static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi) {
80 if(!pi) {
81 return false;
82 }
83 if(!SOSPeerInfoVersionHasV2Data(pi)) {
84 return false;
85 }
86 return true;
87 }
88
89 static CFDataRef SOSPeerInfoGetV2Data(SOSPeerInfoRef pi) {
90 if(SOSPeerInfoV2SanityCheck(pi) == false) return NULL;
91 return CFDictionaryGetValue(pi->description, sV2DictionaryKey);
92 }
93
94 static CFMutableDictionaryRef SOSCreateDictionaryFromDER(CFDataRef v2Data, CFErrorRef *error) {
95 CFMutableDictionaryRef retval = NULL;
96 CFPropertyListRef pl = NULL;
97
98 if(!v2Data) {
99 secerror("Creating raw dictionary instead of creating from DER");
100 return CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
101 }
102
103 if(CFGetTypeID(v2Data) != CFDataGetTypeID()) {
104 SOSCreateError(kSOSErrorBadFormat, CFSTR("Corrupted v2Data Item"), NULL, error);
105 goto fail;
106 }
107
108 const uint8_t *der_p = CFDataGetBytePtr(v2Data);
109 const uint8_t *der_end = CFDataGetLength(v2Data) + der_p;
110
111 der_p = der_decode_plist(NULL, kCFPropertyListImmutable, &pl, error, der_p, der_end);
112
113 if (der_p == NULL || der_p != der_end) {
114 SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Dictionary DER"), NULL, error);
115 goto fail;
116 }
117
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);
123 CFReleaseSafe(pl);
124 goto fail;
125 }
126
127 retval = (CFMutableDictionaryRef) pl;
128 return retval;
129
130 fail:
131 CFReleaseNull(retval);
132 return NULL;
133 }
134
135
136 static CFDataRef SOSCreateDERFromDictionary(CFDictionaryRef di, CFErrorRef *error) {
137 size_t size = der_sizeof_plist(di, error);
138 if (size == 0) return NULL;
139 uint8_t der[size];
140 der_encode_plist(di, error, der, der+size);
141 return CFDataCreate(kCFAllocatorDefault, der, size);
142 }
143
144
145 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi, CFErrorRef *error) {
146 bool retval = false;
147 CFDataRef v2data = NULL;
148 if(!pi) return false;
149
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");
155 }
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);
161 if(whichTransportType == kSOSTransportPresent){
162 CFDictionaryAddValue(v2Dictionary, sDeviceID, CFSTR(""));
163 CFDictionaryAddValue(v2Dictionary, sTransportType, SOSTransportMessageTypeKVS);
164 CFDictionaryAddValue(v2Dictionary, sPreferIDS, kCFBooleanTrue);
165 }
166 else if (whichTransportType == kSOSTransportFuture || whichTransportType == kSOSTransportIDS){
167 CFDictionaryAddValue(v2Dictionary, sDeviceID, CFSTR(""));
168 CFDictionaryAddValue(v2Dictionary, sTransportType, SOSTransportMessageTypeIDS);
169 CFDictionaryAddValue(v2Dictionary, sPreferIDS, kCFBooleanTrue);
170 }
171 require_action_quiet((v2data = SOSCreateDERFromDictionary(v2Dictionary, error)), out, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("No Memory"), NULL, error));
172 CFDictionaryAddValue(pi->description, sV2DictionaryKey, v2data);
173 SOSPeerInfoExpandV2Data(pi, error);
174 retval = true;
175 out:
176 CFReleaseNull(views);
177 CFReleaseNull(secproperties);
178 CFReleaseNull(v2data);
179 CFReleaseNull(v2Dictionary);
180 CFReleaseNull(serialNumber);
181 return retval;
182 }
183
184 void SOSPeerInfoPackV2Data(SOSPeerInfoRef pi) {
185 require(SOSPeerInfoV2SanityCheck(pi), errOut);
186 require_quiet(pi->v2Dictionary, errOut);
187 CFDataRef v2der = SOSCreateDERFromDictionary(pi->v2Dictionary, NULL);
188 CFDictionarySetValue(pi->description, sV2DictionaryKey, v2der);
189 CFReleaseNull(v2der);
190 errOut:
191 return;
192 }
193
194 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi, CFErrorRef *error) {
195 CFDataRef v2data = NULL;
196 CFMutableDictionaryRef v2Dictionary = NULL;
197
198 require_action_quiet((v2data = SOSPeerInfoGetV2Data(pi)), out, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("No V2 Data in description"), NULL, error));
199 require_action_quiet((v2Dictionary = SOSCreateDictionaryFromDER(v2data, error)), out, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Can't expand V2 Dictionary"), NULL, error));
200 CFReleaseNull(pi->v2Dictionary);
201 pi->v2Dictionary = v2Dictionary;
202 return true;
203
204 out:
205 CFReleaseNull(v2Dictionary);
206 return false;
207
208 }
209
210 void SOSPeerInfoV2DictionarySetValue(SOSPeerInfoRef pi, const void *key, const void *value) {
211 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
212 if (value == NULL)
213 CFDictionaryRemoveValue(pi->v2Dictionary, key);
214 else
215 CFDictionarySetValue(pi->v2Dictionary, key, value);
216 SOSPeerInfoPackV2Data(pi);
217 errOut:
218 return;
219 }
220
221 void SOSPeerInfoV2DictionaryRemoveValue(SOSPeerInfoRef pi, const void *key) {
222 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
223 CFDictionaryRemoveValue(pi->v2Dictionary, key);
224 SOSPeerInfoPackV2Data(pi);
225 errOut:
226 return;
227 }
228
229 bool SOSPeerInfoV2DictionaryHasBoolean(SOSPeerInfoRef pi, const void *key) {
230 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
231 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
232 if(asBoolean(value,NULL) != NULL)
233 return true;
234 errOut:
235 return false;
236 }
237
238
239 bool SOSPeerInfoV2DictionaryHasString(SOSPeerInfoRef pi, const void *key) {
240 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
241 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
242 if(asString(value,NULL) != NULL)
243 return true;
244 errOut:
245 return false;
246 }
247
248 bool SOSPeerInfoV2DictionaryHasSet(SOSPeerInfoRef pi, const void *key) {
249 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
250 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
251 if(asSet(value,NULL) != NULL)
252 return true;
253 errOut:
254 return false;
255 }
256
257 bool SOSPeerInfoV2DictionaryHasData(SOSPeerInfoRef pi, const void *key) {
258 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
259 CFTypeRef value = CFDictionaryGetValue(pi->v2Dictionary, key);
260 if(asData(value,NULL) != NULL)
261 return true;
262 errOut:
263 return false;
264 }
265
266 const CFMutableStringRef SOSPeerInfoV2DictionaryCopyString(SOSPeerInfoRef pi, const void *key) {
267 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
268 CFStringRef value = asString(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
269 if(value != NULL)
270 return CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(value), value);
271 errOut:
272 return NULL;
273 }
274
275 static void SOSPeerInfoV2DictionaryWithValue(SOSPeerInfoRef pi, const void *key, void(^operation)(CFTypeRef value)) {
276 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
277 CFTypeRef value = CFRetainSafe(CFDictionaryGetValue(pi->v2Dictionary, key));
278 operation(value);
279 CFReleaseNull(value);
280 errOut:
281 return;
282 }
283
284 void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi, const void *key, void(^operation)(CFSetRef set)) {
285 SOSPeerInfoV2DictionaryWithValue(pi, key, ^(CFTypeRef value) {
286 CFSetRef set = asSet(value, NULL);
287 if (set) {
288 operation(set);
289 }
290 });
291 }
292
293 const CFMutableSetRef SOSPeerInfoV2DictionaryCopySet(SOSPeerInfoRef pi, const void *key) {
294 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
295 CFSetRef value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
296 if(value != NULL)
297 return CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(value), value);
298 errOut:
299 return NULL;
300 }
301
302 void SOSPeerInfoV2DictionaryForEachSetValue(SOSPeerInfoRef pi, const void *key, void (^action)(const void* value)) {
303 CFSetRef value = NULL;
304 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
305 value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
306
307 errOut:
308 if (value) {
309 CFSetForEach(value, action);
310 }
311 }
312
313 bool SOSPeerInfoV2DictionaryHasSetContaining(SOSPeerInfoRef pi, const void *key, const void* member) {
314 CFSetRef value = NULL;
315 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
316 value = asSet(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
317 errOut:
318 return value && CFSetContainsValue(value, member);
319 }
320
321 const CFMutableDataRef SOSPeerInfoV2DictionaryCopyData(SOSPeerInfoRef pi, const void *key) {
322 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
323 CFDataRef value = asData(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
324 if(value != NULL)
325 return CFDataCreateMutableCopy(kCFAllocatorDefault, CFDataGetLength(value), value);
326 errOut:
327 return NULL;
328 }
329
330 const CFBooleanRef SOSPeerInfoV2DictionaryCopyBoolean(SOSPeerInfoRef pi, const void *key) {
331 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
332 CFBooleanRef value = asBoolean(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
333 if(value != NULL)
334 return CFRetainSafe(value);
335 errOut:
336 return NULL;
337 }
338
339 const CFMutableDictionaryRef SOSPeerInfoV2DictionaryCopyDictionary(SOSPeerInfoRef pi, const void *key) {
340 require_quiet(SOSPeerInfoExpandV2Data(pi, NULL), errOut);
341 CFDictionaryRef value = asDictionary(CFDictionaryGetValue(pi->v2Dictionary, key), NULL);
342 if(value != NULL)
343 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(value), value);
344 errOut:
345 return NULL;
346 }