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 <utilities/der_plist.h>
14 #include <utilities/der_plist_internal.h>
15 #include <corecrypto/ccder.h>
16 #include <utilities/der_date.h>
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)
25 CFStringRef sSecurityPropertiesKey
= CFSTR("SecurityProperties");
26 CFStringRef kSOSHsaCrKeyDictionary
= CFSTR("HSADictionary");
27 CFStringRef sRingState
= CFSTR("RingState");
28 CFStringRef sBackupKeyKey
= CFSTR("BackupKey");
32 // need entitlement for this:
34 #include <MobileGestalt.h>
36 static CFStringRef
SOSCopySerialNumberAsString(CFErrorRef
*error
) {
37 CFTypeRef iosAnswer
= (CFStringRef
) MGCopyAnswer(kMGQSerialNumber
, NULL
);
39 SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
);
41 return (CFStringRef
) iosAnswer
;
46 #include <CoreFoundation/CoreFoundation.h>
47 #include <IOKit/IOKitLib.h>
49 static CFStringRef
SOSCopySerialNumberAsString(CFErrorRef
*error
) {
50 CFStringRef serialNumber
= NULL
;
51 CFStringRef retval
= NULL
;
53 io_service_t platformExpert
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOServiceMatching("IOPlatformExpertDevice"));
54 require_action_quiet(platformExpert
, errOut
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
));
55 serialNumber
= IORegistryEntryCreateCFProperty(platformExpert
, CFSTR(kIOPlatformSerialNumberKey
), kCFAllocatorDefault
, 0);
56 if(serialNumber
) retval
= CFStringCreateCopy(kCFAllocatorDefault
, serialNumber
);
57 IOObjectRelease(platformExpert
);
58 CFReleaseNull(serialNumber
);
65 bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi
) {
66 CFStringRef serial
= SOSPeerInfoV2DictionaryCopyString(pi
, sSerialNumberKey
);
67 bool retval
= (serial
!= NULL
);
68 CFReleaseNull(serial
);
72 void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi
) {
73 CFStringRef serialNumber
= SOSCopySerialNumberAsString(NULL
);
74 if(serialNumber
) SOSPeerInfoV2DictionarySetValue(pi
, sSerialNumberKey
, serialNumber
);
75 CFReleaseNull(serialNumber
);
78 static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi
) {
82 if(!SOSPeerInfoVersionHasV2Data(pi
)) {
88 static CFDataRef
SOSPeerInfoGetV2Data(SOSPeerInfoRef pi
) {
89 if(SOSPeerInfoV2SanityCheck(pi
) == false) return NULL
;
90 return CFDictionaryGetValue(pi
->description
, sV2DictionaryKey
);
93 static CFMutableDictionaryRef
SOSCreateDictionaryFromDER(CFDataRef v2Data
, CFErrorRef
*error
) {
94 CFMutableDictionaryRef retval
= NULL
;
95 CFPropertyListRef pl
= NULL
;
98 secerror("Creating raw dictionary instead of creating from DER");
99 return CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
102 if(CFGetTypeID(v2Data
) != CFDataGetTypeID()) {
103 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Corrupted v2Data Item"), NULL
, error
);
107 const uint8_t *der_p
= CFDataGetBytePtr(v2Data
);
108 const uint8_t *der_end
= CFDataGetLength(v2Data
) + der_p
;
110 der_p
= der_decode_plist(NULL
, kCFPropertyListImmutable
, &pl
, error
, der_p
, der_end
);
112 if (der_p
== NULL
|| der_p
!= der_end
) {
113 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Format of Dictionary DER"), NULL
, error
);
117 if (CFGetTypeID(pl
) != CFDictionaryGetTypeID()) {
118 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(pl
));
119 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
120 CFSTR("Expected dictionary got %@"), description
);
121 CFReleaseSafe(description
);
126 retval
= (CFMutableDictionaryRef
) pl
;
130 CFReleaseNull(retval
);
135 static CFDataRef
SOSCreateDERFromDictionary(CFDictionaryRef di
, CFErrorRef
*error
) {
136 size_t size
= der_sizeof_plist(di
, error
);
137 if (size
== 0) return NULL
;
139 der_encode_plist(di
, error
, der
, der
+size
);
140 return CFDataCreate(kCFAllocatorDefault
, der
, size
);
144 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
146 CFDataRef v2data
= NULL
;
147 if(!pi
) return false;
149 SOSPeerInfoSetVersionNumber(pi
, PEERINFO_CURRENT_VERSION
);
150 CFMutableDictionaryRef v2Dictionary
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
151 CFStringRef serialNumber
= SOSCopySerialNumberAsString(error
);
152 if(serialNumber
== NULL
) {
153 secnotice("signing", "serialNumber was returned NULL\n");
155 CFMutableSetRef views
= SOSViewsCreateDefault(false, error
);
156 CFMutableSetRef secproperties
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
157 if(serialNumber
) CFDictionaryAddValue(v2Dictionary
, sSerialNumberKey
, serialNumber
);
158 CFDictionaryAddValue(v2Dictionary
, sViewsKey
, views
);
159 CFDictionaryAddValue(v2Dictionary
, sSecurityPropertiesKey
, secproperties
);
160 if(whichTransportType
== kSOSTransportPresent
){
161 CFDictionaryAddValue(v2Dictionary
, sDeviceID
, CFSTR(""));
162 CFDictionaryAddValue(v2Dictionary
, sTransportType
, SOSTransportMessageTypeKVS
);
163 CFDictionaryAddValue(v2Dictionary
, sPreferIDS
, kCFBooleanTrue
);
165 else if (whichTransportType
== kSOSTransportFuture
|| whichTransportType
== kSOSTransportIDS
){
166 CFDictionaryAddValue(v2Dictionary
, sDeviceID
, CFSTR(""));
167 CFDictionaryAddValue(v2Dictionary
, sTransportType
, SOSTransportMessageTypeIDS
);
168 CFDictionaryAddValue(v2Dictionary
, sPreferIDS
, kCFBooleanTrue
);
170 require_action_quiet((v2data
= SOSCreateDERFromDictionary(v2Dictionary
, error
)), out
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("No Memory"), NULL
, error
));
171 CFDictionaryAddValue(pi
->description
, sV2DictionaryKey
, v2data
);
172 SOSPeerInfoExpandV2Data(pi
, error
);
175 CFReleaseNull(views
);
176 CFReleaseNull(secproperties
);
177 CFReleaseNull(v2data
);
178 CFReleaseNull(v2Dictionary
);
179 CFReleaseNull(serialNumber
);
183 void SOSPeerInfoPackV2Data(SOSPeerInfoRef pi
) {
184 require(SOSPeerInfoV2SanityCheck(pi
), errOut
);
185 require_quiet(pi
->v2Dictionary
, errOut
);
186 CFDataRef v2der
= SOSCreateDERFromDictionary(pi
->v2Dictionary
, NULL
);
187 CFDictionarySetValue(pi
->description
, sV2DictionaryKey
, v2der
);
188 CFReleaseNull(v2der
);
193 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
194 CFDataRef v2data
= NULL
;
195 CFMutableDictionaryRef v2Dictionary
= NULL
;
197 require_action_quiet((v2data
= SOSPeerInfoGetV2Data(pi
)), out
, SOSCreateError(kSOSErrorDecodeFailure
, CFSTR("No V2 Data in description"), NULL
, error
));
198 require_action_quiet((v2Dictionary
= SOSCreateDictionaryFromDER(v2data
, error
)), out
, SOSCreateError(kSOSErrorDecodeFailure
, CFSTR("Can't expand V2 Dictionary"), NULL
, error
));
199 CFReleaseNull(pi
->v2Dictionary
);
200 pi
->v2Dictionary
= v2Dictionary
;
204 CFReleaseNull(v2Dictionary
);
209 void SOSPeerInfoV2DictionarySetValue(SOSPeerInfoRef pi
, const void *key
, const void *value
) {
210 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
212 CFDictionaryRemoveValue(pi
->v2Dictionary
, key
);
214 CFDictionarySetValue(pi
->v2Dictionary
, key
, value
);
215 SOSPeerInfoPackV2Data(pi
);
220 void SOSPeerInfoV2DictionaryRemoveValue(SOSPeerInfoRef pi
, const void *key
) {
221 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
222 CFDictionaryRemoveValue(pi
->v2Dictionary
, key
);
223 SOSPeerInfoPackV2Data(pi
);
228 bool SOSPeerInfoV2DictionaryHasBoolean(SOSPeerInfoRef pi
, const void *key
) {
229 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
230 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
231 if(asBoolean(value
,NULL
) != NULL
)
238 bool SOSPeerInfoV2DictionaryHasString(SOSPeerInfoRef pi
, const void *key
) {
239 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
240 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
241 if(asString(value
,NULL
) != NULL
)
247 bool SOSPeerInfoV2DictionaryHasSet(SOSPeerInfoRef pi
, const void *key
) {
248 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
249 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
250 if(asSet(value
,NULL
) != NULL
)
256 bool SOSPeerInfoV2DictionaryHasData(SOSPeerInfoRef pi
, const void *key
) {
257 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
258 CFTypeRef value
= CFDictionaryGetValue(pi
->v2Dictionary
, key
);
259 if(asData(value
,NULL
) != NULL
)
265 const CFMutableStringRef
SOSPeerInfoV2DictionaryCopyString(SOSPeerInfoRef pi
, const void *key
) {
266 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
267 CFStringRef value
= asString(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
269 return CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(value
), value
);
274 static void SOSPeerInfoV2DictionaryWithValue(SOSPeerInfoRef pi
, const void *key
, void(^operation
)(CFTypeRef value
)) {
275 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
276 CFTypeRef value
= CFRetainSafe(CFDictionaryGetValue(pi
->v2Dictionary
, key
));
278 CFReleaseNull(value
);
283 void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi
, const void *key
, void(^operation
)(CFSetRef set
)) {
284 SOSPeerInfoV2DictionaryWithValue(pi
, key
, ^(CFTypeRef value
) {
285 CFSetRef set
= asSet(value
, NULL
);
292 const CFMutableSetRef
SOSPeerInfoV2DictionaryCopySet(SOSPeerInfoRef pi
, const void *key
) {
293 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
294 CFSetRef value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
296 return CFSetCreateMutableCopy(kCFAllocatorDefault
, CFSetGetCount(value
), value
);
301 void SOSPeerInfoV2DictionaryForEachSetValue(SOSPeerInfoRef pi
, const void *key
, void (^action
)(const void* value
)) {
302 CFSetRef value
= NULL
;
303 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
304 value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
308 CFSetForEach(value
, action
);
312 bool SOSPeerInfoV2DictionaryHasSetContaining(SOSPeerInfoRef pi
, const void *key
, const void* member
) {
313 CFSetRef value
= NULL
;
314 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
315 value
= asSet(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
317 return value
&& CFSetContainsValue(value
, member
);
320 const CFMutableDataRef
SOSPeerInfoV2DictionaryCopyData(SOSPeerInfoRef pi
, const void *key
) {
321 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
322 CFDataRef value
= asData(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
324 return CFDataCreateMutableCopy(kCFAllocatorDefault
, CFDataGetLength(value
), value
);
329 const CFBooleanRef
SOSPeerInfoV2DictionaryCopyBoolean(SOSPeerInfoRef pi
, const void *key
) {
330 require_quiet(SOSPeerInfoExpandV2Data(pi
, NULL
), errOut
);
331 CFBooleanRef value
= asBoolean(CFDictionaryGetValue(pi
->v2Dictionary
, key
), NULL
);
333 return CFRetainSafe(value
);