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