X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c b/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c new file mode 100644 index 00000000..a293c10f --- /dev/null +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "utilities/iOSforOSX.h" + +#include + +#include + +// for OS X +#ifdef __cplusplus +extern "C" { +#endif + +//---- missing + +extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes); +extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); +#ifdef __cplusplus +} +#endif + +struct __OpaqueSOSFullPeerInfo { + CFRuntimeBase _base; + + SOSPeerInfoRef peer_info; + CFDataRef key_ref; +}; + +CFGiblisWithHashFor(SOSFullPeerInfo); + + +static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey"); +static CFStringRef sNameKey = CFSTR("DeviceName"); +static CFStringRef sVersionKey = CFSTR("ConflictVersion"); + +CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription"); +CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature"); +CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName"); + +SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) { + SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); + + fpi->peer_info = SOSPeerInfoCreate(allocator, gestalt, signingKey, error); + if (fpi->peer_info == NULL) { + CFReleaseNull(fpi); + goto exit; + } + + OSStatus result = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref); + + if (result != errSecSuccess) { + CFReleaseNull(fpi); + goto exit; + } + +exit: + return fpi; +} + + + +SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) { + SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); + + SecKeyRef pubKey = NULL; + + fpi->peer_info = peer; + CFRetainSafe(fpi->peer_info); + if (fpi->peer_info == NULL) { + CFReleaseNull(fpi); + goto exit; + } + + pubKey = SOSPeerInfoCopyPubKey(peer); + + fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error); + + if (fpi->key_ref == NULL) { + CFReleaseNull(fpi); + goto exit; + } + +exit: + CFReleaseNull(pubKey); + return fpi; +} + + +SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error, + const uint8_t** der_p, const uint8_t *der_end) { + SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); + SecKeyRef device_key = NULL; + + const uint8_t *sequence_end; + + *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end); + + fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end); + require_quiet(fpi->peer_info != NULL, fail); + + *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end); + + OSStatus result = SecKeyFindWithPersistentRef(fpi->key_ref, &device_key); + + require_quiet(result == errSecSuccess, fail); + require_quiet(*der_p != NULL, fail); + + CFReleaseNull(device_key); + return fpi; + +fail: + CFReleaseNull(fpi); + CFReleaseNull(device_key); + return NULL; +} + +SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error) +{ + size_t size = CFDataGetLength(fullPeerData); + const uint8_t *der = CFDataGetBytePtr(fullPeerData); + SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size); + return inflated; +} + +static void SOSFullPeerInfoDestroy(CFTypeRef aObj) { + SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj; + + CFReleaseNull(fpi->peer_info); + CFReleaseNull(fpi->key_ref); +} + +static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) { + SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs; + SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs; + + if (!CFEqual(lpeer->peer_info, rpeer->peer_info)) + return false; + + if (CFEqual(lpeer->key_ref, rpeer->key_ref)) + return true; + + SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL); + SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL); + + bool match = lpk && rpk && CFEqual(lpk, rpk); + + CFReleaseNull(lpk); + CFReleaseNull(rpk); + + return match; +} + +static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) { + SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf; + + return CFHash(peer->peer_info); +} + +static CFStringRef SOSFullPeerInfoCopyDescription(CFTypeRef aObj) { + SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj; + + return CFStringCreateWithFormat(NULL, NULL, CFSTR(""), fpi, fpi->peer_info); +} + +bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error) +{ + SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error); + require_quiet(device_key, fail); + + SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer->peer_info, + gestalt, device_key, error); + + require_quiet(newPeer, fail); + + CFReleaseNull(peer->peer_info); + peer->peer_info = newPeer; + newPeer = NULL; + + CFReleaseNull(device_key); + return true; + +fail: + CFReleaseNull(device_key); + return false; +} + + +bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) { + return true; +} + +bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) { + CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecValuePersistentRef, fullPeer->key_ref, + kSecUseTombstones, kCFBooleanFalse, + NULL); + SecItemDelete(query); + CFReleaseNull(query); + CFReleaseNull(fullPeer->key_ref); + + return true; +} + +SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) +{ + return fullPeer?fullPeer->peer_info:NULL; +} + +SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) +{ + SecKeyRef device_key = NULL; + + require(fullPeer && fullPeer->key_ref, fail); + + OSStatus result = SecKeyFindWithPersistentRef(fullPeer->key_ref, &device_key); + + require_action_quiet(result == errSecSuccess, fail, SecError(result, error, CFSTR("Finding Persistent Ref"))); + + return device_key; + +fail: + CFReleaseNull(device_key); + return NULL; +} + +// +// MARK: Encode and decode +// +size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error) +{ + size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error); + if (peer_size == 0) + return 0; + + size_t ref_size = der_sizeof_data(peer->key_ref, error); + if (ref_size == 0) + return 0; + + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, + peer_size + ref_size); +} + +uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) +{ + return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + SOSPeerInfoEncodeToDER(peer->peer_info, error, der, + der_encode_data(peer->key_ref, error, der, der_end))); +} + +CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error) +{ + size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error); + if (size == 0) + return NULL; + uint8_t buffer[size]; + uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer)); + CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size); + return result; +} + +bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error) +{ + bool success = false; + SOSPeerInfoRef old_pi = NULL; + + SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error); + require_quiet(device_key, exit); + + old_pi = fpi->peer_info; + fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error); + + require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL); + + success = true; + +exit: + CFReleaseSafe(old_pi); + CFReleaseSafe(device_key); + return success; +} + +bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error) +{ + bool success = false; + SOSPeerInfoRef old_pi = NULL; + + SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error); + require_quiet(device_key, exit); + + old_pi = fpi->peer_info; + fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error); + + require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL); + + success = true; + +exit: + CFReleaseSafe(old_pi); + CFReleaseSafe(device_key); + return success; +} + +// +// +// + +SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error) +{ + SOSPeerInfoRef peer_to_free = NULL; + SOSPeerInfoRef retired_peer = NULL; + SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error); + require_quiet(key, error_out); + + retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error); + + require_quiet(retired_peer, error_out); + + peer_to_free = fpi->peer_info; + fpi->peer_info = retired_peer; + CFRetainSafe(fpi->peer_info); + +error_out: + CFReleaseNull(key); + CFReleaseNull(peer_to_free); + return retired_peer; +} + + +