5 // Created by Richard Murphy on 1/26/15.
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>
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)
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");
34 // need entitlement for this:
36 #include <MobileGestalt.h>
38 static CFStringRef
SOSCopySerialNumberAsString(CFErrorRef
*error
) {
39 CFTypeRef iosAnswer
= (CFStringRef
) MGCopyAnswer(kMGQSerialNumber
, NULL
);
41 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
);
43 return (CFStringRef
) iosAnswer
;
48 #include <CoreFoundation/CoreFoundation.h>
49 #include <IOKit/IOKitLib.h>
51 static CFStringRef
SOSCopySerialNumberAsString(CFErrorRef
*error
) {
52 CFStringRef serialNumber
= NULL
;
53 CFStringRef retval
= NULL
;
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
);
67 bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi
) {
68 CFStringRef serial
= SOSPeerInfoV2DictionaryCopyString(pi
, sSerialNumberKey
);
69 bool retval
= (serial
!= NULL
);
70 CFReleaseNull(serial
);
74 void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi
) {
75 CFStringRef serialNumber
= SOSCopySerialNumberAsString(NULL
);
76 if(serialNumber
) SOSPeerInfoV2DictionarySetValue(pi
, sSerialNumberKey
, serialNumber
);
77 CFReleaseNull(serialNumber
);
80 const CFStringRef SOSSerialUnknown
= CFSTR("Unknown");
82 void SOSPeerInfoSetTestSerialNumber(SOSPeerInfoRef pi
, CFStringRef serialNumber
) {
83 if(serialNumber
) SOSPeerInfoV2DictionarySetValue(pi
, sSerialNumberKey
, serialNumber
);
86 CFStringRef
SOSPeerInfoCopySerialNumber(SOSPeerInfoRef pi
) {
87 CFStringRef retval
= SOSPeerInfoV2DictionaryCopyString(pi
, sSerialNumberKey
);
88 return (retval
? retval
: CFRetain(SOSSerialUnknown
));
91 static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi
) {
95 if(!SOSPeerInfoVersionHasV2Data(pi
)) {
101 static CFDataRef
SOSPeerInfoGetV2Data(SOSPeerInfoRef pi
) {
102 if(SOSPeerInfoV2SanityCheck(pi
) == false) return NULL
;
103 return asData(CFDictionaryGetValue(pi
->description
, sV2DictionaryKey
), NULL
);
106 static CFMutableDictionaryRef
SOSCreateDictionaryFromDER(CFDataRef v2Data
, CFErrorRef
*error
) {
107 CFMutableDictionaryRef retval
= NULL
;
108 CFPropertyListRef pl
= NULL
;
111 secerror("Creating raw dictionary instead of creating from DER");
112 return CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
115 if(CFGetTypeID(v2Data
) != CFDataGetTypeID()) {
116 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Corrupted v2Data Item"), NULL
, error
);
120 const uint8_t *der_p
= CFDataGetBytePtr(v2Data
);
121 const uint8_t *der_end
= CFDataGetLength(v2Data
) + der_p
;
123 der_p
= der_decode_plist(NULL
, kCFPropertyListImmutable
, &pl
, error
, der_p
, der_end
);
125 if (der_p
== NULL
|| der_p
!= der_end
) {
126 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Format of Dictionary DER"), NULL
, error
);
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
);
139 retval
= (CFMutableDictionaryRef
) pl
;
143 CFReleaseNull(retval
);
148 static CFDataRef
SOSCreateDERFromDictionary(CFDictionaryRef di
, CFErrorRef
*error
) {
149 size_t size
= der_sizeof_plist(di
, error
);
150 if (size
== 0) return NULL
;
152 der_encode_plist(di
, error
, der
, der
+size
);
153 return CFDataCreate(kCFAllocatorDefault
, der
, size
);
157 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
159 CFDataRef v2data
= NULL
;
160 if(!pi
) return false;
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
);
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
);
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
);
182 CFReleaseNull(views
);
183 CFReleaseNull(v2data
);
184 CFReleaseNull(v2Dictionary
);
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
);
198 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
199 CFDataRef v2data
= NULL
;
200 CFMutableDictionaryRef v2Dictionary
= NULL
;
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
;
209 CFReleaseNull(v2Dictionary
);
214 void SOSPeerInfoV2DictionarySetValue(SOSPeerInfoRef pi
, const void *key
, const void *value
) {
215 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
217 CFDictionaryRemoveValue(pi
->v2Dictionary
, key
);
219 CFDictionarySetValue(pi
->v2Dictionary
, key
, value
);
220 SOSPeerInfoPackV2Data(pi
);
225 void SOSPeerInfoV2DictionaryRemoveValue(SOSPeerInfoRef pi
, const void *key
) {
226 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
227 CFDictionaryRemoveValue(pi
->v2Dictionary
, key
);
228 SOSPeerInfoPackV2Data(pi
);
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
)
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
);
251 bool SOSPeerInfoV2DictionaryHasStringValue(SOSPeerInfoRef pi
, const void *key
, CFStringRef value
) {
252 return CFEqualSafe(SOSPeerInfoV2DictionaryGetAsString(pi
, key
), value
);
255 bool SOSPeerInfoV2DictionaryHasString(SOSPeerInfoRef pi
, const void *key
) {
256 CFStringRef possibleID
= SOSPeerInfoV2DictionaryGetAsString(pi
, key
);
257 return possibleID
!= NULL
&& CFStringGetLength(possibleID
) > 0;
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
)
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
)
278 CFMutableStringRef
SOSPeerInfoV2DictionaryCopyString(SOSPeerInfoRef pi
, const void *key
) {
279 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
280 CFStringRef value
= asString(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
282 return CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(value
), value
);
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
));
291 CFReleaseNull(value
);
296 void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi
, const void *key
, void(^operation
)(CFSetRef set
)) {
297 SOSPeerInfoV2DictionaryWithValue(pi
, key
, ^(CFTypeRef value
) {
298 CFSetRef set
= asSet(value
, NULL
);
305 CFMutableSetRef
SOSPeerInfoV2DictionaryCopySet(SOSPeerInfoRef pi
, const void *key
) {
306 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
307 CFSetRef value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
309 return CFSetCreateMutableCopy(kCFAllocatorDefault
, CFSetGetCount(value
), value
);
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
);
321 CFSetForEach(value
, action
);
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
);
330 return value
&& CFSetContainsValue(value
, member
);
333 CFMutableDataRef
SOSPeerInfoV2DictionaryCopyData(SOSPeerInfoRef pi
, const void *key
) {
334 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
335 CFDataRef value
= asData(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
337 return CFDataCreateMutableCopy(kCFAllocatorDefault
, CFDataGetLength(value
), value
);
342 CFBooleanRef
SOSPeerInfoV2DictionaryCopyBoolean(SOSPeerInfoRef pi
, const void *key
) {
343 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
344 CFBooleanRef value
= asBoolean(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
346 return CFRetainSafe(value
);
351 CFMutableDictionaryRef
SOSPeerInfoV2DictionaryCopyDictionary(SOSPeerInfoRef pi
, const void *key
) {
352 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
353 CFDictionaryRef value
= asDictionary(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
355 return CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(value
), value
);
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
);
368 SOSPeerInfoPackV2Data(retval
);
369 require_action_quiet(SOSPeerInfoSign(signingKey
, retval
, error
), errOut
, CFReleaseNull(retval
));