1/* 2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include <AssertMacros.h> 26 27#include <SecureObjectSync/SOSFullPeerInfo.h> 28#include <SecureObjectSync/SOSCircle.h> 29 30#include <SecureObjectSync/SOSInternal.h> 31 32#include <Security/SecKeyPriv.h> 33#include <Security/SecItemPriv.h> 34#include <Security/SecOTR.h> 35#include <CoreFoundation/CFArray.h> 36#include <dispatch/dispatch.h> 37 38#include <stdlib.h> 39#include <assert.h> 40 41#include <utilities/SecCFWrappers.h> 42#include <utilities/SecCFRelease.h> 43 44#include <utilities/der_plist.h> 45#include <utilities/der_plist_internal.h> 46#include <corecrypto/ccder.h> 47 48#include <CommonCrypto/CommonDigest.h> 49#include <CommonCrypto/CommonDigestSPI.h> 50 51#include <CoreFoundation/CoreFoundation.h> 52 53#include "utilities/iOSforOSX.h" 54 55#include <AssertMacros.h> 56 57#include <utilities/SecCFError.h> 58 59// for OS X 60#ifdef __cplusplus 61extern "C" { 62#endif 63 64//---- missing 65 66extern OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes); 67extern SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); 68#ifdef __cplusplus 69} 70#endif 71 72struct __OpaqueSOSFullPeerInfo { 73 CFRuntimeBase _base; 74 75 SOSPeerInfoRef peer_info; 76 CFDataRef key_ref; 77}; 78 79CFGiblisWithHashFor(SOSFullPeerInfo); 80 81 82static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey"); 83static CFStringRef sNameKey = CFSTR("DeviceName"); 84static CFStringRef sVersionKey = CFSTR("ConflictVersion"); 85 86CFStringRef kSOSFullPeerInfoDescriptionKey = CFSTR("SOSFullPeerInfoDescription"); 87CFStringRef kSOSFullPeerInfoSignatureKey = CFSTR("SOSFullPeerInfoSignature"); 88CFStringRef kSOSFullPeerInfoNameKey = CFSTR("SOSFullPeerInfoName"); 89 90SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) { 91 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); 92 93 fpi->peer_info = SOSPeerInfoCreate(allocator, gestalt, signingKey, error); 94 if (fpi->peer_info == NULL) { 95 CFReleaseNull(fpi); 96 goto exit; 97 } 98 99 OSStatus result = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref); 100 101 if (result != errSecSuccess) { 102 CFReleaseNull(fpi); 103 goto exit; 104 } 105 106exit: 107 return fpi; 108} 109 110 111 112SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) { 113 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); 114 115 SecKeyRef pubKey = NULL; 116 117 fpi->peer_info = peer; 118 CFRetainSafe(fpi->peer_info); 119 if (fpi->peer_info == NULL) { 120 CFReleaseNull(fpi); 121 goto exit; 122 } 123 124 pubKey = SOSPeerInfoCopyPubKey(peer); 125 126 fpi->key_ref = SecKeyCreatePersistentRefToMatchingPrivateKey(pubKey, error); 127 128 if (fpi->key_ref == NULL) { 129 CFReleaseNull(fpi); 130 goto exit; 131 } 132 133exit: 134 CFReleaseNull(pubKey); 135 return fpi; 136} 137 138 139SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error, 140 const uint8_t** der_p, const uint8_t *der_end) { 141 SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); 142 SecKeyRef device_key = NULL; 143 144 const uint8_t *sequence_end; 145 146 *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end); 147 148 fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end); 149 require_quiet(fpi->peer_info != NULL, fail); 150 151 *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end); 152 153 OSStatus result = SecKeyFindWithPersistentRef(fpi->key_ref, &device_key); 154 155 require_quiet(result == errSecSuccess, fail); 156 require_quiet(*der_p != NULL, fail); 157 158 CFReleaseNull(device_key); 159 return fpi; 160 161fail: 162 CFReleaseNull(fpi); 163 CFReleaseNull(device_key); 164 return NULL; 165} 166 167SOSFullPeerInfoRef SOSFullPeerInfoCreateFromData(CFAllocatorRef allocator, CFDataRef fullPeerData, CFErrorRef *error) 168{ 169 size_t size = CFDataGetLength(fullPeerData); 170 const uint8_t *der = CFDataGetBytePtr(fullPeerData); 171 SOSFullPeerInfoRef inflated = SOSFullPeerInfoCreateFromDER(allocator, error, &der, der + size); 172 return inflated; 173} 174 175static void SOSFullPeerInfoDestroy(CFTypeRef aObj) { 176 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj; 177 178 CFReleaseNull(fpi->peer_info); 179 CFReleaseNull(fpi->key_ref); 180} 181 182static Boolean SOSFullPeerInfoCompare(CFTypeRef lhs, CFTypeRef rhs) { 183 SOSFullPeerInfoRef lpeer = (SOSFullPeerInfoRef) lhs; 184 SOSFullPeerInfoRef rpeer = (SOSFullPeerInfoRef) rhs; 185 186 if (!CFEqual(lpeer->peer_info, rpeer->peer_info)) 187 return false; 188 189 if (CFEqual(lpeer->key_ref, rpeer->key_ref)) 190 return true; 191 192 SecKeyRef lpk = SOSFullPeerInfoCopyDeviceKey(lpeer, NULL); 193 SecKeyRef rpk = SOSFullPeerInfoCopyDeviceKey(rpeer, NULL); 194 195 bool match = lpk && rpk && CFEqual(lpk, rpk); 196 197 CFReleaseNull(lpk); 198 CFReleaseNull(rpk); 199 200 return match; 201} 202 203static CFHashCode SOSFullPeerInfoHash(CFTypeRef cf) { 204 SOSFullPeerInfoRef peer = (SOSFullPeerInfoRef) cf; 205 206 return CFHash(peer->peer_info); 207} 208 209static CFStringRef SOSFullPeerInfoCopyDescription(CFTypeRef aObj) { 210 SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) aObj; 211 212 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSFullPeerInfo@%p: \"%@\">"), fpi, fpi->peer_info); 213} 214 215bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error) 216{ 217 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(peer, error); 218 require_quiet(device_key, fail); 219 220 SOSPeerInfoRef newPeer = SOSPeerInfoCopyWithGestaltUpdate(kCFAllocatorDefault, peer->peer_info, 221 gestalt, device_key, error); 222 223 require_quiet(newPeer, fail); 224 225 CFReleaseNull(peer->peer_info); 226 peer->peer_info = newPeer; 227 newPeer = NULL; 228 229 CFReleaseNull(device_key); 230 return true; 231 232fail: 233 CFReleaseNull(device_key); 234 return false; 235} 236 237 238bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) { 239 return true; 240} 241 242bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) { 243 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 244 kSecValuePersistentRef, fullPeer->key_ref, 245 kSecUseTombstones, kCFBooleanFalse, 246 NULL); 247 SecItemDelete(query); 248 CFReleaseNull(query); 249 CFReleaseNull(fullPeer->key_ref); 250 251 return true; 252} 253 254SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) 255{ 256 return fullPeer?fullPeer->peer_info:NULL; 257} 258 259SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) 260{ 261 SecKeyRef device_key = NULL; 262 263 require(fullPeer && fullPeer->key_ref, fail); 264 265 OSStatus result = SecKeyFindWithPersistentRef(fullPeer->key_ref, &device_key); 266 267 require_action_quiet(result == errSecSuccess, fail, SecError(result, error, CFSTR("Finding Persistent Ref"))); 268 269 return device_key; 270 271fail: 272 CFReleaseNull(device_key); 273 return NULL; 274} 275 276// 277// MARK: Encode and decode 278// 279size_t SOSFullPeerInfoGetDEREncodedSize(SOSFullPeerInfoRef peer, CFErrorRef *error) 280{ 281 size_t peer_size = SOSPeerInfoGetDEREncodedSize(peer->peer_info, error); 282 if (peer_size == 0) 283 return 0; 284 285 size_t ref_size = der_sizeof_data(peer->key_ref, error); 286 if (ref_size == 0) 287 return 0; 288 289 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, 290 peer_size + ref_size); 291} 292 293uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) 294{ 295 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, 296 SOSPeerInfoEncodeToDER(peer->peer_info, error, der, 297 der_encode_data(peer->key_ref, error, der, der_end))); 298} 299 300CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error) 301{ 302 size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error); 303 if (size == 0) 304 return NULL; 305 uint8_t buffer[size]; 306 uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer)); 307 CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size); 308 return result; 309} 310 311bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error) 312{ 313 bool success = false; 314 SOSPeerInfoRef old_pi = NULL; 315 316 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error); 317 require_quiet(device_key, exit); 318 319 old_pi = fpi->peer_info; 320 fpi->peer_info = SOSPeerInfoCopyAsApplication(old_pi, user_key, device_key, error); 321 322 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL); 323 324 success = true; 325 326exit: 327 CFReleaseSafe(old_pi); 328 CFReleaseSafe(device_key); 329 return success; 330} 331 332bool SOSFullPeerInfoUpgradeSignatures(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error) 333{ 334 bool success = false; 335 SOSPeerInfoRef old_pi = NULL; 336 337 SecKeyRef device_key = SOSFullPeerInfoCopyDeviceKey(fpi, error); 338 require_quiet(device_key, exit); 339 340 old_pi = fpi->peer_info; 341 fpi->peer_info = SOSPeerInfoUpgradeSignatures(NULL, user_key, device_key, old_pi, error); 342 343 require_action_quiet(fpi->peer_info, exit, fpi->peer_info = old_pi; old_pi = NULL); 344 345 success = true; 346 347exit: 348 CFReleaseSafe(old_pi); 349 CFReleaseSafe(device_key); 350 return success; 351} 352 353// 354// 355// 356 357SOSPeerInfoRef SOSFullPeerInfoPromoteToRetiredAndCopy(SOSFullPeerInfoRef fpi, CFErrorRef *error) 358{ 359 SOSPeerInfoRef peer_to_free = NULL; 360 SOSPeerInfoRef retired_peer = NULL; 361 SecKeyRef key = SOSFullPeerInfoCopyDeviceKey(fpi, error); 362 require_quiet(key, error_out); 363 364 retired_peer = SOSPeerInfoCreateRetirementTicket(NULL, key, fpi->peer_info, error); 365 366 require_quiet(retired_peer, error_out); 367 368 peer_to_free = fpi->peer_info; 369 fpi->peer_info = retired_peer; 370 CFRetainSafe(fpi->peer_info); 371 372error_out: 373 CFReleaseNull(key); 374 CFReleaseNull(peer_to_free); 375 return retired_peer; 376} 377 378 379 380