2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
26 #include <TargetConditionals.h>
28 #include <SecureObjectSync/SOSPeerInfo.h>
29 #include <SecureObjectSync/SOSPeerInfoInternal.h>
30 #include <SecureObjectSync/SOSCircle.h>
32 #include <SecureObjectSync/SOSInternal.h>
33 #include <ipc/securityd_client.h>
35 #include <CoreFoundation/CFArray.h>
36 #include <dispatch/dispatch.h>
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/SecCFRelease.h>
43 #include <utilities/SecCFError.h>
44 #include <utilities/SecXPCError.h>
46 #include <utilities/der_plist.h>
47 #include <utilities/der_plist_internal.h>
48 #include <corecrypto/ccder.h>
49 #include <utilities/der_date.h>
51 #include <corecrypto/ccdigest.h>
52 #include <corecrypto/ccsha2.h>
55 #include <CoreFoundation/CoreFoundation.h>
56 #include <CoreFoundation/CFDate.h>
60 #if TARGET_OS_IPHONE || TARGET_OS_EMBEDDED
61 #include <MobileGestalt.h>
64 #include <Security/SecBase64.h>
65 #include <Security/SecKeyPriv.h>
66 #include <Security/SecOTR.h>
67 #include <Security/SecuritydXPC.h>
69 #if 0//TARGET_OS_MAC // TODO: this function is the only one that causes secd to need to link against Security.framework on OSX
72 SecKeyRef
_SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef publicBytes
);
75 #endif /* TARGET_OS_MAC */
77 struct __OpaqueSOSPeerInfo
{
81 CFMutableDictionaryRef description
;
85 CFDictionaryRef gestalt
;
89 CFStringRef transportType
;
93 CFGiblisWithHashFor(SOSPeerInfo
);
95 CFStringRef kPIUserDefinedDeviceName
= CFSTR("ComputerName");
96 CFStringRef kPIDeviceModelName
= CFSTR("ModelName");
97 CFStringRef kPIMessageProtocolVersion
= CFSTR("MessageProtocolVersion");
99 // Description Dictionary Entries
100 static CFStringRef sPublicKeyKey
= CFSTR("PublicSigningKey");
101 static CFStringRef sGestaltKey
= CFSTR("DeviceGestalt");
102 static CFStringRef sVersionKey
= CFSTR("ConflictVersion");
103 static CFStringRef sCloudIdentityKey
= CFSTR("CloudIdentity");
104 static CFStringRef sApplicationDate
= CFSTR("ApplicationDate");
105 static CFStringRef sApplicationUsig
= CFSTR("ApplicationUsig");
106 static CFStringRef sRetirementDate
= CFSTR("RetirementDate");
109 CFStringRef kSOSPeerInfoDescriptionKey
= CFSTR("SOSPeerInfoDescription");
110 CFStringRef kSOSPeerInfoSignatureKey
= CFSTR("SOSPeerInfoSignature");
111 CFStringRef kSOSPeerInfoNameKey
= CFSTR("SOSPeerInfoName");
114 SecKeyRef
SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer
) {
115 CFDataRef pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
116 if (pubKeyBytes
== NULL
)
118 CFAllocatorRef allocator
= CFGetAllocator(peer
);
119 SecKeyRef pubKey
= SecKeyCreateFromPublicData(allocator
, kSecECDSAAlgorithmID
, pubKeyBytes
);
124 static bool SOSDescriptionHash(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
, void *hashresult
, CFErrorRef
*error
) {
125 ccdigest_di_decl(di
, ctx
);
126 ccdigest_init(di
, ctx
);
128 if(!SOSPeerInfoUpdateDigestWithDescription(peer
, di
, ctx_p
, error
)) return false;
129 ccdigest_final(di
, ctx
, hashresult
);
135 static CFDataRef
sosSignHash(SecKeyRef privkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
137 size_t siglen
= SIGLEN
;
139 if((stat
= SecKeyRawSign(privkey
, kSecPaddingNone
, hbuf
, di
->output_size
, sig
, &siglen
)) != 0) {
142 return CFDataCreate(NULL
, sig
, (CFIndex
)siglen
);
145 static bool sosVerifyHash(SecKeyRef pubkey
, const struct ccdigest_info
*di
, uint8_t *hbuf
, CFDataRef signature
) {
146 return SecKeyRawVerify(pubkey
, kSecPaddingNone
, hbuf
, di
->output_size
,
147 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)) == errSecSuccess
;
150 static bool SOSPeerInfoSign(SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
152 const struct ccdigest_info
*di
= ccsha256_di();
153 uint8_t hbuf
[di
->output_size
];
154 CFDataRef newSignature
= NULL
;
156 require_action_quiet(SOSDescriptionHash(peer
, di
, hbuf
, error
), fail
,
157 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to hash description for peer"), NULL
, error
));
159 newSignature
= sosSignHash(privKey
, di
, hbuf
);
160 require_action_quiet(newSignature
, fail
, SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign peerinfo for peer"), NULL
, error
));
162 CFReleaseNull(peer
->signature
);
163 peer
->signature
= newSignature
;
168 CFReleaseNull(newSignature
);
172 // Return true (1) if the signature verifies.
173 static bool SOSPeerInfoVerify(SOSPeerInfoRef peer
, CFErrorRef
*error
) {
175 const struct ccdigest_info
*di
= ccsha256_di();
176 uint8_t hbuf
[di
->output_size
];
178 SecKeyRef pubKey
= SOSPeerInfoCopyPubKey(peer
);
179 require_action_quiet(pubKey
, error_out
,
180 SOSErrorCreate(kSOSErrorNoKey
, error
, NULL
,
181 CFSTR("Couldn't find pub key for %@"), peer
));
183 require_quiet(SOSDescriptionHash(peer
, di
, hbuf
, error
), error_out
);
185 require_action_quiet(sosVerifyHash(pubKey
, di
, hbuf
, peer
->signature
), error_out
,
186 SOSErrorCreate(kSOSErrorBadSignature
, error
, NULL
,
187 CFSTR("Signature didn't verify for %@"), peer
));
191 CFReleaseNull(pubKey
);
195 static SOSPeerInfoRef
SOSPeerInfoCreate_Internal(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
, void (^ description_modifier
)(CFMutableDictionaryRef description
)) {
196 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
197 pi
->gestalt
= gestalt
;
198 CFRetain(pi
->gestalt
);
200 pi
->version
= SOSPeerInfoGetPeerProtocolVersion(pi
);
201 pi
->transportType
= CFStringCreateCopy(kCFAllocatorDefault
, CFSTR("KVS"));
202 CFDataRef publicBytes
= NULL
;
203 CFNumberRef versionNumber
= NULL
;
205 SecKeyRef publicKey
= SecKeyCreatePublicFromPrivate(signingKey
);
206 if (publicKey
== NULL
) {
207 SOSCreateError(kSOSErrorBadKey
, CFSTR("Unable to get public"), NULL
, error
);
212 OSStatus result
= SecKeyCopyPublicBytes(publicKey
, &publicBytes
);
214 if (result
!= errSecSuccess
) {
215 SOSCreateError(kSOSErrorBadKey
, CFSTR("Failed to export public bytes"), NULL
, error
);
220 pi
->signature
= CFDataCreateMutable(allocator
, 0);
222 versionNumber
= CFNumberCreateWithCFIndex(NULL
, pi
->version
);
223 pi
->description
= CFDictionaryCreateMutableForCFTypesWith(allocator
,
224 sVersionKey
, versionNumber
,
225 sPublicKeyKey
, publicBytes
,
226 sGestaltKey
, pi
->gestalt
,
228 description_modifier(pi
->description
);
230 CFStringRef deviceName
= CFDictionaryGetValue(pi
->gestalt
, kPIUserDefinedDeviceName
);
231 CFStringRef modelName
= CFDictionaryGetValue(pi
->gestalt
, kPIDeviceModelName
);
232 CFStringRef ID
= pi
->id
;
233 CFMutableStringRef description
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(deviceName
), deviceName
);
235 CFStringAppend(description
, CFSTR(", "));
236 CFStringAppend(description
, modelName
);
239 CFStringAppend(description
, CFSTR(", "));
240 CFStringAppend(description
, ID
);
243 pi
->deviceID
= CFStringCreateCopy(kCFAllocatorDefault
, description
);
244 CFReleaseNull(description
);
246 pi
->id
= SOSCopyIDOfKey(publicKey
, error
);
247 CFReleaseNull(publicKey
);
249 require_quiet(pi
->id
, exit
);
251 if (!SOSPeerInfoSign(signingKey
, pi
, error
)) {
257 CFReleaseNull(versionNumber
);
258 CFReleaseNull(publicBytes
);
262 SOSPeerInfoRef
SOSPeerInfoCreate(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
263 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {});
266 SOSPeerInfoRef
SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
267 return SOSPeerInfoCreate_Internal(allocator
, gestalt
, signingKey
, error
, ^(CFMutableDictionaryRef description
) {
268 CFDictionarySetValue(description
, sCloudIdentityKey
, kCFBooleanTrue
);
274 SOSPeerInfoRef
SOSPeerInfoCreateCopy(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFErrorRef
* error
) {
275 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
277 pi
->description
= CFDictionaryCreateMutableCopy(allocator
, 0, toCopy
->description
);
278 pi
->signature
= CFDataCreateCopy(allocator
, toCopy
->signature
);
280 pi
->gestalt
= CFDictionaryCreateCopy(allocator
, toCopy
->gestalt
);
281 pi
->id
= CFStringCreateCopy(allocator
, toCopy
->id
);
282 pi
->transportType
= CFStringCreateCopy(allocator
, toCopy
->transportType
);
283 pi
->deviceID
= CFStringCreateCopy(kCFAllocatorDefault
, toCopy
->deviceID
);
284 pi
->version
= toCopy
->version
;
289 SOSPeerInfoRef
SOSPeerInfoCopyWithGestaltUpdate(CFAllocatorRef allocator
, SOSPeerInfoRef toCopy
, CFDictionaryRef gestalt
, SecKeyRef signingKey
, CFErrorRef
* error
) {
290 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, toCopy
, error
);
292 CFRetainSafe(gestalt
);
293 CFReleaseNull(pi
->gestalt
);
294 pi
->gestalt
= gestalt
;
296 CFDictionarySetValue(pi
->description
, sGestaltKey
, pi
->gestalt
);
298 SecKeyRef pub_key
= SOSPeerInfoCopyPubKey(pi
);
300 pi
->id
= SOSCopyIDOfKey(pub_key
, error
);
301 require_quiet(pi
->id
, exit
);
303 require_action_quiet(SOSPeerInfoSign(signingKey
, pi
, error
), exit
, CFReleaseNull(pi
));
306 CFReleaseNull(pub_key
);
310 SOSPeerInfoRef
SOSPeerInfoCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
311 const uint8_t** der_p
, const uint8_t *der_end
) {
312 SOSPeerInfoRef pi
= CFTypeAllocate(SOSPeerInfo
, struct __OpaqueSOSPeerInfo
, allocator
);
313 SecKeyRef pubKey
= NULL
;
315 const uint8_t *sequence_end
;
317 CFPropertyListRef pl
= NULL
;
320 pi
->version
= 0; // TODO: Encode this in the DER
321 pi
->transportType
= CFStringCreateCopy(kCFAllocatorDefault
, CFSTR("KVS"));
322 *der_p
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &sequence_end
, *der_p
, der_end
);
323 *der_p
= der_decode_plist(allocator
, kCFPropertyListImmutable
, &pl
, error
, *der_p
, sequence_end
);
324 *der_p
= der_decode_data(allocator
, kCFPropertyListImmutable
, &pi
->signature
, error
, *der_p
, sequence_end
);
326 if (*der_p
== NULL
|| *der_p
!= sequence_end
) {
327 SOSCreateError(kSOSErrorBadFormat
, CFSTR("Bad Format of Peer Info DER"), NULL
, error
);
331 if (CFGetTypeID(pl
) != CFDictionaryGetTypeID()) {
332 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(pl
));
333 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
334 CFSTR("Expected dictionary got %@"), description
);
335 CFReleaseSafe(description
);
339 pi
->description
= (CFMutableDictionaryRef
) pl
;
340 CFRetain(pi
->description
);
343 CFNumberRef versionNumber
= CFDictionaryGetValue(pi
->description
, sVersionKey
);
346 if (CFGetTypeID(versionNumber
) != CFNumberGetTypeID()) {
347 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(versionNumber
));
348 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
349 CFSTR("Expected (version) number got %@"), description
);
350 CFReleaseSafe(description
);
353 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &pi
->version
);
356 CFDictionaryRef gestalt
= CFDictionaryGetValue(pi
->description
, sGestaltKey
);
358 if (gestalt
== NULL
) {
359 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
360 CFSTR("gestalt key missing"));
364 if (!isDictionary(gestalt
)) {
365 CFStringRef description
= CFCopyTypeIDDescription(CFGetTypeID(gestalt
));
366 SOSCreateErrorWithFormat(kSOSErrorUnexpectedType
, NULL
, error
, NULL
,
367 CFSTR("Expected dictionary got %@"), description
);
368 CFReleaseSafe(description
);
372 pi
->gestalt
= gestalt
;
373 CFRetain(pi
->gestalt
);
375 pubKey
= SOSPeerInfoCopyPubKey(pi
);
376 require_quiet(pubKey
, fail
);
378 pi
->id
= SOSCopyIDOfKey(pubKey
, error
);
379 require_quiet(pi
->id
, fail
);
381 if(!SOSPeerInfoVerify(pi
, error
)) {
382 SOSCreateErrorWithFormat(kSOSErrorBadSignature
, NULL
, error
, NULL
, CFSTR("Signature doesn't validate"));
384 secerror("Can't validate PeerInfo: %@", *error
);
388 CFStringRef deviceName
= CFDictionaryGetValue(pi
->gestalt
, kPIUserDefinedDeviceName
);
389 CFStringRef modelName
= CFDictionaryGetValue(pi
->gestalt
, kPIDeviceModelName
);
390 CFStringRef ID
= pi
->id
;
391 CFMutableStringRef description
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(deviceName
), deviceName
);
393 CFStringAppend(description
, CFSTR(", "));
394 CFStringAppend(description
, modelName
);
397 CFStringAppend(description
, CFSTR(", "));
398 CFStringAppend(description
, ID
);
401 pi
->deviceID
= CFStringCreateCopy(kCFAllocatorDefault
, description
);
402 CFReleaseNull(description
);
403 CFReleaseNull(pubKey
);
409 CFReleaseNull(pubKey
);
414 SOSPeerInfoRef
SOSPeerInfoCreateFromData(CFAllocatorRef allocator
, CFErrorRef
* error
,
415 CFDataRef peerinfo_data
) {
416 const uint8_t *der
= CFDataGetBytePtr(peerinfo_data
);
417 CFIndex len
= CFDataGetLength(peerinfo_data
);
418 return SOSPeerInfoCreateFromDER(NULL
, error
, &der
, der
+len
);
421 static void SOSPeerInfoDestroy(CFTypeRef aObj
) {
422 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
425 CFReleaseNull(pi
->description
);
426 CFReleaseNull(pi
->signature
);
427 CFReleaseNull(pi
->gestalt
);
428 CFReleaseNull(pi
->id
);
429 CFReleaseNull(pi
->deviceID
);
432 static Boolean
SOSPeerInfoCompare(CFTypeRef lhs
, CFTypeRef rhs
) {
433 SOSPeerInfoRef lpeer
= (SOSPeerInfoRef
) lhs
;
434 SOSPeerInfoRef rpeer
= (SOSPeerInfoRef
) rhs
;
435 if(!lpeer
|| !rpeer
) return false;
436 return CFEqualSafe(lpeer
->description
, rpeer
->description
) && CFEqualSafe(lpeer
->signature
, rpeer
->signature
);
440 CFComparisonResult
SOSPeerInfoCompareByID(const void *val1
, const void *val2
, void *context
) {
441 // The code below is necessary but not sufficient; not returning a CFComparisonResult
442 // It probably is OK to say that a NULL is < <non-NULL>
443 if (val1
== NULL
|| val2
== NULL
) {
444 ptrdiff_t dv
= val1
- val2
;
445 return dv
< 0 ? kCFCompareLessThan
: dv
== 0 ? kCFCompareEqualTo
: kCFCompareGreaterThan
;
448 CFStringRef v1
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val1
);
449 CFStringRef v2
= SOSPeerInfoGetPeerID((SOSPeerInfoRef
) val2
);
450 if (v1
== NULL
|| v2
== NULL
) {
451 ptrdiff_t dv
= (const void *)v1
- (const void *)v2
;
452 return dv
< 0 ? kCFCompareLessThan
: dv
== 0 ? kCFCompareEqualTo
: kCFCompareGreaterThan
;
455 return CFStringCompare(v1
, v2
, 0);
458 static CFHashCode
SOSPeerInfoHash(CFTypeRef cf
) {
459 SOSPeerInfoRef peer
= (SOSPeerInfoRef
) cf
;
461 return CFHash(peer
->description
) ^ CFHash(peer
->signature
);
464 static CFStringRef
SOSPeerInfoCopyDescription(CFTypeRef aObj
) {
465 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) aObj
;
466 CFIndex version
= SOSPeerInfoGetPeerProtocolVersion(pi
);
468 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSPeerInfo@%p: %s '%@' %@ %@ %ld>"),
470 SOSPeerInfoIsRetirementTicket(pi
) ? "R" : "-",
471 CFDictionaryGetValue(pi
->gestalt
, kPIUserDefinedDeviceName
),
472 CFDictionaryGetValue(pi
->gestalt
, kPIDeviceModelName
),
477 CFDictionaryRef
SOSPeerInfoCopyPeerGestalt(SOSPeerInfoRef pi
) {
478 CFRetain(pi
->gestalt
);
482 CFStringRef
SOSPeerInfoGetTransportType(SOSPeerInfoRef peer
){
483 return peer
->transportType
;
486 CFStringRef
SOSPeerInfoGetDeviceID(SOSPeerInfoRef peer
){
487 return peer
->deviceID
;
490 void SOSPeerInfoSetDeviceID(SOSPeerInfoRef peer
, CFStringRef IDS
){
491 CFReleaseNull(peer
->deviceID
);
492 peer
->deviceID
= CFStringCreateCopy(kCFAllocatorDefault
, IDS
);
495 CFStringRef
SOSPeerInfoGetPeerName(SOSPeerInfoRef peer
) {
496 return SOSPeerInfoLookupGestaltValue(peer
, kPIUserDefinedDeviceName
);
499 CFStringRef
SOSPeerInfoGetPeerDeviceType(SOSPeerInfoRef peer
) {
500 return SOSPeerInfoLookupGestaltValue(peer
, kPIDeviceModelName
);
503 CFIndex
SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer
) {
505 CFTypeRef val
= SOSPeerInfoLookupGestaltValue(peer
, kPIMessageProtocolVersion
);
506 if (val
&& CFGetTypeID(val
) == CFNumberGetTypeID())
507 CFNumberGetValue(val
, kCFNumberCFIndexType
, &version
);
511 CFTypeRef
SOSPeerInfoLookupGestaltValue(SOSPeerInfoRef pi
, CFStringRef key
) {
512 return CFDictionaryGetValue(pi
->gestalt
, key
);
515 CFStringRef
SOSPeerInfoGetPeerID(SOSPeerInfoRef pi
) {
516 return pi
? pi
->id
: NULL
;
519 CFIndex
SOSPeerInfoGetVersion(SOSPeerInfoRef pi
) {
520 // TODO: Encode this in the DER.
524 bool SOSPeerInfoUpdateDigestWithPublicKeyBytes(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
525 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
526 CFDataRef pubKeyBytes
= CFDictionaryGetValue(peer
->description
, sPublicKeyKey
);
529 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Digest failed – no public key"));
533 ccdigest_update(di
, ctx
, CFDataGetLength(pubKeyBytes
), CFDataGetBytePtr(pubKeyBytes
));
538 bool SOSPeerInfoUpdateDigestWithDescription(SOSPeerInfoRef peer
, const struct ccdigest_info
*di
,
539 ccdigest_ctx_t ctx
, CFErrorRef
*error
) {
540 size_t description_size
= der_sizeof_plist(peer
->description
, error
);
541 uint8_t data_begin
[description_size
];
542 uint8_t *data_end
= data_begin
+ description_size
;
543 uint8_t *encoded
= der_encode_plist(peer
->description
, error
, data_begin
, data_end
);
546 SOSCreateErrorWithFormat(kSOSErrorEncodeFailure
, NULL
, error
, NULL
, CFSTR("Description encode failed"));
550 ccdigest_update(di
, ctx
, description_size
, data_begin
);
556 static CFDataRef
sosCreateDate() {
557 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
558 size_t bufsiz
= der_sizeof_date(now
, NULL
);
560 der_encode_date(now
, NULL
, buf
, buf
+bufsiz
);
562 return CFDataCreate(NULL
, buf
, bufsiz
);
565 static CFDateRef
sosCreateCFDate(CFDataRef sosdate
) {
567 der_decode_date(NULL
, 0, &date
, NULL
, CFDataGetBytePtr(sosdate
),
568 CFDataGetBytePtr(sosdate
) + CFDataGetLength(sosdate
));
572 static bool sospeer_application_hash(SOSPeerInfoRef pi
, const struct ccdigest_info
*di
, uint8_t *hbuf
) {
573 CFDataRef appdate
= CFDictionaryGetValue(pi
->description
, sApplicationDate
);
574 if(!appdate
) return false;
575 ccdigest_di_decl(di
, ctx
);
576 ccdigest_init(di
, ctx
);
577 ccdigest_update(di
, ctx
, CFDataGetLength(appdate
), CFDataGetBytePtr(appdate
));
578 if (!SOSPeerInfoUpdateDigestWithPublicKeyBytes(pi
, di
, ctx
, NULL
)) return false;
579 ccdigest_final(di
, ctx
, hbuf
);
583 SOSPeerInfoRef
SOSPeerInfoCopyAsApplication(SOSPeerInfoRef original
, SecKeyRef userkey
, SecKeyRef peerkey
, CFErrorRef
*error
) {
584 SOSPeerInfoRef result
= NULL
;
585 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, original
, error
);
586 pi
->transportType
= CFStringCreateCopy(kCFAllocatorDefault
, CFSTR("KVS"));
587 const struct ccdigest_info
*di
= ccsha256_di();
588 uint8_t hbuf
[di
->output_size
];
589 CFDataRef usersig
= NULL
;
591 CFDataRef creationDate
= sosCreateDate();
592 CFDictionarySetValue(pi
->description
, sApplicationDate
, creationDate
);
593 CFReleaseNull(creationDate
);
595 // Create User Application Signature
596 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), fail
,
597 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
599 usersig
= sosSignHash(userkey
, di
, hbuf
);
600 require_action_quiet(usersig
, fail
,
601 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to sign public key hash for peer"), NULL
, error
));
603 CFDictionarySetValue(pi
->description
, sApplicationUsig
, usersig
);
605 require_quiet(SOSPeerInfoSign(peerkey
, pi
, error
), fail
);
611 CFReleaseNull(usersig
);
616 bool SOSPeerInfoApplicationVerify(SOSPeerInfoRef pi
, SecKeyRef userkey
, CFErrorRef
*error
) {
617 const struct ccdigest_info
*di
= ccsha256_di();
618 uint8_t hbuf
[di
->output_size
];
621 CFDataRef usig
= CFDictionaryGetValue(pi
->description
, sApplicationUsig
);
622 require_action_quiet(usig
, exit
,
623 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not an applicant"), NULL
, error
));
624 // Verify User Application Signature
625 require_action_quiet(sospeer_application_hash(pi
, di
, hbuf
), exit
,
626 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Failed to create hash for peer applicant"), NULL
, error
));
627 require_action_quiet(sosVerifyHash(userkey
, di
, hbuf
, usig
), exit
,
628 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("user signature of public key hash fails to verify"), NULL
, error
));
630 result
= SOSPeerInfoVerify(pi
, error
);
637 static CF_RETURNS_RETAINED CFDateRef
sosPeerInfoGetDate(SOSPeerInfoRef pi
, CFStringRef entry
) {
639 CFDataRef sosdate
= CFDictionaryGetValue(pi
->description
, entry
);
640 if(!sosdate
) return NULL
;
641 CFDateRef date
= sosCreateCFDate(sosdate
);
646 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetApplicationDate(SOSPeerInfoRef pi
) {
647 return sosPeerInfoGetDate(pi
, sApplicationDate
);
650 CF_RETURNS_RETAINED CFDateRef
SOSPeerInfoGetRetirementDate(SOSPeerInfoRef pi
) {
651 return sosPeerInfoGetDate(pi
, sRetirementDate
);
655 size_t SOSPeerInfoGetDEREncodedSize(SOSPeerInfoRef peer
, CFErrorRef
*error
) {
656 size_t plist_size
= der_sizeof_plist(peer
->description
, error
);
660 size_t signature_size
= der_sizeof_data(peer
->signature
, error
);
661 if (signature_size
== 0)
664 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
,
665 plist_size
+ signature_size
);
668 uint8_t* SOSPeerInfoEncodeToDER(SOSPeerInfoRef peer
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
669 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, der_end
, der
,
670 der_encode_plist(peer
->description
, error
, der
,
671 der_encode_data(peer
->signature
, error
, der
, der_end
)));
674 CFDataRef
SOSPeerInfoCopyEncodedData(SOSPeerInfoRef peer
, CFAllocatorRef allocator
, CFErrorRef
*error
) {
675 size_t size
= SOSPeerInfoGetDEREncodedSize(peer
, error
);
676 if (size
== 0) return NULL
;
678 uint8_t buffer
[size
];
679 uint8_t* start
= SOSPeerInfoEncodeToDER(peer
, error
, buffer
, buffer
+ sizeof(buffer
));
680 CFDataRef result
= CFDataCreate(kCFAllocatorDefault
, start
, size
);
689 CFStringRef
SOSPeerGestaltGetName(CFDictionaryRef gestalt
) {
690 CFStringRef name
= SOSPeerGestaltGetAnswer(gestalt
, kPIUserDefinedDeviceName
);
691 return isString(name
) ? name
: NULL
;
694 CFTypeRef
SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt
, CFStringRef question
) {
695 return gestalt
? CFDictionaryGetValue(gestalt
, question
) : NULL
;
703 SOSPeerInfoRef
SOSPeerInfoCreateRetirementTicket(CFAllocatorRef allocator
, SecKeyRef privKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
705 SOSPeerInfoRef pi
= SOSPeerInfoCreateCopy(allocator
, peer
, error
);
709 // Fill out Resignation Date
710 CFDataRef resignationDate
= sosCreateDate();
711 CFDictionaryAddValue(pi
->description
, sRetirementDate
, resignationDate
);
712 CFReleaseNull(resignationDate
);
714 require(SOSPeerInfoSign(privKey
, pi
, error
), fail
);
723 CFStringRef
SOSPeerInfoInspectRetirementTicket(SOSPeerInfoRef pi
, CFErrorRef
*error
) {
724 CFStringRef retval
= NULL
;
725 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
726 CFDateRef retirement
= NULL
;
728 require_quiet(SOSPeerInfoVerify(pi
, error
), err
);
730 retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
732 require_action_quiet(retirement
, err
,
733 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Peer is not retired"), NULL
, error
));
735 require_action_quiet(CFDateCompare(now
, retirement
, NULL
) == kCFCompareGreaterThan
, err
,
736 SOSCreateError(kSOSErrorUnexpectedType
, CFSTR("Retirement date is after current date"), NULL
, error
));
738 retval
= SOSPeerInfoGetPeerID(pi
);
742 CFReleaseNull(retirement
);
746 bool SOSPeerInfoRetireRetirementTicket(size_t max_seconds
, SOSPeerInfoRef pi
) {
747 CFDateRef now
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
748 CFDateRef retirement
= sosCreateCFDate(CFDictionaryGetValue(pi
->description
, sRetirementDate
));
749 CFTimeInterval timediff
= CFDateGetTimeIntervalSinceDate(now
, retirement
); // diff in seconds
751 CFReleaseNull(retirement
);
752 if(timediff
> (max_seconds
)) return true;
756 bool SOSPeerInfoIsRetirementTicket(SOSPeerInfoRef pi
) {
757 CFDataRef flag
= CFDictionaryGetValue(pi
->description
, sRetirementDate
);
761 bool SOSPeerInfoIsCloudIdentity(SOSPeerInfoRef pi
) {
762 CFTypeRef value
= CFDictionaryGetValue(pi
->description
, sCloudIdentityKey
);
763 return CFEqualSafe(value
, kCFBooleanTrue
);
766 SOSPeerInfoRef
SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator
, SecKeyRef privKey
, SecKeyRef peerKey
, SOSPeerInfoRef peer
, CFErrorRef
*error
) {
767 SecKeyRef pubKey
= SecKeyCreatePublicFromPrivate(privKey
);
768 SOSPeerInfoRef retval
= NULL
;
770 retval
= SOSPeerInfoCopyAsApplication(peer
, privKey
, peerKey
, error
);
771 CFReleaseNull(pubKey
);