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 CFStringRef v1
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val1
);
369 CFStringRef v2
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val2
);
370 return CFStringCompare(v1
, v2
, 0);
373 static CFHashCode
SOSPeerInfoHash(CFTypeRef cf
) {
374 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) cf
;
376 return CFHash(peer
->description
) ^ CFHash(peer
->signature
);
379 static CFStringRef
SOSPeerInfoCopyDescription(CFTypeRef aObj
) {
380 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
382 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSPeerInfo@%p: Name:'%@'%s Type: '%@' ID:'%@'>"),
384 CFDictionaryGetValue(pi
->gestalt
, kPIUserDefinedDeviceName
),
385 SOSPeerInfoIsRetirementTicket(pi
) ? " [retired]" : "",
386 CFDictionaryGetValue(pi
->gestalt
, kPIDeviceModelName
),
390 CFDictionaryRef
SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi
) {
391 CFRetain(pi
->gestalt
);
395 CFStringRef
SOSPeerInfoGetPeerName(SOSPeerInfoRef peer
) {
396 return SOSPeerInfoLookupGestaltValue(peer
, kPIUserDefinedDeviceName
);
399 CFStringRef
SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer
) {
400 return SOSPeerInfoLookupGestaltValue(peer
, kPIDeviceModelName
);
403 CFTypeRef
SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi
, CFStringRef key
) {
404 return CFDictionaryGetValue(pi
->gestalt
, key
);
407 CFStringRef
SOSPeerInfoGetPeerID(SOSPeerInfoRef pi
) {
411 CFIndex
SOSPeerInfoGetVersion(SOSPeerInfoRef pi
) {
412 // TODO: Encode this in the DER.
416 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
417 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
418 CFDataRef pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
421 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Digest failed – no public key"));
425 ccdigest_update(di
, ctx
, CFDataGetLength(pubKeyBytes
), CFDataGetBytePtr(pubKeyBytes
));
430 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
431 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
432 size_t description_size
= der_sizeof_plist(peer
->description
, error
);
433 uint8_t data_begin
[description_size
];
434 uint8_t *data_end
= data_begin
+ description_size
;
435 uint8_t *encoded
= der_encode_plist(peer
->description
, error
, data_begin
, data_end
);
438 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Description encode failed"));
442 ccdigest_update(di
, ctx
, description_size
, data_begin
);
448 static CFDataRef
sosCreateDate() {
449 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
450 size_t bufsiz
= der_sizeof_date(now
, NULL
);
452 der_encode_date(now
, NULL
, buf
, buf
+bufsiz
);
454 return CFDataCreate(NULL
, buf
, bufsiz
);
457 static CFDateRef
sosCreateCFDate(CFDataRef sosdate
) {
459 der_decode_date(NULL
, 0, &date
, NULL
, CFDataGetBytePtr(sosdate
),
460 CFDataGetBytePtr(sosdate
) + CFDataGetLength(sosdate
));
464 static bool sospeer_application_hash(SOSPeerInfoRef pi
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
465 CFDataRef appdate
= CFDictionaryGetValue(pi
->description
, sApplicationDate
);
466 if(!appdate
) return false;
467 ccdigest_di_decl(di
, ctx
);
468 ccdigest_init(di
, ctx
);
469 ccdigest_update(di
, ctx
, CFDataGetLength(appdate
), CFDataGetBytePtr(appdate
));
470 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi
, di
, ctx
, NULL
)) return false;
471 ccdigest_final(di
, ctx
, hbuf
);
475 SOSPeerInfoRef
SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original
, SecKeyRef userkey
, SecKeyRef peerkey
, CFErrorRef
*error
) {
476 SOSPeerInfoRef result
= NULL
;
477 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, original
, error
);
479 const struct ccdigest_info
*di
= ccsha256_di();
480 uint8_t hbuf
[di
->output_size
];
481 CFDataRef usersig
= NULL
;
483 CFDataRef creationDate
= sosCreateDate();
484 CFDictionarySetValue(pi
->description
, sApplicationDate
, creationDate
);
485 CFReleaseNull(creationDate
);
487 // Create User Application Signature
488 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), fail
,
489 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
491 usersig
= sosSignHash(userkey
, di
, hbuf
);
492 require_action_quiet(usersig
, fail
,
493 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign public key hash for peer"), NULL
, error
));
495 CFDictionarySetValue(pi
->description
, sApplicationUsig
, usersig
);
497 require_quiet(SOSPeerInfoSign(peerkey
, pi
, error
), fail
);
503 CFReleaseNull(usersig
);
508 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi
, SecKeyRef userkey
, CFErrorRef
*error
) {
509 const struct ccdigest_info
*di
= ccsha256_di();
510 uint8_t hbuf
[di
->output_size
];
513 CFDataRef usig
= CFDictionaryGetValue(pi
->description
, sApplicationUsig
);
514 require_action_quiet(usig
, exit
,
515 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not an applicant"), NULL
, error
));
516 // Verify User Application Signature
517 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), exit
,
518 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
519 require_action_quiet(sosVerifyHash(userkey
, di
, hbuf
, usig
), exit
,
520 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("user signature of public key hash fails to verify"), NULL
, error
));
522 result
= SOSPeerInfoVerify(pi
, error
);
529 static CF_RETURNS_RETAINED CFDateRef
sosPeerInfoGetDate(SOSPeerInfoRef pi
, CFStringRef entry
) {
531 CFDataRef sosdate
= CFDictionaryGetValue(pi
->description
, entry
);
532 if(!sosdate
) return NULL
;
533 CFDateRef date
= sosCreateCFDate(sosdate
);
538 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi
) {
539 return sosPeerInfoGetDate(pi
, sApplicationDate
);
542 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi
) {
543 return sosPeerInfoGetDate(pi
, sRetirementDate
);
547 size_t SOSPeerInfoGetDEREncodedSize(SOSPeerInfoRef peer
, CFErrorRef
*error
) {
548 size_t plist_size
= der_sizeof_plist(peer
->description
, error
);
552 size_t signature_size
= der_sizeof_data(peer
->signature
, error
);
553 if (signature_size
== 0)
556 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
557 plist_size
+ signature_size
);
560 uint8_t* SOSPeerInfoEncodeToDER(SOSPeerInfoRef peer
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
561 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
562 der_encode_plist(peer
->description
, error
, der
,
563 der_encode_data(peer
->signature
, error
, der
, der_end
)));
566 CFDataRef
SOSPeerInfoCopyEncodedData(SOSPeerInfoRef peer
, CFAllocatorRef allocator
, CFErrorRef
*error
) {
567 size_t size
= SOSPeerInfoGetDEREncodedSize(peer
, error
);
568 if (size
== 0) return NULL
;
570 uint8_t buffer
[size
];
571 uint8_t* start
= SOSPeerInfoEncodeToDER(peer
, error
, buffer
, buffer
+ sizeof(buffer
));
572 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
578 // PeerInfoArray encoding decoding
581 CFMutableArrayRef
SOSPeerInfoArrayCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
582 const uint8_t** der_p
, const uint8_t *der_end
) {
583 CFMutableArrayRef pia
= CFArrayCreateMutableForCFTypes(allocator
);
585 const uint8_t *sequence_end
;
587 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
589 require_action(*der_p
, fail
, SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array Sequence Header"), NULL
, error
));
591 while (sequence_end
!= *der_p
) {
592 SOSPeerInfoRef pi
= SOSPeerInfoCreateFromDER(allocator
, error
, der_p
, sequence_end
);
594 if (pi
== NULL
|| *der_p
== NULL
) {
595 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Peer Info Array DER"), (error
!= NULL
? *error
: NULL
), error
);
600 CFArrayAppendValue(pia
, pi
);
614 size_t SOSPeerInfoArrayGetDEREncodedSize(CFArrayRef pia
, CFErrorRef
*error
) {
615 size_t array_size
= 0;
617 for(CFIndex count
= CFArrayGetCount(pia
);
620 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) CFArrayGetValueAtIndex(pia
, count
- 1);
622 if (CFGetTypeID(pi
) != SOSPeerInfoGetTypeID()) {
623 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), (error
!= NULL
? *error
: NULL
), error
);
627 size_t pi_size
= SOSPeerInfoGetDEREncodedSize(pi
, error
);
630 SOSCreateError(kSOSErrorEncodeFailure
, CFSTR("Bad DER size"), (error
!= NULL
? *error
: NULL
), error
);
634 array_size
+= pi_size
;
638 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
642 uint8_t* SOSPeerInfoArrayEncodeToDER(CFArrayRef pia
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end_param
) {
644 uint8_t* const sequence_end
= der_end_param
;
645 __block
uint8_t* der_end
= der_end_param
;
647 CFArrayForEachReverse(pia
, ^(const void *value
) {
648 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
649 if (CFGetTypeID(pi
) != SOSPeerInfoGetTypeID()) {
650 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Non SOSPeerInfo in array"), NULL
, error
);
651 der_end
= NULL
; // Indicate error and continue.
654 der_end
= SOSPeerInfoEncodeToDER(pi
, error
, der
, der_end
);
660 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, sequence_end
, der
, der_end
);
664 CFArrayRef
CreateArrayOfPeerInfoWithXPCObject(xpc_object_t peerArray
, CFErrorRef
* error
) {
666 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Array to encode"));
670 if (xpc_get_type(peerArray
) != XPC_TYPE_DATA
) {
671 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Array of peer info not array, got %@"), peerArray
);
675 const uint8_t* der
= xpc_data_get_bytes_ptr(peerArray
);
676 const uint8_t* der_end
= der
+ xpc_data_get_length(peerArray
);
678 return SOSPeerInfoArrayCreateFromDER(kCFAllocatorDefault
, error
, &der
, der_end
);
681 xpc_object_t
CreateXPCObjectWithArrayOfPeerInfo(CFArrayRef array
, CFErrorRef
*error
) {
682 size_t data_size
= SOSPeerInfoArrayGetDEREncodedSize(array
, error
);
685 uint8_t *data
= (uint8_t *)malloc(data_size
);
686 if (!data
) return NULL
;
688 xpc_object_t result
= NULL
;
689 if (SOSPeerInfoArrayEncodeToDER(array
, error
, data
, data
+ data_size
))
690 result
= xpc_data_create(data
, data_size
);
700 CFStringRef
SOSPeerGestaltGetName(CFDictionaryRef gestalt
) {
701 CFStringRef name
= SOSPeerGestaltGetAnswer(gestalt
, kPIUserDefinedDeviceName
);
702 return isString(name
) ? name
: NULL
;
705 CFTypeRef
SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt
, CFStringRef question
) {
706 return gestalt
? CFDictionaryGetValue(gestalt
, question
) : NULL
;
714 SOSPeerInfoRef
SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator
, SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
716 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, peer
, error
);
720 // Fill out Resignation Date
721 CFDataRef resignationDate
= sosCreateDate();
722 CFDictionaryAddValue(pi
->description
, sRetirementDate
, resignationDate
);
723 CFReleaseNull(resignationDate
);
725 require(SOSPeerInfoSign(privKey
, pi
, error
), fail
);
734 CFStringRef
SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
735 CFStringRef retval
= NULL
;
736 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
737 CFDateRef retirement
= NULL
;
739 require_quiet(SOSPeerInfoVerify(pi
, error
), err
);
741 retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
743 require_action_quiet(retirement
, err
,
744 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not retired"), NULL
, error
));
746 require_action_quiet(CFDateCompare(now
, retirement
, NULL
) == kCFCompareGreaterThan
, err
,
747 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Retirement date is after current date"), NULL
, error
));
749 retval
= SOSPeerInfoGetPeerID(pi
);
753 CFReleaseNull(retirement
);
757 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds
, SOSPeerInfoRef pi
) {
758 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
759 CFDateRef retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
760 CFTimeInterval timediff
= CFDateGetTimeIntervalSinceDate(now
, retirement
); // diff in seconds
762 CFReleaseNull(retirement
);
763 if(timediff
> (max_seconds
)) return true;
767 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi
) {
768 CFDataRef flag
= CFDictionaryGetValue(pi
->description
, sRetirementDate
);
772 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi
) {
773 CFTypeRef value
= CFDictionaryGetValue(pi
->description
, sCloudIdentityKey
);
774 return CFEqualSafe(value
, kCFBooleanTrue
);
777 SOSPeerInfoRef
SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator
, SecKeyRef privKey
, SecKeyRef peerKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
778 SecKeyRef pubKey
= SecKeyCreatePublicFromPrivate(privKey
);
779 SOSPeerInfoRef retval
= NULL
;
781 retval
= SOSPeerInfoCopyAsApplication(peer
, privKey
, peerKey
, error
);
782 CFReleaseNull(pubKey
);