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 <SecureObjectSync/SOSInternal.h> 26#include <SecureObjectSync/SOSCircle.h> 27#include <SecureObjectSync/SOSCloudCircle.h> 28#include <SecureObjectSync/SOSKVSKeys.h> 29#include "utilities/SecCFError.h" 30#include "utilities/SecCFRelease.h" 31#include "utilities/SecCFWrappers.h" 32#include "utilities/iOSforOSX.h" 33 34#include <CoreFoundation/CoreFoundation.h> 35 36#include <Security/SecKey.h> 37#include <Security/SecKeyPriv.h> 38#include <Security/SecItem.h> 39#include <securityd/SecDbItem.h> // For SecError 40#include "utilities/iOSforOSX.h" 41 42#include <Security/SecBase64.h> 43 44#include <AssertMacros.h> 45 46CFStringRef kSOSErrorDomain = CFSTR("com.apple.security.sos.error"); 47 48bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...) { 49 if (!errorCode) return true; 50 if (error && !*error) { 51 va_list va; 52 va_start(va, format); 53 SecCFCreateErrorWithFormatAndArguments(errorCode, kSOSErrorDomain, NULL, error, formatOptions, format, va); 54 va_end(va); 55 } 56 return false; 57} 58 59bool SOSCreateError(CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) { 60 SOSCreateErrorWithFormat(errorCode, previousError, newError, NULL, CFSTR("%@"), descriptionString); 61 return true; 62} 63 64bool SOSCreateErrorWithFormat(CFIndex errorCode, CFErrorRef previousError, CFErrorRef *newError, 65 CFDictionaryRef formatOptions, CFStringRef format, ...) { 66 va_list va; 67 va_start(va, format); 68 bool res = SOSCreateErrorWithFormatAndArguments(errorCode, previousError, newError, formatOptions, format, va); 69 va_end(va); 70 return res; 71} 72 73bool SOSCreateErrorWithFormatAndArguments(CFIndex errorCode, CFErrorRef previousError, CFErrorRef *newError, 74 CFDictionaryRef formatOptions, CFStringRef format, va_list args) { 75 SecCFCreateErrorWithFormatAndArguments(errorCode, kSOSErrorDomain, previousError, newError, formatOptions, format, args); 76 return true; 77} 78 79 80// 81// Utility Functions 82// 83 84static OSStatus GenerateECPairImp(int keySize, CFBooleanRef permanent, SecKeyRef* public, SecKeyRef *full) 85{ 86 static const CFStringRef sTempNameToUse = CFSTR("GenerateECPair Temporary Key - Shouldn't be live"); 87 88 CFNumberRef signing_bitsize = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize); 89 90 CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 91 kSecAttrKeyType, kSecAttrKeyTypeEC, 92 kSecAttrKeySizeInBits, signing_bitsize, 93 kSecAttrIsPermanent, permanent, 94 kSecAttrLabel, sTempNameToUse, 95 NULL); 96 CFReleaseNull(signing_bitsize); 97 OSStatus result = SecKeyGeneratePair(keygen_parameters, public, full); 98 CFReleaseNull(keygen_parameters); 99 100 return result; 101} 102 103OSStatus GenerateECPair(int keySize, SecKeyRef* public, SecKeyRef *full) 104{ 105 return GenerateECPairImp(keySize, kCFBooleanFalse, public, full); 106} 107 108OSStatus GeneratePermanentECPair(int keySize, SecKeyRef* public, SecKeyRef *full) 109{ 110 return GenerateECPairImp(keySize, kCFBooleanTrue, public, full); 111} 112 113static CFStringRef SOSCircleCopyDescriptionFromData(CFDataRef data) 114{ 115 CFErrorRef error = NULL; 116 CFStringRef result = NULL; 117 118 SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, data, &error); 119 120 if (circle) 121 result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), circle); 122 123 CFReleaseSafe(circle); 124 125 return result; 126} 127 128CFStringRef SOSChangesCopyDescription(CFDictionaryRef changes, bool is_sender) 129{ 130 CFMutableStringRef string = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("<Changes: {\n")); 131 132 CFDictionaryForEach(changes, ^(const void *key, const void *value) { 133 CFStringRef value_description = NULL; 134 if (isString(key) && isData(value)) { 135 CFDataRef value_data = (CFDataRef) value; 136 switch (SOSKVSKeyGetKeyType(key)) { 137 case kCircleKey: 138 value_description = SOSCircleCopyDescriptionFromData(value_data); 139 break; 140 case kMessageKey: 141 value_description = CFCopyDescription(value_data); 142 break; 143 default: 144 break; 145 } 146 147 } 148 CFStringAppendFormat(string, NULL, CFSTR(" '%@' %s %@\n"), 149 key, 150 is_sender ? "<=" : "=>", 151 value_description ? value_description : value); 152 153 CFReleaseNull(value_description); 154 }); 155 156 CFStringAppendFormat(string, NULL, CFSTR("}")); 157 158 return string; 159} 160 161CFStringRef SOSCopyIDOfKey(SecKeyRef key, CFErrorRef *error) 162{ 163 const struct ccdigest_info * di = ccsha1_di(); 164 CFDataRef publicBytes = NULL; 165 CFStringRef result = NULL; 166 167 uint8_t digest[di->output_size]; 168 char encoded[2 * di->output_size]; // Big enough for base64 encoding. 169 170 require_quiet(SecError(SecKeyCopyPublicBytes(key, &publicBytes), error, CFSTR("Failed to export public bytes %@"), key), fail); 171 172 ccdigest(di, CFDataGetLength(publicBytes), CFDataGetBytePtr(publicBytes), digest); 173 174 size_t length = SecBase64Encode(digest, sizeof(digest), encoded, sizeof(encoded)); 175 assert(length && length < sizeof(encoded)); 176 if (length > 26) 177 length = 26; 178 encoded[length] = 0; 179 CFReleaseNull(publicBytes); 180 return CFStringCreateWithCString(kCFAllocatorDefault, encoded, kCFStringEncodingASCII); 181 182fail: 183 CFReleaseNull(publicBytes); 184 return result; 185} 186