5 // Created by Mitch Adler on 7/19/12.
9 #include <AssertMacros.h>
10 #include <TargetConditionals.h>
12 #include <SecureObjectSync/SOSPeerInfo.h>
13 #include <SecureObjectSync/SOSPeerInfoInternal.h>
14 #include <SecureObjectSync/SOSCircle.h>
16 #include <SecureObjectSync/SOSInternal.h>
17 #include <ipc/securityd_client.h>
19 #include "Imported/SecuritydXPC.h"
21 #include <CoreFoundation/CFArray.h>
22 #include <dispatch/dispatch.h>
27 #include <utilities/SecCFWrappers.h>
28 #include <utilities/SecCFRelease.h>
29 #include <utilities/SecCFError.h>
30 #include <utilities/SecXPCError.h>
32 #include <utilities/der_plist.h>
33 #include <utilities/der_plist_internal.h>
34 #include <corecrypto/ccder.h>
35 #include <utilities/der_date.h>
37 #include <corecrypto/ccdigest.h>
38 #include <corecrypto/ccsha2.h>
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <CoreFoundation/CFDate.h>
46 #if TARGET_OS_IPHONE || TARGET_OS_EMBEDDED
47 #include <MobileGestalt.h>
50 #include <Security/SecBase64.h>
51 #include <Security/SecKeyPriv.h>
52 #include <Security/SecOTR.h>
54 #if 0//TARGET_OS_MAC // TODO: this function is the only one that causes secd to need to link against Security.framework on OSX
57 SecKeyRef
_SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef publicBytes
);
60 #endif /* TARGET_OS_MAC */
62 struct __OpaqueSOSPeerInfo
{
66 CFMutableDictionaryRef description
;
70 CFDictionaryRef gestalt
;
75 CFGiblisWithHashFor(SOSPeerInfo
);
77 CFStringRef kPIUserDefinedDeviceName
= CFSTR("ComputerName");
78 CFStringRef kPIDeviceModelName
= CFSTR("ModelName");
80 // Description Dictionary Entries
81 static CFStringRef sPublicKeyKey
= CFSTR("PublicSigningKey");
82 static CFStringRef sGestaltKey
= CFSTR("DeviceGestalt");
83 static CFStringRef sVersionKey
= CFSTR("ConflictVersion");
84 static CFStringRef sCloudIdentityKey
= CFSTR("CloudIdentity");
85 static CFStringRef sApplicationDate
= CFSTR("ApplicationDate");
86 static CFStringRef sApplicationUsig
= CFSTR("ApplicationUsig");
87 static CFStringRef sRetirementDate
= CFSTR("RetirementDate");
90 CFStringRef kSOSPeerInfoDescriptionKey
= CFSTR("SOSPeerInfoDescription");
91 CFStringRef kSOSPeerInfoSignatureKey
= CFSTR("SOSPeerInfoSignature");
92 CFStringRef kSOSPeerInfoNameKey
= CFSTR("SOSPeerInfoName");
95 SecKeyRef
SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer
) {
96 CFDataRef pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
97 CFAllocatorRef allocator
= CFGetAllocator(peer
);
98 SecKeyRef pubKey
= SecKeyCreateFromPublicData(allocator
, kSecECDSAAlgorithmID
, pubKeyBytes
);
103 static bool SOSDescriptionHash(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
, void *hashresult
, CFErrorRef
*error
) {
104 ccdigest_di_decl(di
, ctx
);
105 ccdigest_init(di
, ctx
);
107 if(!SOSPeerInfoUpdateDigestWithDescription(peer
, di
, ctx_p
, error
)) return false;
108 ccdigest_final(di
, ctx
, hashresult
);
114 static CFDataRef
sosSignHash(SecKeyRef privkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
116 size_t siglen
= SIGLEN
;
118 if((stat
= SecKeyRawSign(privkey
, kSecPaddingNone
, hbuf
, di
->output_size
, sig
, &siglen
)) != 0) {
121 return CFDataCreate(NULL
, sig
, (CFIndex
)siglen
);
124 static bool sosVerifyHash(SecKeyRef pubkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
, CFDataRef signature
) {
125 return SecKeyRawVerify(pubkey
, kSecPaddingNone
, hbuf
, di
->output_size
,
126 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
129 static bool SOSPeerInfoSign(SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
131 const struct ccdigest_info
*di
= ccsha256_di();
132 uint8_t hbuf
[di
->output_size
];
133 CFDataRef newSignature
= NULL
;
135 require_action_quiet(SOSDescriptionHash(peer
, di
, hbuf
, error
), fail
,
136 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to hash description for peer"), NULL
, error
));
138 newSignature
= sosSignHash(privKey
, di
, hbuf
);
139 require_action_quiet(newSignature
, fail
, SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign peerinfo for peer"), NULL
, error
));
141 CFReleaseNull(peer
->signature
);
142 peer
->signature
= newSignature
;
147 CFReleaseNull(newSignature
);
151 // Return true (1) if the signature verifies.
152 static bool SOSPeerInfoVerify(SOSPeerInfoRef peer
, CFErrorRef
*error
) {
154 const struct ccdigest_info
*di
= ccsha256_di();
155 uint8_t hbuf
[di
->output_size
];
157 SecKeyRef pubKey
= SOSPeerInfoCopyPubKey(peer
);
158 require_quiet(pubKey
, error_out
);
160 require_quiet(SOSDescriptionHash(peer
, di
, hbuf
, error
), error_out
);
162 result
= sosVerifyHash(pubKey
, di
, hbuf
, peer
->signature
);
165 CFReleaseNull(pubKey
);
169 static SOSPeerInfoRef
SOSPeerInfoCreate_Internal(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
, void (^ description_modifier
)(CFMutableDictionaryRef description
)) {
170 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
171 pi
->gestalt
= gestalt
;
172 CFRetain(pi
->gestalt
);
174 pi
->version
= kSOSPeerVersion
;
176 CFDataRef publicBytes
= NULL
;
177 CFNumberRef versionNumber
= NULL
;
179 SecKeyRef publicKey
= SecKeyCreatePublicFromPrivate(signingKey
);
180 if (publicKey
== NULL
) {
181 SOSCreateError(kSOSErrorBadKey
, CFSTR("Unable to get public"), NULL
, error
);
186 OSStatus result
= SecKeyCopyPublicBytes(publicKey
, &publicBytes
);
188 if (result
!= errSecSuccess
) {
189 SOSCreateError(kSOSErrorBadKey
, CFSTR("Failed to export public bytes"), NULL
, error
);
194 pi
->signature
= CFDataCreateMutable(allocator
, 0);
196 versionNumber
= CFNumberCreateWithCFIndex(NULL
, pi
->version
);
197 pi
->description
= CFDictionaryCreateMutableForCFTypesWith(allocator
,
198 sVersionKey
, versionNumber
,
199 sPublicKeyKey
, publicBytes
,
200 sGestaltKey
, pi
->gestalt
,
202 description_modifier(pi
->description
);
204 pi
->id
= SOSCopyIDOfKey(publicKey
, error
);
205 CFReleaseNull(publicKey
);
207 require_quiet(pi
->id
, exit
);
209 if (!SOSPeerInfoSign(signingKey
, pi
, error
)) {
215 CFReleaseNull(versionNumber
);
216 CFReleaseNull(publicBytes
);
220 SOSPeerInfoRef
SOSPeerInfoCreate(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
221 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {});
224 SOSPeerInfoRef
SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
225 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {
226 CFDictionarySetValue(description
, sCloudIdentityKey
, kCFBooleanTrue
);
232 SOSPeerInfoRef
SOSPeerInfoCreateCopy(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFErrorRef
* error
) {
233 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
235 pi
->description
= CFDictionaryCreateMutableCopy(allocator
, 0, toCopy
->description
);
236 pi
->signature
= CFDataCreateCopy(allocator
, toCopy
->signature
);
238 pi
->gestalt
= CFDictionaryCreateCopy(allocator
, toCopy
->gestalt
);
239 pi
->id
= CFStringCreateCopy(allocator
, toCopy
->id
);
241 pi
->version
= toCopy
->version
;
246 SOSPeerInfoRef
SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
247 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, toCopy
, error
);
249 CFRetainSafe(gestalt
);
250 CFReleaseNull(pi
->gestalt
);
251 pi
->gestalt
= gestalt
;
253 CFDictionarySetValue(pi
->description
, sGestaltKey
, pi
->gestalt
);
255 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(pi
);
257 pi
->id
= SOSCopyIDOfKey(pub_key
, error
);
258 require_quiet(pi
->id
, exit
);
260 require_action_quiet(SOSPeerInfoSign(signingKey
, pi
, error
), exit
, CFReleaseNull(pi
));
263 CFReleaseNull(pub_key
);
267 SOSPeerInfoRef
SOSPeerInfoCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
268 const uint8_t** der_p
, const uint8_t *der_end
) {
269 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
270 SecKeyRef pubKey
= NULL
;
272 const uint8_t *sequence_end
;
274 CFPropertyListRef pl
= NULL
;
277 pi
->version
= 0; // TODO: Encode this in the DER
279 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
280 *der_p
= der_decode_plist(allocator
, kCFPropertyListImmutable
, &pl
, error
, *der_p
, sequence_end
);
281 *der_p
= der_decode_data(allocator
, kCFPropertyListImmutable
, &pi
->signature
, error
, *der_p
, sequence_end
);
283 if (*der_p
== NULL
|| *der_p
!= sequence_end
) {
284 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Format of Peer Info DER"), NULL
, error
);
288 if (CFGetTypeID(pl
) != CFDictionaryGetTypeID()) {
289 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(pl
));
290 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
291 CFSTR("Expected dictionary got %@"), description
);
292 CFReleaseSafe(description
);
296 pi
->description
= (CFMutableDictionaryRef
) pl
;
297 CFRetain(pi
->description
);
300 CFNumberRef versionNumber
= CFDictionaryGetValue(pi
->description
, sVersionKey
);
303 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &pi
->version
);
306 CFDictionaryRef gestalt
= CFDictionaryGetValue(pi
->description
, sGestaltKey
);
308 if (!isDictionary(gestalt
)) {
309 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(pl
));
310 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
311 CFSTR("Expected dictionary got %@"), description
);
312 CFReleaseSafe(description
);
316 pi
->gestalt
= gestalt
;
317 CFRetain(pi
->gestalt
);
319 pubKey
= SOSPeerInfoCopyPubKey(pi
);
320 require_quiet(pubKey
, fail
);
322 pi
->id
= SOSCopyIDOfKey(pubKey
, error
);
323 require_quiet(pi
->id
, fail
);
325 if(!SOSPeerInfoVerify(pi
, error
)) {
326 SOSCreateErrorWithFormat(kSOSErrorBadSignature
, NULL
, error
, NULL
, CFSTR("Signature doesn't validate"));
328 secerror("Can't validate PeerInfo: %@", *error
);
331 CFReleaseNull(pubKey
);
337 CFReleaseNull(pubKey
);
342 SOSPeerInfoRef
SOSPeerInfoCreateFromData(CFAllocatorRef allocator
, CFErrorRef
* error
,
343 CFDataRef peerinfo_data
) {
344 const uint8_t *der
= CFDataGetBytePtr(peerinfo_data
);
345 CFIndex len
= CFDataGetLength(peerinfo_data
);
346 return SOSPeerInfoCreateFromDER(NULL
, error
, &der
, der
+len
);
349 static void SOSPeerInfoDestroy(CFTypeRef aObj
) {
350 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
353 CFReleaseNull(pi
->description
);
354 CFReleaseNull(pi
->signature
);
355 CFReleaseNull(pi
->gestalt
);
356 CFReleaseNull(pi
->id
);
359 static Boolean
SOSPeerInfoCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
360 SOSPeerInfoRef lpeer
= (SOSPeerInfoRef
) lhs
;
361 SOSPeerInfoRef rpeer
= (SOSPeerInfoRef
) rhs
;
362 if(!lpeer
|| !rpeer
) return false;
363 return CFEqualSafe(lpeer
->description
, rpeer
->description
) && CFEqualSafe(lpeer
->signature
, rpeer
->signature
);
367 CFComparisonResult
SOSPeerInfoCompareByID(const void *val1
, const void *val2
, void *context
) {
368 // The code below is necessary but not sufficient; not returning a CFComparisonResult
369 // It probably is OK to say that a NULL is < <non-NULL>
370 if (val1
== NULL
|| val2
== NULL
) {
371 ptrdiff_t dv
= val1
- val2
;
372 return dv
< 0 ? kCFCompareLessThan
: dv
== 0 ? kCFCompareEqualTo
: kCFCompareGreaterThan
;
375 CFStringRef v1
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val1
);
376 CFStringRef v2
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val2
);
377 if (v1
== NULL
|| v2
== NULL
) {
378 ptrdiff_t dv
= (const void *)v1
- (const void *)v2
;
379 return dv
< 0 ? kCFCompareLessThan
: dv
== 0 ? kCFCompareEqualTo
: kCFCompareGreaterThan
;
382 return CFStringCompare(v1
, v2
, 0);
385 static CFHashCode
SOSPeerInfoHash(CFTypeRef cf
) {
386 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) cf
;
388 return CFHash(peer
->description
) ^ CFHash(peer
->signature
);
391 static CFStringRef
SOSPeerInfoCopyDescription(CFTypeRef aObj
) {
392 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
394 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSPeerInfo@%p: Name:'%@'%s Type: '%@' ID:'%@'>"),
396 CFDictionaryGetValue(pi
->gestalt
, kPIUserDefinedDeviceName
),
397 SOSPeerInfoIsRetirementTicket(pi
) ? " [retired]" : "",
398 CFDictionaryGetValue(pi
->gestalt
, kPIDeviceModelName
),
402 CFDictionaryRef
SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi
) {
403 CFRetain(pi
->gestalt
);
407 CFStringRef
SOSPeerInfoGetPeerName(SOSPeerInfoRef peer
) {
408 return SOSPeerInfoLookupGestaltValue(peer
, kPIUserDefinedDeviceName
);
411 CFStringRef
SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer
) {
412 return SOSPeerInfoLookupGestaltValue(peer
, kPIDeviceModelName
);
415 CFTypeRef
SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi
, CFStringRef key
) {
416 return CFDictionaryGetValue(pi
->gestalt
, key
);
419 CFStringRef
SOSPeerInfoGetPeerID(SOSPeerInfoRef pi
) {
420 return pi
? pi
->id
: NULL
;
423 CFIndex
SOSPeerInfoGetVersion(SOSPeerInfoRef pi
) {
424 // TODO: Encode this in the DER.
428 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
429 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
430 CFDataRef pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
433 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Digest failed – no public key"));
437 ccdigest_update(di
, ctx
, CFDataGetLength(pubKeyBytes
), CFDataGetBytePtr(pubKeyBytes
));
442 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
443 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
444 size_t description_size
= der_sizeof_plist(peer
->description
, error
);
445 uint8_t data_begin
[description_size
];
446 uint8_t *data_end
= data_begin
+ description_size
;
447 uint8_t *encoded
= der_encode_plist(peer
->description
, error
, data_begin
, data_end
);
450 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Description encode failed"));
454 ccdigest_update(di
, ctx
, description_size
, data_begin
);
460 static CFDataRef
sosCreateDate() {
461 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
462 size_t bufsiz
= der_sizeof_date(now
, NULL
);
464 der_encode_date(now
, NULL
, buf
, buf
+bufsiz
);
466 return CFDataCreate(NULL
, buf
, bufsiz
);
469 static CFDateRef
sosCreateCFDate(CFDataRef sosdate
) {
471 der_decode_date(NULL
, 0, &date
, NULL
, CFDataGetBytePtr(sosdate
),
472 CFDataGetBytePtr(sosdate
) + CFDataGetLength(sosdate
));
476 static bool sospeer_application_hash(SOSPeerInfoRef pi
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
477 CFDataRef appdate
= CFDictionaryGetValue(pi
->description
, sApplicationDate
);
478 if(!appdate
) return false;
479 ccdigest_di_decl(di
, ctx
);
480 ccdigest_init(di
, ctx
);
481 ccdigest_update(di
, ctx
, CFDataGetLength(appdate
), CFDataGetBytePtr(appdate
));
482 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi
, di
, ctx
, NULL
)) return false;
483 ccdigest_final(di
, ctx
, hbuf
);
487 SOSPeerInfoRef
SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original
, SecKeyRef userkey
, SecKeyRef peerkey
, CFErrorRef
*error
) {
488 SOSPeerInfoRef result
= NULL
;
489 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, original
, error
);
491 const struct ccdigest_info
*di
= ccsha256_di();
492 uint8_t hbuf
[di
->output_size
];
493 CFDataRef usersig
= NULL
;
495 CFDataRef creationDate
= sosCreateDate();
496 CFDictionarySetValue(pi
->description
, sApplicationDate
, creationDate
);
497 CFReleaseNull(creationDate
);
499 // Create User Application Signature
500 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), fail
,
501 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
503 usersig
= sosSignHash(userkey
, di
, hbuf
);
504 require_action_quiet(usersig
, fail
,
505 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign public key hash for peer"), NULL
, error
));
507 CFDictionarySetValue(pi
->description
, sApplicationUsig
, usersig
);
509 require_quiet(SOSPeerInfoSign(peerkey
, pi
, error
), fail
);
515 CFReleaseNull(usersig
);
520 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi
, SecKeyRef userkey
, CFErrorRef
*error
) {
521 const struct ccdigest_info
*di
= ccsha256_di();
522 uint8_t hbuf
[di
->output_size
];
525 CFDataRef usig
= CFDictionaryGetValue(pi
->description
, sApplicationUsig
);
526 require_action_quiet(usig
, exit
,
527 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not an applicant"), NULL
, error
));
528 // Verify User Application Signature
529 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), exit
,
530 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
531 require_action_quiet(sosVerifyHash(userkey
, di
, hbuf
, usig
), exit
,
532 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("user signature of public key hash fails to verify"), NULL
, error
));
534 result
= SOSPeerInfoVerify(pi
, error
);
541 static CF_RETURNS_RETAINED CFDateRef
sosPeerInfoGetDate(SOSPeerInfoRef pi
, CFStringRef entry
) {
543 CFDataRef sosdate
= CFDictionaryGetValue(pi
->description
, entry
);
544 if(!sosdate
) return NULL
;
545 CFDateRef date
= sosCreateCFDate(sosdate
);
550 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi
) {
551 return sosPeerInfoGetDate(pi
, sApplicationDate
);
554 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi
) {
555 return sosPeerInfoGetDate(pi
, sRetirementDate
);
559 size_t SOSPeerInfoGetDEREncodedSize(SOSPeerInfoRef peer
, CFErrorRef
*error
) {
560 size_t plist_size
= der_sizeof_plist(peer
->description
, error
);
564 size_t signature_size
= der_sizeof_data(peer
->signature
, error
);
565 if (signature_size
== 0)
568 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
569 plist_size
+ signature_size
);
572 uint8_t* SOSPeerInfoEncodeToDER(SOSPeerInfoRef peer
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
573 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
574 der_encode_plist(peer
->description
, error
, der
,
575 der_encode_data(peer
->signature
, error
, der
, der_end
)));
578 CFDataRef
SOSPeerInfoCopyEncodedData(SOSPeerInfoRef peer
, CFAllocatorRef allocator
, CFErrorRef
*error
) {
579 size_t size
= SOSPeerInfoGetDEREncodedSize(peer
, error
);
580 if (size
== 0) return NULL
;
582 uint8_t buffer
[size
];
583 uint8_t* start
= SOSPeerInfoEncodeToDER(peer
, error
, buffer
, buffer
+ sizeof(buffer
));
584 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
590 // PeerInfoArray encoding decoding
593 CFMutableArrayRef
SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
594 const uint8_t** der_p
, const uint8_t *der_end
) {
595 CFMutableArrayRef pia
= CFArrayCreateMutableForCFTypes(allocator
);
597 const uint8_t *sequence_end
;
599 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
601 require_action(*der_p
, fail
, SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array Sequence Header"), NULL
, error
));
603 while (sequence_end
!= *der_p
) {
604 SOSPeerInfoRef pi
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, sequence_end
);
606 if (pi
== NULL
|| *der_p
== NULL
) {
607 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array DER"), (error
!= NULL
? *error
: NULL
), error
);
612 CFArrayAppendValue(pia
, pi
);
626 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia
, CFErrorRef
*error
) {
627 size_t array_size
= 0;
629 for(CFIndex count
= CFArrayGetCount(pia
);
632 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) CFArrayGetValueAtIndex(pia
, count
- 1);
634 if (CFGetTypeID(pi
) != SOSPeerInfoGetTypeID()) {
635 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
639 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
642 SOSCreateError(kSOSErrorEncodeFailure
, CFSTR("Bad DER size"), (error
!= NULL
? *error
: NULL
), error
);
646 array_size
+= pi_size
;
650 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
654 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end_param
) {
656 uint8_t* const sequence_end
= der_end_param
;
657 __block
uint8_t* der_end
= der_end_param
;
659 CFArrayForEachReverse(pia
, ^(const void *value
) {
660 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
661 if (CFGetTypeID(pi
) != SOSPeerInfoGetTypeID()) {
662 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), NULL
, error
);
663 der_end
= NULL
; // Indicate error and continue.
666 der_end
= SOSPeerInfoEncodeToDER(pi
, error
, der
, der_end
);
672 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, sequence_end
, der
, der_end
);
676 CFArrayRef
CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray
, CFErrorRef
* error
) {
678 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Array to encode"));
682 if (xpc_get_type(peerArray
) != XPC_TYPE_DATA
) {
683 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Array of peer info not array, got %@"), peerArray
);
687 const uint8_t* der
= xpc_data_get_bytes_ptr(peerArray
);
688 const uint8_t* der_end
= der
+ xpc_data_get_length(peerArray
);
690 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault
, error
, &der
, der_end
);
693 xpc_object_t
CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array
, CFErrorRef
*error
) {
694 size_t data_size
= SOSPeerInfoArrayGetDEREncodedSize(array
, error
);
697 uint8_t *data
= (uint8_t *)malloc(data_size
);
698 if (!data
) return NULL
;
700 xpc_object_t result
= NULL
;
701 if (SOSPeerInfoArrayEncodeToDER(array
, error
, data
, data
+ data_size
))
702 result
= xpc_data_create(data
, data_size
);
712 CFStringRef
SOSPeerGestaltGetName(CFDictionaryRef gestalt
) {
713 CFStringRef name
= SOSPeerGestaltGetAnswer(gestalt
, kPIUserDefinedDeviceName
);
714 return isString(name
) ? name
: NULL
;
717 CFTypeRef
SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt
, CFStringRef question
) {
718 return gestalt
? CFDictionaryGetValue(gestalt
, question
) : NULL
;
726 SOSPeerInfoRef
SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator
, SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
728 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, peer
, error
);
732 // Fill out Resignation Date
733 CFDataRef resignationDate
= sosCreateDate();
734 CFDictionaryAddValue(pi
->description
, sRetirementDate
, resignationDate
);
735 CFReleaseNull(resignationDate
);
737 require(SOSPeerInfoSign(privKey
, pi
, error
), fail
);
746 CFStringRef
SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
747 CFStringRef retval
= NULL
;
748 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
749 CFDateRef retirement
= NULL
;
751 require_quiet(SOSPeerInfoVerify(pi
, error
), err
);
753 retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
755 require_action_quiet(retirement
, err
,
756 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not retired"), NULL
, error
));
758 require_action_quiet(CFDateCompare(now
, retirement
, NULL
) == kCFCompareGreaterThan
, err
,
759 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Retirement date is after current date"), NULL
, error
));
761 retval
= SOSPeerInfoGetPeerID(pi
);
765 CFReleaseNull(retirement
);
769 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds
, SOSPeerInfoRef pi
) {
770 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
771 CFDateRef retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
772 CFTimeInterval timediff
= CFDateGetTimeIntervalSinceDate(now
, retirement
); // diff in seconds
774 CFReleaseNull(retirement
);
775 if(timediff
> (max_seconds
)) return true;
779 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi
) {
780 CFDataRef flag
= CFDictionaryGetValue(pi
->description
, sRetirementDate
);
784 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi
) {
785 CFTypeRef value
= CFDictionaryGetValue(pi
->description
, sCloudIdentityKey
);
786 return CFEqualSafe(value
, kCFBooleanTrue
);
789 SOSPeerInfoRef
SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator
, SecKeyRef privKey
, SecKeyRef peerKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
790 SecKeyRef pubKey
= SecKeyCreatePublicFromPrivate(privKey
);
791 SOSPeerInfoRef retval
= NULL
;
793 retval
= SOSPeerInfoCopyAsApplication(peer
, privKey
, peerKey
, error
);
794 CFReleaseNull(pubKey
);